diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 84481b654..2339e0d6e 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -378,7 +378,14 @@ advance_token :: proc(p: ^Parser) -> tokenizer.Token { prev := p.prev_tok if next_token0(p) { - consume_comment_groups(p, prev) + #partial switch p.curr_tok.kind { + case .Comment: + consume_comment_groups(p, prev) + case .Semicolon: + if p.expr_level > 0 && p.curr_tok.text == "\n" { + advance_token(p) + } + } } return prev } @@ -2366,10 +2373,10 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { case .Open_Paren: open := expect_token(p, .Open_Paren) - p.expr_level += 1 + prev_expr_level := p.expr_level + p.expr_level = max(p.expr_level, 0) + 1 expr := parse_expr(p, false) - skip_possible_newline(p) - p.expr_level -= 1 + p.expr_level = prev_expr_level close := expect_token(p, .Close_Paren) pe := ast.new(ast.Paren_Expr, open.pos, end_pos(close)) @@ -3203,11 +3210,12 @@ parse_elem_list :: proc(p: ^Parser) -> []^ast.Expr { parse_literal_value :: proc(p: ^Parser, type: ^ast.Expr) -> ^ast.Comp_Lit { elems: []^ast.Expr open := expect_token(p, .Open_Brace) - p.expr_level += 1 + prev_expr_level := p.expr_level + p.expr_level = 0 if p.curr_tok.kind != .Close_Brace { elems = parse_elem_list(p) } - p.expr_level -= 1 + p.expr_level = prev_expr_level skip_possible_newline(p) close := expect_closing_brace_of_field_list(p) @@ -3226,7 +3234,8 @@ parse_call_expr :: proc(p: ^Parser, operand: ^ast.Expr) -> ^ast.Expr { ellipsis: tokenizer.Token - p.expr_level += 1 + prev_expr_level := p.expr_level + p.expr_level = 0 open := expect_token(p, .Open_Paren) seen_ellipsis := false @@ -3273,8 +3282,8 @@ parse_call_expr :: proc(p: ^Parser, operand: ^ast.Expr) -> ^ast.Expr { allow_token(p, .Comma) or_break } + p.expr_level = prev_expr_level close := expect_closing_token_of_field_list(p, .Close_Paren, "argument list") - p.expr_level -= 1 ce := ast.new(ast.Call_Expr, operand.pos, end_pos(close)) ce.expr = operand @@ -3360,8 +3369,8 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a } } - close := expect_token(p, .Close_Bracket) p.expr_level -= 1 + close := expect_token(p, .Close_Bracket) if is_slice_op { if interval.kind == .Comma { diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 30ff35b1b..73e927e08 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -2147,19 +2147,31 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty } } } else { + isize multiple_return_offset = 0; for_array(i, cl->elems) { - Entity *f = type->Struct.fields[i]; + Entity *f = type->Struct.fields[i+multiple_return_offset]; TypeAndValue tav = cl->elems[i]->tav; - ExactValue val = {}; - if (tav.mode != Addressing_Invalid) { - val = tav.value; + + // INFO: dead code: + + // ExactValue val = {}; + // if (tav.mode != Addressing_Invalid) { + // val = tav.value; + // } + + if (is_type_tuple(tav.type)){ + multiple_return_offset += tav.type->Tuple.variables.count-1; } i32 index = field_remapping[f->Variable.field_index]; + + if (elem_type_can_be_constant(f->type)) { lbValue value = lb_const_value(m, f->type, tav.value, tav.type, cc); LLVMTypeRef value_type = LLVMTypeOf(value.value); - GB_ASSERT_MSG(lb_sizeof(value_type) == type_size_of(f->type), "%s vs %s", LLVMPrintTypeToString(value_type), type_to_string(f->type)); + isize lb_sizeof_value_type = lb_sizeof(value_type); + isize type_size_of_f_type = type_size_of(f->type); + GB_ASSERT_MSG(lb_sizeof_value_type ==type_size_of_f_type, "%s vs %s", LLVMPrintTypeToString(value_type), type_to_string(f->type)); values[index] = value.value; visited[index] = true; } diff --git a/src/main.cpp b/src/main.cpp index b32cbca65..3a72c2a9c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -178,11 +178,44 @@ gb_internal i32 system_exec_command_line_app(char const *name, char const *fmt, return exit_code; } -gb_internal void system_must_exec_command_line_app(char const *name, char const *fmt, ...) { - va_list va; - va_start(va, fmt); - system_exec_command_line_app_internal(/* exit_on_err= */ true, name, fmt, va); - va_end(va); +#if defined(GB_SYSTEM_WINDOWS) +#include +#else +#include +extern char **environ; +#endif + +int run_subprocess(const char *name, const char **args) { +#if defined(GB_SYSTEM_WINDOWS) + return (int)_spawnv(_P_WAIT, name, args); +#else + pid_t pid; + int status; + status = posix_spawn(&pid, name, NULL, NULL, (char *const *)args, environ); + if (status != 0) { + gb_printf_err("Could not spawn subprocess: %s\n", strerror(errno)); + return -1; + } + + for (;;) { + if (waitpid(pid, &status, WUNTRACED) < 0) { + gb_printf_err("Could not wait on subprocess: (pid: %d): %s\n", pid, strerror(errno)); + return -1; + } + + if (WIFEXITED(status)) { + return WEXITSTATUS(status); + } else if (WIFSIGNALED(status)) { + struct rlimit limit = { 0, 0, }; + setrlimit(RLIMIT_CORE, &limit); + raise(WTERMSIG(status)); + return -1; + } else if (WIFSTOPPED(status)) { + return -1; + } + } + GB_PANIC("Subprocess failure"); +#endif } #if defined(GB_SYSTEM_WINDOWS) @@ -3653,10 +3686,11 @@ int main(int arg_count, char const **arg_ptr) { init_build_context_error_pos_style(); Array args = setup_args(arg_count, arg_ptr); + Array run_args = array_make(heap_allocator(), 0, arg_count); + defer (array_free(&run_args)); String command = args[1]; String init_filename = {}; - String run_args_string = {}; isize last_non_run_arg = args.count; for_array(i, args) { @@ -3680,9 +3714,6 @@ int main(int arg_count, char const **arg_ptr) { build_context.command_kind = Command_test; } - Array run_args = array_make(heap_allocator(), 0, arg_count); - defer (array_free(&run_args)); - isize run_args_start_idx = -1; for_array(i, args) { if (args[i] == "--") { @@ -3704,7 +3735,6 @@ int main(int arg_count, char const **arg_ptr) { } } args = array_slice(args, 0, last_non_run_arg); - run_args_string = string_join_and_quote(heap_allocator(), run_args); init_filename = args[2]; run_output = true; @@ -4293,8 +4323,23 @@ end_of_code_gen:; String exe_name = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Output]); defer (gb_free(heap_allocator(), exe_name.text)); - system_must_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(exe_name), LIT(run_args_string)); + const char* exe_name_cstring = alloc_cstring(heap_allocator(), exe_name); + Array run_args_cstring = array_make(heap_allocator(), 0, run_args.count); + defer({ + for_array(i, run_args_cstring) { gb_free(heap_allocator(), (void*)run_args_cstring[i]); } + array_free(&run_args_cstring); + }); + array_add(&run_args_cstring, exe_name_cstring); + for_array(i, run_args) { + array_add(&run_args_cstring, alloc_cstring(heap_allocator(), run_args[i])); + } + array_add(&run_args_cstring, NULL); + + int subprocess_res = run_subprocess(exe_name_cstring, run_args_cstring.data); + if (subprocess_res) { + gb_exit(subprocess_res); + } if (!build_context.keep_executable) { char const *filename = cast(char const *)exe_name.text; gb_file_remove(filename); diff --git a/src/types.cpp b/src/types.cpp index c3a997562..45486e6bb 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -3094,7 +3094,7 @@ gb_internal bool lookup_subtype_polymorphic_selection(Type *dst, Type *src, Sele return true; } } - if ((f->flags & EntityFlag_Using) != 0 && is_type_struct(f->type)) { + if ((f->flags & EntityFlags_IsSubtype) != 0 && is_type_struct(f->type)) { String name = lookup_subtype_polymorphic_field(dst, f->type); if (name.len > 0) { array_add(&sel->index, cast(i32)i); @@ -5043,11 +5043,7 @@ gb_internal isize check_is_assignable_to_using_subtype(Type *src, Type *dst, isi return level+1; } } - // Only follow the chain transitively when the field also has `using`, which is - // what the backend's lookup_subtype_polymorphic_selection requires (it gates - // recursion on EntityFlag_Using). A plain `#subtype`-only field enables a - // single-hop conversion but not a two-or-more hop transitive one. - if (f->flags & EntityFlag_Using) { + if (f->flags & EntityFlags_IsSubtype) { isize nested_level = check_is_assignable_to_using_subtype(f->type, dst, level+1, src_is_ptr, allow_polymorphic); if (nested_level > 0) { return nested_level; diff --git a/tests/core/odin/test_parser.odin b/tests/core/odin/test_parser.odin index cc180f9af..3fb15d893 100644 --- a/tests/core/odin/test_parser.odin +++ b/tests/core/odin/test_parser.odin @@ -94,3 +94,40 @@ test_parse_stb_image :: proc(t: ^testing.T) { testing.expectf(t, value.syntax_error_count == 0, "%v should contain zero errors", key) } } + +@test +test_parse_multiline_ternary :: proc(t: ^testing.T) { + context.allocator = context.temp_allocator + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + file := ast.File{ + fullpath = "test.odin", + src = ` +package main + +my_func :: proc (cond: bool, a: string, b: string) -> string { + out := ( + cond + ? a + : b + ) + return out +} + `, + } + + p := parser.default_parser() + + p.err = proc(pos: tokenizer.Pos, format: string, args: ..any) { + message := fmt.tprintf(format, ..args) + log.errorf("%s(%d:%d): %s", pos.file, pos.line, pos.column, message) + } + + p.warn = proc(pos: tokenizer.Pos, format: string, args: ..any) { + message := fmt.tprintf(format, ..args) + log.warnf("%s(%d:%d): %s", pos.file, pos.line, pos.column, message) + } + + ok := parser.parse_file(&p, &file) + testing.expect(t, ok, "bad parse") + testing.expect(t, file.syntax_error_count == 0, "should contain zero errors") +} diff --git a/tests/issues/test_issue_6853.odin b/tests/issues/test_issue_6853.odin new file mode 100644 index 000000000..fec4951a5 --- /dev/null +++ b/tests/issues/test_issue_6853.odin @@ -0,0 +1,30 @@ +package test_issues + +import "core:testing" + +@(test) +test_issue_6853 :: proc(t: ^testing.T) { + + test_s :: struct { + a, b, c, d, e: u64, + } + + expected := test_s{1, 2, 3, 4, 5} + + case0 :: proc() -> (u64, u64) {return 1, 2} + test0 := test_s{case0(), 3, 4, 5} + testing.expect_value(t, test0, expected) + + case1 :: proc() -> (u64, u64, u64) {return 1, 2, 3} + test1 := test_s{case1(), 4, 5} + testing.expect_value(t, test1, expected) + + case2 :: proc() -> (u64, u64) {return 2, 3} + test2 := test_s{1, case2(), 4, 5} + testing.expect_value(t, test2, expected) + + case3_1 :: proc() -> (u64, u64) {return 1, 2} + case3_2 :: proc() -> (u64, u64) {return 3, 4} + test3 := test_s{case3_1(), case3_2(), 5} + testing.expect_value(t, test3, expected) +}