diff options
| author | Ginger Bill <bill@gingerbill.org> | 2017-01-02 18:47:47 +0000 |
|---|---|---|
| committer | Ginger Bill <bill@gingerbill.org> | 2017-01-02 18:47:47 +0000 |
| commit | a3883a178c1e4e10058089a2832004a6ce1521e2 (patch) | |
| tree | 6ca5a8f0ad91bb94fb09cf10910ad98e7542ff77 | |
| parent | ce89a1428e40aeac13a9d82211fac463f8171717 (diff) | |
`range` statement
| -rw-r--r-- | code/demo.odin | 9 | ||||
| -rw-r--r-- | core/_preload.odin | 4 | ||||
| -rw-r--r-- | src/checker/decl.c | 3 | ||||
| -rw-r--r-- | src/checker/entity.c | 4 | ||||
| -rw-r--r-- | src/checker/expr.c | 14 | ||||
| -rw-r--r-- | src/checker/stmt.c | 99 | ||||
| -rw-r--r-- | src/parser.c | 189 | ||||
| -rw-r--r-- | src/ssa.c | 211 | ||||
| -rw-r--r-- | src/tokenizer.c | 4 |
9 files changed, 462 insertions, 75 deletions
diff --git a/code/demo.odin b/code/demo.odin index b1d7dd426..05a9dfd50 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -18,5 +18,12 @@ Thing :: enum f64 { } main :: proc() { - fmt.println(Thing.A, Thing.B, Thing.C, Thing.D); + msg := "Hello"; + range index, value : msg { + fmt.println(index, value); + } + list := []int{1, 4, 7, 3, 7, 2, 1}; + range index, value : list { + fmt.println(index, value); + } } diff --git a/core/_preload.odin b/core/_preload.odin index 28494f53d..c0ca2ec6a 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -3,6 +3,7 @@ #import "os.odin"; #import "fmt.odin"; #import "mem.odin"; +#import "utf8.odin"; // IMPORTANT NOTE(bill): `type_info` & `type_info_val` cannot be used within a // #shared_global_scope due to the internals of the compiler. @@ -329,4 +330,7 @@ __substring_expr_error :: proc(file: string, line, column: int, low, high: int) __debug_trap(); } +__string_decode_rune :: proc(s: string) -> (rune, int) #inline { + return utf8.decode_rune(s); +} diff --git a/src/checker/decl.c b/src/checker/decl.c index 4fffc81b4..312ae172c 100644 --- a/src/checker/decl.c +++ b/src/checker/decl.c @@ -161,8 +161,9 @@ void check_var_decl_node(Checker *c, AstNodeValueDecl *vd) { } e->flags |= EntityFlag_Visited; - if (e->type == NULL) + if (e->type == NULL) { e->type = init_type; + } } check_arity_match(c, vd); diff --git a/src/checker/entity.c b/src/checker/entity.c index 85e4c5d8d..614fa0ce2 100644 --- a/src/checker/entity.c +++ b/src/checker/entity.c @@ -182,8 +182,8 @@ Entity *make_entity_implicit_value(gbAllocator a, String name, Type *type, Impli } -Entity *make_entity_dummy_variable(gbAllocator a, Scope *file_scope, Token token) { +Entity *make_entity_dummy_variable(gbAllocator a, Scope *scope, Token token) { token.string = str_lit("_"); - return make_entity_variable(a, file_scope, token, NULL); + return make_entity_variable(a, scope, token, NULL); } diff --git a/src/checker/expr.c b/src/checker/expr.c index 33dfa9e44..3c7403143 100644 --- a/src/checker/expr.c +++ b/src/checker/expr.c @@ -3809,20 +3809,26 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint case_end; case_ast_node(pl, ProcLit, node); - Type *proc_type = check_type(c, pl->type); - if (proc_type == NULL) { + Type *type = check_type(c, pl->type); + if (type == NULL || !is_type_proc(type)) { gbString str = expr_to_string(node); error_node(node, "Invalid procedure literal `%s`", str); gb_string_free(str); check_close_scope(c); goto error; } + if (pl->tags != 0) { + error_node(node, "A procedure literal cannot have tags"); + pl->tags = 0; // TODO(bill): Should I zero this?! + } + check_open_scope(c, pl->type); - check_proc_body(c, empty_token, c->context.decl, proc_type, pl->body); + check_procedure_later(c, c->curr_ast_file, empty_token, c->context.decl, type, pl->body, pl->tags); + // check_proc_body(c, empty_token, c->context.decl, type, pl->body); check_close_scope(c); o->mode = Addressing_Value; - o->type = proc_type; + o->type = type; case_end; case_ast_node(ge, GiveExpr, node); diff --git a/src/checker/stmt.c b/src/checker/stmt.c index c4c7cf3f2..60154855f 100644 --- a/src/checker/stmt.c +++ b/src/checker/stmt.c @@ -133,6 +133,12 @@ bool check_is_terminating(AstNode *node) { } case_end; + case_ast_node(rs, RangeStmt, node); + if (!check_has_break(rs->body, true)) { + return true; + } + case_end; + case_ast_node(ms, MatchStmt, node); bool has_default = false; for_array(i, ms->body->BlockStmt.stmts) { @@ -584,6 +590,99 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { check_close_scope(c); case_end; + case_ast_node(rs, RangeStmt, node); + u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed; + check_open_scope(c, node); + + + Operand operand = {Addressing_Invalid}; + check_expr(c, &operand, rs->expr); + + Type *key = NULL; + Type *val = NULL; + if (operand.mode != Addressing_Invalid) { + Type *t = base_type(type_deref(operand.type)); + switch (t->kind) { + case Type_Basic: + if (is_type_string(t)) { + key = t_int; + val = t_rune; + } + break; + case Type_Array: + key = t_int; + val = t->Array.elem; + break; + case Type_Slice: + key = t_int; + val = t->Array.elem; + break; + } + } + + if (key == NULL) { + gbString s = expr_to_string(operand.expr); + error_node(operand.expr, "Cannot iterate over %s", s); + gb_string_free(s); + } + + Entity *entities[2] = {0}; + isize entity_count = 0; + AstNode *lhs[2] = {rs->key, rs->value}; + Type * rhs[2] = {key, val}; + + for (isize i = 0; i < 2; i++) { + if (lhs[i] == NULL) { + continue; + } + AstNode *name = lhs[i]; + Type * type = rhs[i]; + + Entity *entity = NULL; + if (name->kind == AstNode_Ident) { + Token token = name->Ident; + String str = token.string; + Entity *found = NULL; + + if (str_ne(str, str_lit("_"))) { + found = current_scope_lookup_entity(c->context.scope, str); + } + if (found == NULL) { + entity = make_entity_variable(c->allocator, c->context.scope, token, type); + add_entity_definition(&c->info, name, entity); + } else { + TokenPos pos = found->token.pos; + error(token, + "Redeclaration of `%.*s` in this scope\n" + "\tat %.*s(%td:%td)", + LIT(str), LIT(pos.file), pos.line, pos.column); + entity = found; + } + } else { + error_node(name, "A variable declaration must be an identifier"); + } + + if (entity == NULL) { + entity = make_entity_dummy_variable(c->allocator, c->global_scope, ast_node_token(name)); + } + + entities[entity_count++] = entity; + + if (type == NULL) { + entity->type = t_invalid; + entity->flags |= EntityFlag_Used; + } + } + + for (isize i = 0; i < entity_count; i++) { + add_entity(c, c->context.scope, entities[i]->identifier, entities[i]); + } + + check_stmt(c, rs->body, new_flags); + + check_close_scope(c); + case_end; + case_ast_node(ms, MatchStmt, node); Operand x = {0}; diff --git a/src/parser.c b/src/parser.c index 086bf9bd7..da87a6c7c 100644 --- a/src/parser.c +++ b/src/parser.c @@ -204,6 +204,13 @@ AST_NODE_KIND(_ComplexStmtBegin, "", i32) \ AstNode *post; \ AstNode *body; \ }) \ + AST_NODE_KIND(RangeStmt, "range statement", struct { \ + Token token; \ + AstNode * key; \ + AstNode * value; \ + AstNode * expr; \ + AstNode * body; \ + }) \ AST_NODE_KIND(CaseClause, "case clause", struct { \ Token token; \ AstNodeArray list; \ @@ -847,7 +854,15 @@ AstNode *make_for_stmt(AstFile *f, Token token, AstNode *init, AstNode *cond, As result->ForStmt.body = body; return result; } - +AstNode *make_range_stmt(AstFile *f, Token token, AstNode *key, AstNode *value, AstNode *expr, AstNode *body) { + AstNode *result = make_node(f, AstNode_RangeStmt); + result->RangeStmt.token = token; + result->RangeStmt.key = key; + result->RangeStmt.value = value; + result->RangeStmt.expr = expr; + result->RangeStmt.body = body; + return result; +} AstNode *make_match_stmt(AstFile *f, Token token, AstNode *init, AstNode *tag, AstNode *body) { AstNode *result = make_node(f, AstNode_MatchStmt); @@ -1195,6 +1210,7 @@ void fix_advance_to_next_stmt(AstFile *f) { case Token_when: case Token_return: case Token_for: + case Token_range: case Token_match: case Token_defer: case Token_asm: @@ -1749,8 +1765,9 @@ AstNode *parse_operand(AstFile *f, bool lhs) { syntax_error(token, "A procedure tagged as `#foreign` cannot have a body"); } AstNode *curr_proc = f->curr_proc; + AstNode *body = NULL; f->curr_proc = type; - AstNode *body = parse_body(f); + body = parse_body(f); f->curr_proc = curr_proc; return make_proc_lit(f, type, body, tags, foreign_name, link_name); @@ -2062,7 +2079,7 @@ AstNodeArray parse_rhs_expr_list(AstFile *f) { return parse_expr_list(f, false); } -AstNodeArray parse_identfier_list(AstFile *f) { +AstNodeArray parse_identifier_list(AstFile *f) { AstNodeArray list = make_ast_node_array(f); do { @@ -2110,8 +2127,63 @@ AstNode *parse_type(AstFile *f) { return type; } + +AstNode *parse_value_decl(AstFile *f, AstNodeArray lhs) { + parse_check_name_list_for_reserves(f, lhs); + + AstNode *type = NULL; + AstNodeArray values = {0}; + bool is_mutable = true; + + if (allow_token(f, Token_Colon)) { + if (!allow_token(f, Token_type)) { + type = parse_type_attempt(f); + } + } else if (f->curr_token.kind != Token_Eq && + f->curr_token.kind != Token_Semicolon) { + syntax_error(f->curr_token, "Expected a type separator `:` or `=`"); + } + + + switch (f->curr_token.kind) { + case Token_Colon: + is_mutable = false; + /*fallthrough*/ + case Token_Eq: + next_token(f); + values = parse_rhs_expr_list(f); + if (values.count > lhs.count) { + syntax_error(f->curr_token, "Too many values on the right hand side of the declaration"); + } else if (values.count < lhs.count && !is_mutable) { + syntax_error(f->curr_token, "All constant declarations must be defined"); + } else if (values.count == 0) { + syntax_error(f->curr_token, "Expected an expression for this declaration"); + } + break; + } + + if (is_mutable) { + if (type == NULL && values.count == 0) { + syntax_error(f->curr_token, "Missing variable type or initialization"); + return make_bad_decl(f, f->curr_token, f->curr_token); + } + } else { + if (type == NULL && values.count == 0 && lhs.count > 0) { + syntax_error(f->curr_token, "Missing constant value"); + return make_bad_decl(f, f->curr_token, f->curr_token); + } + } + + if (values.e == NULL) { + values = make_ast_node_array(f); + } + + AstNodeArray specs = {0}; + array_init_reserve(&specs, heap_allocator(), 1); + return make_value_decl(f, is_mutable, lhs, type, values); +} + AstNode *parse_simple_stmt(AstFile *f) { - Token start_token = f->curr_token; AstNodeArray lhs = parse_lhs_expr_list(f); Token token = f->curr_token; switch (token.kind) { @@ -2143,60 +2215,8 @@ AstNode *parse_simple_stmt(AstFile *f) { return make_assign_stmt(f, token, lhs, rhs); } break; - case Token_Colon: { - parse_check_name_list_for_reserves(f, lhs); - - AstNode *type = NULL; - AstNodeArray values = {0}; - bool is_mutable = true; - - if (allow_token(f, Token_Colon)) { - if (!allow_token(f, Token_type)) { - type = parse_type_attempt(f); - } - } else if (f->curr_token.kind != Token_Eq && - f->curr_token.kind != Token_Semicolon) { - syntax_error(f->curr_token, "Expected a type separator `:` or `=`"); - } - - - switch (f->curr_token.kind) { - case Token_Colon: - is_mutable = false; - /*fallthrough*/ - case Token_Eq: - next_token(f); - values = parse_rhs_expr_list(f); - if (values.count > lhs.count) { - syntax_error(f->curr_token, "Too many values on the right hand side of the declaration"); - } else if (values.count < lhs.count && !is_mutable) { - syntax_error(f->curr_token, "All constant declarations must be defined"); - } else if (values.count == 0) { - syntax_error(f->curr_token, "Expected an expression for this declaration"); - } - break; - } - - if (is_mutable) { - if (type == NULL && values.count == 0) { - syntax_error(f->curr_token, "Missing variable type or initialization"); - return make_bad_decl(f, f->curr_token, f->curr_token); - } - } else { - if (type == NULL && values.count == 0 && lhs.count > 0) { - syntax_error(f->curr_token, "Missing constant value"); - return make_bad_decl(f, f->curr_token, f->curr_token); - } - } - - if (values.e == NULL) { - values = make_ast_node_array(f); - } - - AstNodeArray specs = {0}; - array_init_reserve(&specs, heap_allocator(), 1); - return make_value_decl(f, is_mutable, lhs, type, values); - } break; + case Token_Colon: + return parse_value_decl(f, lhs); } if (lhs.count > 1) { @@ -2265,7 +2285,7 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, bool allow_using, is_using = true; } - AstNodeArray names = parse_identfier_list(f); + AstNodeArray names = parse_identifier_list(f); if (names.count == 0) { syntax_error(f->curr_token, "Empty parameter declaration"); break; @@ -2523,9 +2543,14 @@ void parse_proc_signature(AstFile *f, AstNode *parse_body(AstFile *f) { AstNodeArray stmts = {0}; Token open, close; + isize prev_expr_level = f->expr_level; + + // NOTE(bill): The body may be within an expression so reset to zero + f->expr_level = 0; open = expect_token(f, Token_OpenBrace); stmts = parse_stmt_list(f); close = expect_token(f, Token_CloseBrace); + f->expr_level = prev_expr_level; return make_block_stmt(f, stmts, open, close); } @@ -2727,8 +2752,7 @@ AstNode *parse_for_stmt(AstFile *f) { if (f->curr_token.kind != Token_Semicolon) { cond = parse_simple_stmt(f); if (is_ast_node_complex_stmt(cond)) { - syntax_error(f->curr_token, - "You are not allowed that type of statement in a for statement, it is too complex!"); + syntax_error(f->curr_token, "You are not allowed that type of statement in a for statement, it is too complex!"); } } @@ -2752,6 +2776,45 @@ AstNode *parse_for_stmt(AstFile *f) { return make_for_stmt(f, token, init, cond, end, body); } + +AstNode *parse_range_stmt(AstFile *f) { + if (f->curr_proc == NULL) { + syntax_error(f->curr_token, "You cannot use a range statement in the file scope"); + return make_bad_stmt(f, f->curr_token, f->curr_token); + } + + Token token = expect_token(f, Token_range); + AstNodeArray names = parse_identifier_list(f); + parse_check_name_list_for_reserves(f, names); + Token colon = expect_token_after(f, Token_Colon, "range name list"); + + isize prev_level = f->expr_level; + f->expr_level = -1; + AstNode *expr = parse_expr(f, false); + f->expr_level = prev_level; + + AstNode *key = NULL; + AstNode *value = NULL; + AstNode *body = parse_block_stmt(f, false); + + switch (names.count) { + case 0: + break; + case 1: + key = names.e[0]; + break; + case 2: + key = names.e[0]; + value = names.e[1]; + break; + default: + error_node(names.e[names.count-1], "Expected at most 2 expressions"); + return make_bad_stmt(f, token, f->curr_token); + } + + return make_range_stmt(f, token, key, value, expr, body); +} + AstNode *parse_case_clause(AstFile *f) { Token token = f->curr_token; AstNodeArray list = make_ast_node_array(f); @@ -2929,6 +2992,7 @@ AstNode *parse_stmt(AstFile *f) { case Token_if: return parse_if_stmt(f); case Token_when: return parse_when_stmt(f); case Token_for: return parse_for_stmt(f); + case Token_range: return parse_range_stmt(f); case Token_match: return parse_match_stmt(f); case Token_defer: return parse_defer_stmt(f); case Token_asm: return parse_asm_stmt(f); @@ -2944,7 +3008,8 @@ AstNode *parse_stmt(AstFile *f) { return s; case Token_using: { - next_token(f); + // TODO(bill): Make using statements better + Token token = expect_token(f, Token_using); AstNode *node = parse_stmt(f); bool valid = false; @@ -1807,7 +1807,7 @@ ssaValue *ssa_string_elem(ssaProcedure *proc, ssaValue *string) { } ssaValue *ssa_string_len(ssaProcedure *proc, ssaValue *string) { Type *t = ssa_type(string); - GB_ASSERT(t->kind == Type_Basic && t->Basic.kind == Basic_string); + GB_ASSERT_MSG(t->kind == Type_Basic && t->Basic.kind == Basic_string, "%s", type_to_string(t)); return ssa_emit_struct_ev(proc, string, 1); } @@ -3908,6 +3908,129 @@ void ssa_build_when_stmt(ssaProcedure *proc, AstNodeWhenStmt *ws) { } } +void ssa_build_range_indexed(ssaProcedure *proc, ssaValue *expr, Type *val_type, + ssaValue **key_, ssaValue **val_, ssaBlock **loop_, ssaBlock **done_) { + ssaValue *count = NULL; + Type *expr_type = base_type(ssa_type(expr)); + switch (expr_type->kind) { + case Type_Array: + count = ssa_make_const_int(proc->module->allocator, expr_type->Array.count); + break; + case Type_Slice: + count = ssa_slice_len(proc, expr); + break; + default: + GB_PANIC("Cannot do range_indexed of %s", type_to_string(expr_type)); + break; + } + + ssaValue *idx = NULL; + ssaValue *val = NULL; + ssaBlock *loop = NULL; + ssaBlock *done = NULL; + ssaBlock *body = NULL; + + ssaValue *index = ssa_add_local_generated(proc, t_int); + ssa_emit_store(proc, index, ssa_make_const_int(proc->module->allocator, -1)); + + loop = ssa_add_block(proc, NULL, "rangeindex.loop"); + ssa_emit_jump(proc, loop); + proc->curr_block = loop; + + ssaValue *incr = ssa_emit_arith(proc, Token_Add, ssa_emit_load(proc, index), v_one, t_int); + ssa_emit_store(proc, index, incr); + + body = ssa_add_block(proc, NULL, "rangeindex.body"); + done = ssa_add_block(proc, NULL, "rangeindex.done"); + ssaValue *cond = ssa_emit_comp(proc, Token_Lt, incr, count); + ssa_emit_if(proc, cond, body, done); + proc->curr_block = body; + + idx = ssa_emit_load(proc, index); + if (val_type != NULL) { + switch (expr_type->kind) { + case Type_Array: { + val = ssa_emit_load(proc, ssa_emit_array_ep(proc, expr, idx)); + } break; + case Type_Slice: { + ssaValue *elem = ssa_slice_elem(proc, expr); + val = ssa_emit_load(proc, ssa_emit_ptr_offset(proc, elem, idx)); + } break; + default: + GB_PANIC("Cannot do range_indexed of %s", type_to_string(expr_type)); + break; + } + } + + if (key_) *key_ = idx; + if (val_) *val_ = val; + if (loop_) *loop_ = loop; + if (done_) *done_ = done; +} + + +void ssa_build_range_string(ssaProcedure *proc, ssaValue *expr, Type *val_type, + ssaValue **key_, ssaValue **val_, ssaBlock **loop_, ssaBlock **done_) { + ssaValue *count = v_zero; + Type *expr_type = base_type(ssa_type(expr)); + switch (expr_type->kind) { + case Type_Basic: + count = ssa_string_len(proc, expr); + break; + default: + GB_PANIC("Cannot do range_string of %s", type_to_string(expr_type)); + break; + } + + ssaValue *idx = NULL; + ssaValue *val = NULL; + ssaBlock *loop = NULL; + ssaBlock *done = NULL; + ssaBlock *body = NULL; + + ssaValue *index = ssa_add_local_generated(proc, t_int); + ssa_emit_store(proc, index, v_zero); + + ssaValue *offset_ = ssa_add_local_generated(proc, t_int); + ssa_emit_store(proc, index, v_zero); + + loop = ssa_add_block(proc, NULL, "rangestring.loop"); + ssa_emit_jump(proc, loop); + proc->curr_block = loop; + + + + body = ssa_add_block(proc, NULL, "rangestring.body"); + done = ssa_add_block(proc, NULL, "rangestring.done"); + + ssaValue *offset = ssa_emit_load(proc, offset_); + + ssaValue *cond = ssa_emit_comp(proc, Token_Lt, offset, count); + ssa_emit_if(proc, cond, body, done); + proc->curr_block = body; + + + ssaValue *str_elem = ssa_emit_ptr_offset(proc, ssa_string_elem(proc, expr), offset); + ssaValue *str_len = ssa_emit_arith(proc, Token_Sub, count, offset, t_int); + ssaValue **args = gb_alloc_array(proc->module->allocator, ssaValue *, 1); + args[0] = ssa_emit_string(proc, str_elem, str_len); + ssaValue *rune_and_len = ssa_emit_global_call(proc, "__string_decode_rune", args, 1); + ssaValue *len = ssa_emit_struct_ev(proc, rune_and_len, 1); + ssa_emit_store(proc, offset_, ssa_emit_arith(proc, Token_Add, offset, len, t_int)); + + + idx = ssa_emit_load(proc, index); + if (val_type != NULL) { + val = ssa_emit_struct_ev(proc, rune_and_len, 0); + } + ssa_emit_store(proc, index, ssa_emit_arith(proc, Token_Add, ssa_emit_load(proc, index), v_one, t_int)); + + if (key_) *key_ = idx; + if (val_) *val_ = val; + if (loop_) *loop_ = loop; + if (done_) *done_ = done; +} + void ssa_build_stmt_internal(ssaProcedure *proc, AstNode *node) { switch (node->kind) { case_ast_node(bs, EmptyStmt, node); @@ -4312,7 +4435,93 @@ void ssa_build_stmt_internal(ssaProcedure *proc, AstNode *node) { proc->curr_block = done; + case_end; + + case_ast_node(rs, RangeStmt, node); + ssa_emit_comment(proc, str_lit("RangeStmt")); + + Type *key_type = NULL; + Type *val_type = NULL; + if (rs->key != NULL && !ssa_is_blank_ident(rs->key)) { + key_type = type_of_expr(proc->module->info, rs->key); + } + if (rs->value != NULL && !ssa_is_blank_ident(rs->value)) { + val_type = type_of_expr(proc->module->info, rs->value); + } + + if (key_type != NULL) { + ssa_add_local_for_identifier(proc, rs->key, true); + } + if (val_type != NULL) { + ssa_add_local_for_identifier(proc, rs->value, true); + } + + ssaValue *key = NULL; + ssaValue *val = NULL; + ssaBlock *loop = NULL; + ssaBlock *done = NULL; + + Type *expr_type = type_of_expr(proc->module->info, rs->expr); + Type *et = base_type(type_deref(expr_type)); + bool deref = is_type_pointer(expr_type); + switch (et->kind) { + case Type_Array: { + ssaValue *array = ssa_build_addr(proc, rs->expr).addr; + if (deref) { + array = ssa_emit_load(proc, array); + } + ssa_build_range_indexed(proc, array, val_type, &key, &val, &loop, &done); + } break; + case Type_Slice: { + ssaValue *slice = ssa_build_expr(proc, rs->expr); + if (deref) { + slice = ssa_emit_load(proc, slice); + } + ssa_build_range_indexed(proc, slice, val_type, &key, &val, &loop, &done); + } break; + case Type_Basic: { + ssaValue *string = ssa_build_expr(proc, rs->expr); + if (deref) { + string = ssa_emit_load(proc, string); + } + if (is_type_untyped(expr_type)) { + ssaValue *s = ssa_add_local_generated(proc, t_string); + ssa_emit_store(proc, s, string); + string = ssa_emit_load(proc, s); + } + ssa_build_range_string(proc, string, val_type, &key, &val, &loop, &done); + } break; + default: + GB_PANIC("Cannot range over %s", type_to_string(expr_type)); + break; + } + + + ssaAddr key_addr = {0}; + ssaAddr val_addr = {0}; + if (key_type != NULL) { + key_addr = ssa_build_addr(proc, rs->key); + } + if (val_type != NULL) { + val_addr = ssa_build_addr(proc, rs->value); + } + if (key_type != NULL) { + ssa_addr_store(proc, key_addr, key); + } + if (val_type != NULL) { + ssa_addr_store(proc, val_addr, val); + } + + ssa_push_target_list(proc, done, loop, NULL); + + ssa_open_scope(proc); + ssa_build_stmt(proc, rs->body); + ssa_close_scope(proc, ssaDeferExit_Default, NULL); + + ssa_pop_target_list(proc); + ssa_emit_jump(proc, loop); + proc->curr_block = done; case_end; case_ast_node(ms, MatchStmt, node); diff --git a/src/tokenizer.c b/src/tokenizer.c index 2625dbf42..5e0f31279 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -84,10 +84,6 @@ TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \ TOKEN_KIND(Token_type, "type"), \ TOKEN_KIND(Token_proc, "proc"), \ - /* TOKEN_KIND(Token_var, "var"), */\ - /* TOKEN_KIND(Token_const, "const"), */\ - /* TOKEN_KIND(Token_import, "import"), */\ - /* TOKEN_KIND(Token_include, "include"), */\ TOKEN_KIND(Token_macro, "macro"), \ TOKEN_KIND(Token_match, "match"), \ TOKEN_KIND(Token_break, "break"), \ |