mirror of
https://github.com/odin-lang/Odin.git
synced 2026-07-17 21:21:04 +00:00
Merge branch 'master' into bill/rexcode
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
67
src/main.cpp
67
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 <process.h>
|
||||
#else
|
||||
#include <spawn.h>
|
||||
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<String> args = setup_args(arg_count, arg_ptr);
|
||||
Array<String> run_args = array_make<String>(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<String> run_args = array_make<String>(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<const char *> run_args_cstring = array_make<const char *>(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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
30
tests/issues/test_issue_6853.odin
Normal file
30
tests/issues/test_issue_6853.odin
Normal file
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user