diff --git a/code/demo.odin b/code/demo.odin index 6bf3748c0..f93c1575b 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -10,22 +10,15 @@ import ( "utf8.odin"; ) -type Byte_Size f64; -const ( - _ = iota; // ignore first value by assigning to blank identifier - KB Byte_Size = 1 << (10 * iota); - // Because there is no type or expression, the previous one is used but - // with `iota` incremented by one - MB; - GB; - TB; - PB; - EB; -) - - proc main() { - fmt.println("Here"); + var x = proc() -> int { + proc print_here() { + fmt.println("Here"); + } + print_here(); + return 1; + }; + fmt.println(x()); } diff --git a/core/_preload.odin b/core/_preload.odin index 4bff92a58..89803334c 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -112,7 +112,7 @@ proc fmuladd64(a, b, c f64) -> f64 #foreign "llvm.fmuladd.f64" -type Allocator_Mode int; +type Allocator_Mode u8; const ( ALLOCATOR_ALLOC Allocator_Mode = iota; ALLOCATOR_FREE; diff --git a/core/_soft_numbers.odin b/core/_soft_numbers.odin index e71934321..db68cad73 100644 --- a/core/_soft_numbers.odin +++ b/core/_soft_numbers.odin @@ -1,158 +1,158 @@ #shared_global_scope; -/* -#import "fmt.odin" -__u128_mod :: proc(a, b: u128) -> u128 #link_name "__umodti3" { - _, r := __u128_quo_mod(a, b) - return r -} +// import "fmt.odin"; -__u128_quo :: proc(a, b: u128) -> u128 #link_name "__udivti3" { - n, _ := __u128_quo_mod(a, b) - return n -} +// proc __u128_mod(a, b: u128) -> u128 #link_name "__umodti3" { +// var _, r := __u128_quo_mod(a, b) +// return r +// } -__i128_mod :: proc(a, b: i128) -> i128 #link_name "__modti3" { - _, r := __i128_quo_mod(a, b) - return r -} +// proc __u128_quo(a, b: u128) -> u128 #link_name "__udivti3" { +// var n, _ := __u128_quo_mod(a, b) +// return n +// } -__i128_quo :: proc(a, b: i128) -> i128 #link_name "__divti3" { - n, _ := __i128_quo_mod(a, b) - return n -} +// proc __i128_mod(a, b: i128) -> i128 #link_name "__modti3" { +// var _, r := __i128_quo_mod(a, b) +// return r +// } -__i128_quo_mod :: proc(a, b: i128) -> (i128, i128) #link_name "__divmodti4" { - s := b >> 127 - b = (b ~ s) - s - s = a >> 127 - a = (a ~ s) - s +// proc __i128_quo(a, b: i128) -> i128 #link_name "__divti3" { +// var n, _ := __i128_quo_mod(a, b) +// return n +// } - n, r := __u128_quo_mod(a as u128, b as u128) - return (n as i128 ~ s) - s, (r as i128 ~ s) - s -} +// proc __i128_quo_mod(a, b: i128) -> (i128, i128) #link_name "__divmodti4" { +// var s := b >> 127 +// b = (b ~ s) - s +// s = a >> 127 +// a = (a ~ s) - s + +// var n, r := __u128_quo_mod(a as u128, b as u128) +// return (n as i128 ~ s) - s, (r as i128 ~ s) - s +// } -__u128_quo_mod :: proc(a, b: u128) -> (u128, u128) #link_name "__udivmodti4" { - clz :: proc(x: u64) -> u64 { - clz_u64 :: proc(x: u64, is_zero_undef: bool) -> u64 #foreign "llvm.ctlz.i64" - return clz_u64(x, false) - } - ctz :: proc(x: u64) -> u64 { - ctz_u64 :: proc(x: u64, is_zero_undef: bool) -> u64 #foreign "llvm.cttz.i64" - return ctz_u64(x, false) - } +// proc __u128_quo_mod(a, b: u128) -> (u128, u128) #link_name "__udivmodti4" { +// proc clz(x: u64) -> u64 { +// proc clz_u64(x: u64, is_zero_undef: bool) -> u64 #foreign "llvm.ctlz.i64" +// return clz_u64(x, false) +// } +// proc ctz(x: u64) -> u64 { +// proc ctz_u64(x: u64, is_zero_undef: bool) -> u64 #foreign "llvm.cttz.i64" +// return ctz_u64(x, false) +// } - u128_lo_hi :: raw_union { - all: u128 - using _lohi: struct {lo, hi: u64;} - } +// u128_lo_hi :: raw_union { +// all: u128 +// using _lohi: struct {lo, hi: u64;} +// } - n, d, q, r: u128_lo_hi - sr: u64 +// n, d, q, r: u128_lo_hi +// sr: u64 - n.all = a - d.all = b +// n.all = a +// d.all = b - if n.hi == 0 { - if d.hi == 0 { - return (n.lo / d.lo) as u128, (n.lo % d.lo) as u128 - } - return 0, n.lo as u128 - } - if d.lo == 0 { - if d.hi == 0 { - return (n.hi / d.lo) as u128, (n.hi % d.lo) as u128 - } - if n.lo == 0 { - r.hi = n.hi % d.hi - r.lo = 0 - return (n.hi / d.hi) as u128, r.all - } - if (d.hi & (d.hi-1)) == 0 { - r.lo = n.lo - r.hi = n.hi & (d.hi-1) - return (n.hi >> ctz(d.hi)) as u128, r.all - } +// if n.hi == 0 { +// if d.hi == 0 { +// return (n.lo / d.lo) as u128, (n.lo % d.lo) as u128 +// } +// return 0, n.lo as u128 +// } +// if d.lo == 0 { +// if d.hi == 0 { +// return (n.hi / d.lo) as u128, (n.hi % d.lo) as u128 +// } +// if n.lo == 0 { +// r.hi = n.hi % d.hi +// r.lo = 0 +// return (n.hi / d.hi) as u128, r.all +// } +// if (d.hi & (d.hi-1)) == 0 { +// r.lo = n.lo +// r.hi = n.hi & (d.hi-1) +// return (n.hi >> ctz(d.hi)) as u128, r.all +// } - sr = clz(d.hi) - clz(n.hi) - if sr > 64 - 2 { - return 0, n.all - } - sr++ - q.lo = 0 - q.hi = n.lo << (64-sr) - r.hi = n.hi >> sr - r.lo = (n.hi << (64-sr)) | (n.lo >> sr) - } else { - if d.hi == 0 { - if (d.lo & (d.lo - 1)) == 0 { - rem := (n.lo % (d.lo - 1)) as u128 - if d.lo == 1 { - return n.all, rem - } - sr = ctz(d.lo) - q.hi = n.hi >> sr - q.lo = (n.hi << (64-sr)) | (n.lo >> sr) - return q.all, rem - } +// sr = clz(d.hi) - clz(n.hi) +// if sr > 64 - 2 { +// return 0, n.all +// } +// sr++ +// q.lo = 0 +// q.hi = n.lo << (64-sr) +// r.hi = n.hi >> sr +// r.lo = (n.hi << (64-sr)) | (n.lo >> sr) +// } else { +// if d.hi == 0 { +// if (d.lo & (d.lo - 1)) == 0 { +// var rem := (n.lo % (d.lo - 1)) as u128 +// if d.lo == 1 { +// return n.all, rem +// } +// sr = ctz(d.lo) +// q.hi = n.hi >> sr +// q.lo = (n.hi << (64-sr)) | (n.lo >> sr) +// return q.all, rem +// } - sr = 1 + 64 + clz(d.lo) - clz(n.hi) +// sr = 1 + 64 + clz(d.lo) - clz(n.hi) - q.all = n.all << (128-sr) - r.all = n.all >> sr - if sr == 64 { - q.lo = 0 - q.hi = n.lo - r.hi = 0 - r.lo = n.hi - } else if sr < 64 { - q.lo = 0 - q.hi = n.lo << (64-sr) - r.hi = n.hi >> sr - r.lo = (n.hi << (64-sr)) | (n.lo >> sr) - } else { - q.lo = n.lo << (128-sr) - q.hi = (n.hi << (128-sr)) | (n.lo >> (sr-64)) - r.hi = 0 - r.lo = n.hi >> (sr-64) - } - } else { - sr = clz(d.hi) - clz(n.hi) - if sr > 64-1 { - return 0, n.all - } - sr++ - q.lo = 0 - q.hi = n.lo << (64-sr) - r.all = n.all >> sr - if sr < 64 { - r.hi = n.hi >> sr - r.lo = (n.hi << (64-sr)) | (n.lo >> sr) - } else { - r.hi = 0 - r.lo = n.hi - } - } - } +// q.all = n.all << (128-sr) +// r.all = n.all >> sr +// if sr == 64 { +// q.lo = 0 +// q.hi = n.lo +// r.hi = 0 +// r.lo = n.hi +// } else if sr < 64 { +// q.lo = 0 +// q.hi = n.lo << (64-sr) +// r.hi = n.hi >> sr +// r.lo = (n.hi << (64-sr)) | (n.lo >> sr) +// } else { +// q.lo = n.lo << (128-sr) +// q.hi = (n.hi << (128-sr)) | (n.lo >> (sr-64)) +// r.hi = 0 +// r.lo = n.hi >> (sr-64) +// } +// } else { +// sr = clz(d.hi) - clz(n.hi) +// if sr > 64-1 { +// return 0, n.all +// } +// sr++ +// q.lo = 0 +// q.hi = n.lo << (64-sr) +// r.all = n.all >> sr +// if sr < 64 { +// r.hi = n.hi >> sr +// r.lo = (n.hi << (64-sr)) | (n.lo >> sr) +// } else { +// r.hi = 0 +// r.lo = n.hi +// } +// } +// } - carry: u64 - for ; sr > 0; sr-- { - r.hi = (r.hi << 1) | (r.lo >> (64-1)) - r.lo = (r.lo << 1) | (r.hi >> (64-1)) - q.hi = (q.hi << 1) | (q.lo >> (64-1)) - q.lo = (q.lo << 1) | carry +// carry: u64 +// for ; sr > 0; sr-- { +// r.hi = (r.hi << 1) | (r.lo >> (64-1)) +// r.lo = (r.lo << 1) | (r.hi >> (64-1)) +// q.hi = (q.hi << 1) | (q.lo >> (64-1)) +// q.lo = (q.lo << 1) | carry - carry = 0 - if r.all >= d.all { - r.all -= d.all - carry = 1 - } - } +// carry = 0 +// if r.all >= d.all { +// r.all -= d.all +// carry = 1 +// } +// } + +// q.all = (q.all << 1) | (carry as u128) +// return q.all, r.all +// } - q.all = (q.all << 1) | (carry as u128) - return q.all, r.all -} -*/ diff --git a/core/os_windows.odin b/core/os_windows.odin index 139c55cef..777273e8f 100644 --- a/core/os_windows.odin +++ b/core/os_windows.odin @@ -93,8 +93,7 @@ const ( FILE_STANDARD_ERROR; FILE_STANDARD_COUNT; -); - +) // NOTE(bill): Uses startup to initialize it var ( __std_files = [FILE_STANDARD_COUNT]File{ diff --git a/core/utf8.odin b/core/utf8.odin index 3be7bec5b..42913eba5 100644 --- a/core/utf8.odin +++ b/core/utf8.odin @@ -8,11 +8,11 @@ const ( SURROGATE_MIN = 0xd800; SURROGATE_MAX = 0xdfff; -); +) type Accept_Range struct { lo, hi u8; -}; +} var ( accept_ranges = [5]Accept_Range{ @@ -99,10 +99,12 @@ proc decode_rune(s string) -> (rune, int) { return RUNE_ERROR, 1; } - const MASK_X = 0b00111111; - const MASK_2 = 0b00011111; - const MASK_3 = 0b00001111; - const MASK_4 = 0b00000111; + const ( + MASK_X = 0b00111111; + MASK_2 = 0b00011111; + MASK_3 = 0b00001111; + MASK_4 = 0b00000111; + ) if size == 2 { return (b0&MASK_2) as rune <<6 | (b1&MASK_X) as rune, 2; diff --git a/src/checker/checker.c b/src/checker/checker.c index 20d1aa149..8fc40b83d 100644 --- a/src/checker/checker.c +++ b/src/checker/checker.c @@ -1142,6 +1142,8 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As for_array(iota, gd->specs) { AstNode *spec = gd->specs.e[iota]; switch (spec->kind) { + case_ast_node(bd, BadDecl, decl); + case_end; case_ast_node(is, ImportSpec, spec); if (!parent_scope->is_file) { // NOTE(bill): _Should_ be caught by the parser @@ -1347,7 +1349,7 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { } // NOTE(bill): Do not add other imported entities add_entity(c, parent_scope, NULL, e); - if (!id->is_load) { // `#import`ed entities don't get exported + if (id->keyword == Token_import) { // `#import`ed entities don't get exported HashKey key = hash_string(e->token.string); map_entity_set(&parent_scope->implicit, key, e); } diff --git a/src/checker/expr.c b/src/checker/expr.c index 8afaed865..79a8e8623 100644 --- a/src/checker/expr.c +++ b/src/checker/expr.c @@ -87,6 +87,8 @@ void check_local_collect_entities(Checker *c, AstNodeArray nodes, DelayedEntitie for_array(iota, gd->specs) { AstNode *spec = gd->specs.e[iota]; switch (spec->kind) { + case_ast_node(bd, BadDecl, spec); + case_end; case_ast_node(vs, ValueSpec, spec); switch (vs->keyword) { case Token_var: @@ -453,15 +455,15 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, fields[field_index++] = make_entity_type_name(c->allocator, c->context.scope, empty_token, NULL); for_array(decl_index, decls) { AstNode *decl = decls.e[decl_index]; - if (decl->kind != AstNode_Parameter) { + if (decl->kind != AstNode_Field) { continue; } - ast_node(p, Parameter, decl); - Type *base_type = check_type_extra(c, p->type, NULL); + ast_node(f, Field, decl); + Type *base_type = check_type_extra(c, f->type, NULL); - for_array(name_index, p->names) { - AstNode *name = p->names.e[name_index]; + for_array(name_index, f->names) { + AstNode *name = f->names.e[name_index]; if (!ast_node_expect(name, AstNode_Ident)) { continue; } @@ -493,28 +495,28 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, isize field_index = 0; for_array(decl_index, decls) { AstNode *decl = decls.e[decl_index]; - if (decl->kind != AstNode_Parameter) { + if (decl->kind != AstNode_Field) { continue; } - ast_node(param, Parameter, decl); + ast_node(f, Field, decl); - Type *type = check_type_extra(c, param->type, NULL); + Type *type = check_type_extra(c, f->type, NULL); - if (param->is_using) { - if (param->names.count > 1) { - error_node(param->names.e[0], "Cannot apply `using` to more than one of the same type"); + if (f->is_using) { + if (f->names.count > 1) { + error_node(f->names.e[0], "Cannot apply `using` to more than one of the same type"); } } - for_array(name_index, param->names) { - AstNode *name = param->names.e[name_index]; + for_array(name_index, f->names) { + AstNode *name = f->names.e[name_index]; if (!ast_node_expect(name, AstNode_Ident)) { continue; } Token name_token = name->Ident; - Entity *e = make_entity_field(c->allocator, c->context.scope, name_token, type, param->is_using, cast(i32)field_index); + Entity *e = make_entity_field(c->allocator, c->context.scope, name_token, type, f->is_using, cast(i32)field_index); e->identifier = name; if (str_eq(name_token.string, str_lit("_"))) { fields[field_index++] = e; @@ -533,19 +535,19 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, } - if (param->is_using) { + if (f->is_using) { Type *t = base_type(type_deref(type)); if (!is_type_struct(t) && !is_type_raw_union(t) && - param->names.count >= 1 && - param->names.e[0]->kind == AstNode_Ident) { - Token name_token = param->names.e[0]->Ident; + f->names.count >= 1 && + f->names.e[0]->kind == AstNode_Ident) { + Token name_token = f->names.e[0]->Ident; if (is_type_indexable(t)) { bool ok = true; for_array(emi, entity_map.entries) { Entity *e = entity_map.entries.e[emi].value; if (e->kind == Entity_Variable && e->flags & EntityFlag_Anonymous) { if (is_type_indexable(e->type)) { - if (e->identifier != param->names.e[0]) { + if (e->identifier != f->names.e[0]) { ok = false; using_index_expr = e; break; @@ -613,8 +615,8 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node) { for_array(field_index, st->fields) { AstNode *field = st->fields.e[field_index]; switch (field->kind) { - case_ast_node(p, Parameter, field); - field_count += p->names.count; + case_ast_node(f, Field, field); + field_count += f->names.count; case_end; } } @@ -662,8 +664,8 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) { for_array(field_index, ut->fields) { AstNode *field = ut->fields.e[field_index]; switch (field->kind) { - case_ast_node(p, Parameter, field); - field_count += p->names.count; + case_ast_node(f, Field, field); + field_count += f->names.count; case_end; } } @@ -685,8 +687,8 @@ void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) { for_array(field_index, ut->fields) { AstNode *field = ut->fields.e[field_index]; switch (field->kind) { - case_ast_node(p, Parameter, field); - field_count += p->names.count; + case_ast_node(f, Field, field); + field_count += f->names.count; case_end; } } @@ -699,51 +701,47 @@ void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) { union_type->Record.field_count = field_count; } -GB_COMPARE_PROC(cmp_enum_order) { - // Rule: - // Biggest to smallest alignment - // if same alignment: biggest to smallest size - // if same size: order by source order - Entity *x = *(Entity **)a; - Entity *y = *(Entity **)b; - GB_ASSERT(x != NULL); - GB_ASSERT(y != NULL); - GB_ASSERT(x->kind == Entity_Constant); - GB_ASSERT(y->kind == Entity_Constant); - GB_ASSERT(x->Constant.value.kind == ExactValue_Integer); - GB_ASSERT(y->Constant.value.kind == ExactValue_Integer); - i64 i = x->Constant.value.value_integer; - i64 j = y->Constant.value.value_integer; +// GB_COMPARE_PROC(cmp_enum_order) { +// // Rule: +// // Biggest to smallest alignment +// // if same alignment: biggest to smallest size +// // if same size: order by source order +// Entity *x = *(Entity **)a; +// Entity *y = *(Entity **)b; +// GB_ASSERT(x != NULL); +// GB_ASSERT(y != NULL); +// GB_ASSERT(x->kind == Entity_Constant); +// GB_ASSERT(y->kind == Entity_Constant); +// GB_ASSERT(x->Constant.value.kind == ExactValue_Integer); +// GB_ASSERT(y->Constant.value.kind == ExactValue_Integer); +// i64 i = x->Constant.value.value_integer; +// i64 j = y->Constant.value.value_integer; - return i < j ? -1 : i > j; -} +// return i < j ? -1 : i > j; +// } Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, bool *is_variadic_) { if (params.count == 0) { return NULL; } - bool is_variadic = false; - - Type *tuple = make_type_tuple(c->allocator); - isize variable_count = 0; for_array(i, params) { AstNode *field = params.e[i]; - if (!ast_node_expect(field, AstNode_Parameter)) { - continue; + if (ast_node_expect(field, AstNode_Field)) { + ast_node(f, Field, field); + variable_count += f->names.count; } - ast_node(p, Parameter, field); - variable_count += p->names.count; } + bool is_variadic = false; Entity **variables = gb_alloc_array(c->allocator, Entity *, variable_count); isize variable_index = 0; for_array(i, params) { - if (params.e[i]->kind != AstNode_Parameter) { + if (params.e[i]->kind != AstNode_Field) { continue; } - ast_node(p, Parameter, params.e[i]); + ast_node(p, Field, params.e[i]); AstNode *type_expr = p->type; if (type_expr) { if (type_expr->kind == AstNode_Ellipsis) { @@ -777,6 +775,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, bool *is_v end->type = make_type_slice(c->allocator, end->type); } + Type *tuple = make_type_tuple(c->allocator); tuple->Tuple.variables = variables; tuple->Tuple.variable_count = variable_count; @@ -3687,21 +3686,21 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint case_end; case_ast_node(pl, ProcLit, node); - check_open_scope(c, pl->type); - c->context.decl = make_declaration_info(c->allocator, c->context.scope); Type *proc_type = check_type(c, pl->type); - if (proc_type != NULL) { - check_proc_body(c, empty_token, c->context.decl, proc_type, pl->body); - o->mode = Addressing_Value; - o->type = proc_type; - check_close_scope(c); - } else { + if (proc_type == NULL) { gbString str = expr_to_string(node); error_node(node, "Invalid procedure literal `%s`", str); gb_string_free(str); check_close_scope(c); goto error; } + check_open_scope(c, pl->type); + check_proc_body(c, empty_token, c->context.decl, proc_type, pl->body); + check_close_scope(c); + + o->mode = Addressing_Value; + o->type = proc_type; + case_end; case_ast_node(cl, CompoundLit, node); @@ -4240,7 +4239,7 @@ gbString write_expr_to_string(gbString str, AstNode *node); gbString write_params_to_string(gbString str, AstNodeArray params, char *sep) { for_array(i, params) { - ast_node(p, Parameter, params.e[i]); + ast_node(p, Field, params.e[i]); if (i > 0) { str = gb_string_appendc(str, sep); } @@ -4390,14 +4389,15 @@ gbString write_expr_to_string(gbString str, AstNode *node) { str = write_expr_to_string(str, vt->elem); case_end; - case_ast_node(p, Parameter, node); + case_ast_node(p, Field, node); if (p->is_using) { str = gb_string_appendc(str, "using "); } for_array(i, p->names) { AstNode *name = p->names.e[i]; - if (i > 0) + if (i > 0) { str = gb_string_appendc(str, ", "); + } str = write_expr_to_string(str, name); } diff --git a/src/checker/stmt.c b/src/checker/stmt.c index 89c68d0f6..7ae8355d2 100644 --- a/src/checker/stmt.c +++ b/src/checker/stmt.c @@ -1088,6 +1088,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { for_array(spec_index, gd->specs) { AstNode *spec = gd->specs.e[spec_index]; switch (spec->kind) { + case_ast_node(bd, BadDecl, spec); + case_end; case_ast_node(vs, ValueSpec, spec); switch (vs->keyword) { case Token_let: diff --git a/src/main.c b/src/main.c index 89d9e5150..1ca921ebe 100644 --- a/src/main.c +++ b/src/main.c @@ -59,17 +59,26 @@ i32 win32_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) { return exit_code; } +void print_usage_line(i32 indent, char *fmt, ...) { + while (indent --> 0) { + gb_printf_err("\t"); + } + va_list va; + va_start(va, fmt); + gb_printf_err_va(fmt, va); + va_end(va); + gb_printf_err("\n"); +} void usage(char *argv0) { - gb_printf_err("%s is a tool for managing Odin source code\n", argv0); - gb_printf_err("Usage:"); - gb_printf_err("\n\t%s command [arguments]\n", argv0); - gb_printf_err("Commands:"); - gb_printf_err("\n\tbuild compile .odin file"); - gb_printf_err("\n\tbuild_dll compile .odin file as dll"); - gb_printf_err("\n\trun compile and run .odin file"); - gb_printf_err("\n\tversion print Odin version"); - gb_printf_err("\n\n"); + print_usage_line(0, "%s is a tool for managing Odin source code", argv0); + print_usage_line(0, "Usage:"); + print_usage_line(1, "%s command [arguments]", argv0); + print_usage_line(0, "Commands:"); + print_usage_line(1, "build compile .odin file as executable"); + print_usage_line(1, "build_dll compile .odin file as dll"); + print_usage_line(1, "run compile and run .odin file"); + print_usage_line(1, "version print version"); } int main(int argc, char **argv) { diff --git a/src/parser.c b/src/parser.c index 21a394c11..5ccc0df8a 100644 --- a/src/parser.c +++ b/src/parser.c @@ -57,6 +57,7 @@ typedef struct Parser { Array(ImportedFile) imports; gbAtomic32 import_index; isize total_token_count; + isize total_line_count; gbMutex mutex; } Parser; @@ -176,52 +177,56 @@ AST_NODE_KIND(_ComplexStmtBegin, "", i32) \ AstNodeArray results; \ }) \ AST_NODE_KIND(ForStmt, "for statement", struct { \ - Token token; \ - AstNode *init, *cond, *post; \ + Token token; \ + AstNode *init; \ + AstNode *cond; \ + AstNode *post; \ AstNode *body; \ }) \ AST_NODE_KIND(CaseClause, "case clause", struct { \ - Token token; \ - AstNodeArray list, stmts; \ + Token token; \ + AstNodeArray list; \ + AstNodeArray stmts; \ }) \ AST_NODE_KIND(MatchStmt, "match statement", struct { \ - Token token; \ - AstNode *init, *tag; \ + Token token; \ + AstNode *init; \ + AstNode *tag; \ AstNode *body; \ }) \ AST_NODE_KIND(TypeMatchStmt, "type match statement", struct { \ - Token token; \ - AstNode *tag, *var; \ - AstNode *body; \ + Token token; \ + AstNode *tag; \ + AstNode *var; \ + AstNode *body; \ }) \ AST_NODE_KIND(DeferStmt, "defer statement", struct { Token token; AstNode *stmt; }) \ AST_NODE_KIND(BranchStmt, "branch statement", struct { Token token; }) \ AST_NODE_KIND(UsingStmt, "using statement", struct { Token token; AstNode *node; }) \ AST_NODE_KIND(AsmOperand, "assembly operand", struct { \ - Token string; \ + Token string; \ AstNode *operand; \ }) \ AST_NODE_KIND(AsmStmt, "assembly statement", struct { \ - Token token; \ - bool is_volatile; \ - Token open, close; \ - Token code_string; \ - AstNode *output_list; \ - AstNode *input_list; \ + Token token; \ + bool is_volatile; \ + Token open, close; \ + Token code_string; \ + AstNode *output_list; \ + AstNode *input_list; \ AstNode *clobber_list; \ isize output_count, input_count, clobber_count; \ }) \ AST_NODE_KIND(PushAllocator, "push_allocator statement", struct { \ - Token token; \ + Token token; \ AstNode *expr; \ AstNode *body; \ }) \ AST_NODE_KIND(PushContext, "push_context statement", struct { \ - Token token; \ + Token token; \ AstNode *expr; \ AstNode *body; \ }) \ -\ AST_NODE_KIND(_ComplexStmtEnd, "", i32) \ AST_NODE_KIND(_StmtEnd, "", i32) \ AST_NODE_KIND(_SpecBegin, "", i32) \ @@ -237,12 +242,12 @@ AST_NODE_KIND(_SpecBegin, "", i32) \ AstNode *note; \ }) \ AST_NODE_KIND(ImportSpec, "import specification", struct { \ - Token relpath; \ - String fullpath; \ - Token import_name; \ - bool is_load; \ - AstNode *cond; \ - AstNode *note; \ + TokenKind keyword; \ + Token relpath; \ + String fullpath; \ + Token import_name; \ + AstNode *cond; \ + AstNode *note; \ }) \ AST_NODE_KIND(_SpecEnd, "", i32) \ AST_NODE_KIND(_DeclBegin, "", i32) \ @@ -270,12 +275,12 @@ AST_NODE_KIND(_DeclBegin, "", i32) \ bool is_system; \ }) \ AST_NODE_KIND(_DeclEnd, "", i32) \ -AST_NODE_KIND(_TypeBegin, "", i32) \ - AST_NODE_KIND(Parameter, "parameter", struct { \ - AstNodeArray names; \ - AstNode *type; \ - bool is_using; \ + AST_NODE_KIND(Field, "field", struct { \ + AstNodeArray names; \ + AstNode * type; \ + bool is_using; \ }) \ +AST_NODE_KIND(_TypeBegin, "", i32) \ AST_NODE_KIND(ProcType, "procedure type", struct { \ Token token; \ AstNodeArray params; \ @@ -477,11 +482,11 @@ Token ast_node_token(AstNode *node) { case AstNode_ImportSpec: return node->ImportSpec.relpath; - case AstNode_Parameter: { - if (node->Parameter.names.count > 0) { - return ast_node_token(node->Parameter.names.e[0]); + case AstNode_Field: { + if (node->Field.names.count > 0) { + return ast_node_token(node->Field.names.e[0]); } else { - return ast_node_token(node->Parameter.type); + return ast_node_token(node->Field.type); } } case AstNode_ProcType: @@ -898,11 +903,11 @@ AstNode *make_bad_decl(AstFile *f, Token begin, Token end) { return result; } -AstNode *make_parameter(AstFile *f, AstNodeArray names, AstNode *type, bool is_using) { - AstNode *result = make_node(f, AstNode_Parameter); - result->Parameter.names = names; - result->Parameter.type = type; - result->Parameter.is_using = is_using; +AstNode *make_field(AstFile *f, AstNodeArray names, AstNode *type, bool is_using) { + AstNode *result = make_node(f, AstNode_Field); + result->Field.names = names; + result->Field.type = type; + result->Field.is_using = is_using; return result; } @@ -1030,12 +1035,12 @@ AstNode *make_type_spec(AstFile *f, AstNode *name, AstNode *type) { } -AstNode *make_import_spec(AstFile *f, Token relpath, Token import_name, AstNode *cond, bool is_load) { +AstNode *make_import_spec(AstFile *f, TokenKind keyword, Token relpath, Token import_name, AstNode *cond) { AstNode *result = make_node(f, AstNode_ImportSpec); + result->ImportSpec.keyword = keyword; result->ImportSpec.relpath = relpath; result->ImportSpec.import_name = import_name; result->ImportSpec.cond = cond; - result->ImportSpec.is_load = is_load; return result; } @@ -1057,6 +1062,21 @@ bool next_token(AstFile *f) { return false; } +TokenKind look_ahead_token_kind(AstFile *f, isize amount) { + GB_ASSERT(amount > 0); + + TokenKind kind = Token_Invalid; + isize index = f->curr_token_index; + while (amount > 0) { + index++; + kind = f->tokens.e[index].kind; + if (kind != Token_Comment) { + amount--; + } + } + return kind; +} + Token expect_token(AstFile *f, TokenKind kind) { Token prev = f->curr_token; if (prev.kind != kind) { @@ -1859,17 +1879,17 @@ AstNodeArray parse_identfier_list(AstFile *f) { } void parse_check_name_list_for_reserves(AstFile *f, AstNodeArray names) { - // for_array(i, names) { - // AstNode *name = names.e[i]; - // if (name->kind == AstNode_Ident) { - // String n = name->Ident.string; - // // NOTE(bill): Check for reserved identifiers - // if (str_eq(n, str_lit("context"))) { - // syntax_error_node(name, "`context` is a reserved identifier"); - // break; - // } - // } - // } + for_array(i, names) { + AstNode *name = names.e[i]; + if (name->kind == AstNode_Ident) { + String n = name->Ident.string; + // NOTE(bill): Check for reserved identifiers + if (str_eq(n, str_lit("context"))) { + syntax_error_node(name, "`context` is a reserved identifier"); + break; + } + } + } } AstNode *parse_type_attempt(AstFile *f) { @@ -1998,7 +2018,7 @@ PARSE_SPEC_PROC(parse_import_spec) { syntax_error(import_name, "You cannot use `import` within a procedure. This must be done at the file scope"); spec = make_bad_decl(f, import_name, file_path); } else { - spec = make_import_spec(f, file_path, import_name, cond, false); + spec = make_import_spec(f, Token_import, file_path, import_name, cond); } return spec; } @@ -2017,7 +2037,7 @@ PARSE_SPEC_PROC(parse_include_spec) { syntax_error(import_name, "You cannot use `include` within a procedure. This must be done at the file scope"); spec = make_bad_decl(f, import_name, file_path); } else { - spec = make_import_spec(f, file_path, import_name, cond, true); + spec = make_import_spec(f, Token_include, file_path, import_name, cond); } return spec; } @@ -2060,11 +2080,7 @@ AstNode *parse_simple_stmt(AstFile *f) { return parse_decl(f); } - isize lhs_count = 0, rhs_count = 0; AstNodeArray lhs = parse_lhs_expr_list(f); - - - AstNode *statement = NULL; Token token = f->curr_token; switch (token.kind) { case Token_Eq: @@ -2096,7 +2112,7 @@ AstNode *parse_simple_stmt(AstFile *f) { } break; } - if (lhs_count > 1) { + if (lhs.count > 1) { syntax_error(token, "Expected 1 expression"); return make_bad_stmt(f, token, f->curr_token); } @@ -2109,9 +2125,9 @@ AstNode *parse_simple_stmt(AstFile *f) { syntax_error(f->curr_token, "You cannot use a simple statement in the file scope"); return make_bad_stmt(f, f->curr_token, f->curr_token); } - statement = make_inc_dec_stmt(f, token, lhs.e[0]); + AstNode *stmt = make_inc_dec_stmt(f, token, lhs.e[0]); next_token(f); - return statement; + return stmt; } return make_expr_stmt(f, lhs.e[0]); @@ -2155,7 +2171,7 @@ AstNode *parse_proc_type(AstFile *f) { } -AstNodeArray parse_parameter_list(AstFile *f, isize *name_count_, bool allow_using, TokenKind separator, TokenKind follow) { +AstNodeArray parse_field_list(AstFile *f, isize *name_count_, bool allow_using, TokenKind separator, TokenKind follow) { AstNodeArray params = make_ast_node_array(f); isize name_count = 0; @@ -2210,10 +2226,9 @@ AstNodeArray parse_parameter_list(AstFile *f, isize *name_count_, bool allow_usi syntax_error(f->curr_token, "Expected a type for this parameter declaration"); } - AstNode *param = make_parameter(f, names, type, is_using); + AstNode *param = make_field(f, names, type, is_using); array_add(¶ms, param); - if (separator == Token_Semicolon) { expect_semicolon(f, param); } else { @@ -2229,8 +2244,8 @@ AstNodeArray parse_parameter_list(AstFile *f, isize *name_count_, bool allow_usi } -AstNodeArray parse_record_params(AstFile *f, isize *field_count_, bool allow_using, String context) { - return parse_parameter_list(f, field_count_, allow_using, Token_Semicolon, Token_CloseBrace); +AstNodeArray parse_record_fields(AstFile *f, isize *field_count_, bool allow_using, String context) { + return parse_field_list(f, field_count_, allow_using, Token_Semicolon, Token_CloseBrace); } AstNode *parse_identifier_or_type(AstFile *f) { @@ -2295,7 +2310,7 @@ AstNode *parse_identifier_or_type(AstFile *f) { bool is_packed = false; bool is_ordered = false; while (allow_token(f, Token_Hash)) { - Token tag = expect_token_after(f, Token_Ident, "`#`"); + Token tag = expect_token_after(f, Token_Ident, "#"); if (str_eq(tag.string, str_lit("packed"))) { if (is_packed) { syntax_error(tag, "Duplicate struct tag `#%.*s`", LIT(tag.string)); @@ -2315,9 +2330,9 @@ AstNode *parse_identifier_or_type(AstFile *f) { syntax_error(token, "`#ordered` is not needed with `#packed` which implies ordering"); } - Token open = expect_token_after(f, Token_OpenBrace, "`struct`"); + Token open = expect_token_after(f, Token_OpenBrace, "struct"); isize decl_count = 0; - AstNodeArray decls = parse_record_params(f, &decl_count, true, str_lit("struct")); + AstNodeArray decls = parse_record_fields(f, &decl_count, true, str_lit("struct")); Token close = expect_token(f, Token_CloseBrace); return make_struct_type(f, token, decls, decl_count, is_packed, is_ordered); @@ -2325,9 +2340,9 @@ AstNode *parse_identifier_or_type(AstFile *f) { case Token_union: { Token token = expect_token(f, Token_union); - Token open = expect_token_after(f, Token_OpenBrace, "`union`"); + Token open = expect_token_after(f, Token_OpenBrace, "union"); isize decl_count = 0; - AstNodeArray decls = parse_record_params(f, &decl_count, false, str_lit("union")); + AstNodeArray decls = parse_record_fields(f, &decl_count, false, str_lit("union")); Token close = expect_token(f, Token_CloseBrace); return make_union_type(f, token, decls, decl_count); @@ -2335,9 +2350,9 @@ AstNode *parse_identifier_or_type(AstFile *f) { case Token_raw_union: { Token token = expect_token(f, Token_raw_union); - Token open = expect_token_after(f, Token_OpenBrace, "`raw_union`"); + Token open = expect_token_after(f, Token_OpenBrace, "raw_union"); isize decl_count = 0; - AstNodeArray decls = parse_record_params(f, &decl_count, true, str_lit("raw_union")); + AstNodeArray decls = parse_record_fields(f, &decl_count, true, str_lit("raw_union")); Token close = expect_token(f, Token_CloseBrace); return make_raw_union_type(f, token, decls, decl_count); @@ -2391,7 +2406,7 @@ void parse_proc_signature(AstFile *f, AstNodeArray *params, AstNodeArray *results) { expect_token(f, Token_OpenParen); - *params = parse_parameter_list(f, NULL, true, Token_Comma, Token_CloseParen); + *params = parse_field_list(f, NULL, true, Token_Comma, Token_CloseParen); expect_token_after(f, Token_CloseParen, "parameter list"); *results = parse_results(f); } @@ -2409,8 +2424,14 @@ AstNode *parse_body(AstFile *f) { AstNode *parse_proc_decl(AstFile *f) { - Token proc_token = expect_token(f, Token_proc); + if (look_ahead_token_kind(f, 1) == Token_OpenParen) { + // NOTE(bill): It's an anonymous procedure + // NOTE(bill): This look-ahead technically makes the grammar LALR(2) + // but is that a problem in practice? + return make_expr_stmt(f, parse_expr(f, true)); + } + Token proc_token = expect_token(f, Token_proc); AstNode *name = parse_identifier(f); AstNodeArray params = {0}; @@ -2426,19 +2447,18 @@ AstNode *parse_proc_decl(AstFile *f) { parse_proc_tags(f, &tags, &foreign_name, &link_name); - AstNode *curr_proc = f->curr_proc; - f->curr_proc = proc_type; - if (f->curr_token.kind == Token_OpenBrace) { if ((tags & ProcTag_foreign) != 0) { - syntax_error_node(name, "A procedure tagged as `#foreign` cannot have a body"); + syntax_error(proc_token, "A procedure tagged as `#foreign` cannot have a body"); } + AstNode *curr_proc = f->curr_proc; + f->curr_proc = proc_type; body = parse_body(f); + f->curr_proc = curr_proc; } else if ((tags & ProcTag_foreign) == 0) { - syntax_error_node(name, "Only a procedure tagged as `#foreign` cannot have a body"); + syntax_error(proc_token, "Only a procedure tagged as `#foreign` cannot have a body"); } - f->curr_proc = curr_proc; return make_proc_decl(f, name, proc_type, body, tags, foreign_name, link_name); } @@ -2958,6 +2978,11 @@ AstNodeArray parse_stmt_list(AstFile *f) { AstNode *stmt = parse_stmt(f); if (stmt && stmt->kind != AstNode_EmptyStmt) { array_add(&list, stmt); + if (stmt->kind == AstNode_ExprStmt && + stmt->ExprStmt.expr != NULL && + stmt->ExprStmt.expr->kind == AstNode_ProcLit) { + syntax_error_node(stmt, "Procedure literal evaluated but not used"); + } } } @@ -3031,7 +3056,7 @@ void destroy_parser(Parser *p) { for_array(i, p->files) { destroy_ast_file(&p->files.e[i]); } -#if 1 +#if 0 for_array(i, p->imports) { // gb_free(heap_allocator(), p->imports[i].text); } @@ -3093,21 +3118,23 @@ bool is_import_path_valid(String path) { u8 *start = path.text; u8 *end = path.text + path.len; u8 *curr = start; - Rune r = -1; while (curr < end) { isize width = 1; - r = curr[0]; + Rune r = curr[0]; if (r >= 0x80) { width = gb_utf8_decode(curr, end-curr, &r); - if (r == GB_RUNE_INVALID && width == 1) + if (r == GB_RUNE_INVALID && width == 1) { return false; - else if (r == GB_RUNE_BOM && curr-start > 0) + } + else if (r == GB_RUNE_BOM && curr-start > 0) { return false; + } } for (isize i = 0; i < gb_count_of(illegal_import_runes); i++) { - if (r == illegal_import_runes[i]) + if (r == illegal_import_runes[i]) { return false; + } } curr += width; @@ -3135,7 +3162,7 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, AstNodeArray String file_str = is->relpath.string; if (!is_import_path_valid(file_str)) { - if (is->is_load) { + if (is->keyword == Token_include) { syntax_error_node(node, "Invalid #include path: `%.*s`", LIT(file_str)); } else { syntax_error_node(node, "Invalid #import path: `%.*s`", LIT(file_str)); @@ -3266,6 +3293,7 @@ ParseFileError parse_files(Parser *p, char *init_filename) { gb_mutex_lock(&p->mutex); file.id = p->files.count; array_add(&p->files, file); + p->total_line_count += file.tokenizer.line_count; gb_mutex_unlock(&p->mutex); } } diff --git a/src/ssa.c b/src/ssa.c index 46520797a..f3e404571 100644 --- a/src/ssa.c +++ b/src/ssa.c @@ -2607,6 +2607,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue } else if (e != NULL && e->kind == Entity_Variable) { return ssa_addr_load(proc, ssa_build_addr(proc, expr)); } + GB_PANIC("nil value for expression from identifier: %.*s", LIT(i->string)); return NULL; case_end; @@ -2714,9 +2715,10 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue proc->module, NULL, type, pl->type, pl->body, name); value->Proc.tags = pl->tags; + value->Proc.parent = proc; array_add(&proc->children, &value->Proc); - ssa_build_proc(value, proc); + array_add(&proc->module->procs_to_generate, value); return value; case_end; @@ -2971,32 +2973,6 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue } break; -#if 0 - case BuiltinProc_ptr_offset: { - ssa_emit_comment(proc, str_lit("ptr_offset")); - ssaValue *ptr = ssa_build_expr(proc, ce->args.e[0]); - ssaValue *offset = ssa_build_expr(proc, ce->args.e[1]); - return ssa_emit_ptr_offset(proc, ptr, offset); - } break; - - case BuiltinProc_ptr_sub: { - ssa_emit_comment(proc, str_lit("ptr_sub")); - ssaValue *ptr_a = ssa_build_expr(proc, ce->args.e[0]); - ssaValue *ptr_b = ssa_build_expr(proc, ce->args.e[1]); - Type *ptr_type = base_type(ssa_type(ptr_a)); - GB_ASSERT(ptr_type->kind == Type_Pointer); - isize elem_size = type_size_of(proc->module->sizes, proc->module->allocator, ptr_type->Pointer.elem); - - ssaValue *v = ssa_emit_arith(proc, Token_Sub, ptr_a, ptr_b, t_int); - if (elem_size > 1) { - ssaValue *ez = ssa_make_const_int(proc->module->allocator, elem_size); - v = ssa_emit_arith(proc, Token_Quo, v, ez, t_int); - } - - return v; - } break; -#endif - case BuiltinProc_slice_ptr: { ssa_emit_comment(proc, str_lit("slice_ptr")); ssaValue *ptr = ssa_build_expr(proc, ce->args.e[0]); @@ -3095,9 +3071,9 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue } } - // NOTE(bill): Regular call ssaValue *value = ssa_build_expr(proc, ce->proc); + GB_ASSERT(value != NULL); Type *proc_type_ = base_type(ssa_type(value)); GB_ASSERT(proc_type_->kind == Type_Proc); TypeProc *type = &proc_type_->Proc; @@ -3269,7 +3245,7 @@ ssaAddr ssa_build_addr_from_entity(ssaProcedure *proc, Entity *e, AstNode *expr) } if (v == NULL) { - GB_PANIC("Unknown value: %s, entity: %p %.*s\n", expr_to_string(expr), e, LIT(entity_strings[e->kind])); + GB_PANIC("Unknown value: %.*s, entity: %p %.*s\n", LIT(e->token.string), e, LIT(entity_strings[e->kind])); } return ssa_make_addr(v, expr); @@ -3293,7 +3269,9 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { case_ast_node(se, SelectorExpr, expr); ssa_emit_comment(proc, str_lit("SelectorExpr")); - String selector = unparen_expr(se->selector)->Ident.string; + AstNode *sel = unparen_expr(se->selector); + GB_ASSERT(sel->kind == AstNode_Ident); + String selector = sel->Ident.string; Type *type = base_type(type_of_expr(proc->module->info, se->expr)); if (type == t_invalid) { @@ -4958,7 +4936,7 @@ void ssa_gen_tree(ssaGen *s) { array_add(&global_variables, var); } - map_ssa_value_set(&m->values, hash_pointer(e), g); + ssa_module_add_value(m, e, g); map_ssa_value_set(&m->members, hash_string(name), g); } break; @@ -4978,7 +4956,7 @@ void ssa_gen_tree(ssaGen *s) { ssaValue *p = ssa_make_value_procedure(a, m, e, e->type, decl->type_expr, body, name); p->Proc.tags = pd->tags; - map_ssa_value_set(&m->values, hash_pointer(e), p); + ssa_module_add_value(m, e, p); HashKey hash_name = hash_string(name); if (map_ssa_value_get(&m->members, hash_name) == NULL) { map_ssa_value_set(&m->members, hash_name, p);