From aa5741203fba9c6157b4eda44a6bcfa554edbeac Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Sun, 19 Jun 2022 22:31:59 +0200 Subject: [PATCH] For loop iterate through arrays and slices --- ast.cpp | 8 ++++++-- ccodegen.cpp | 43 +++++++++++++++++++++++++++++++++++-------- compiler.h | 2 ++ parsing.cpp | 4 ++-- programs/any.kl | 6 +++++- typechecking.cpp | 18 +++++++++++++++++- 6 files changed, 67 insertions(+), 14 deletions(-) diff --git a/ast.cpp b/ast.cpp index 0c5d094..5bb031e 100644 --- a/ast.cpp +++ b/ast.cpp @@ -163,6 +163,10 @@ struct Ast_For: Ast{ Ast_Expr *cond; Ast_Expr *iter; Ast_Scope *scope; + + Ast_Decl *array_traversal_var; + bool is_array_traversal; + bool is_also_slice_traversal; }; struct Ast_Lambda : Ast_Expr { @@ -266,9 +270,9 @@ struct Ast_Decl: Ast{ result->pos = ipos; \ result->di = ++pctx->unique_ids -#define MAKE_AST(T,kind,pos,flags) (T *)ast_new(sizeof(T), kind, pos, flags) +#define new_ast(T,kind,pos,flags) (T *)_new_ast(sizeof(T), kind, pos, flags) function Ast * -ast_new(SizeU size, Ast_Kind kind, Token *pos, Ast_Flag flags = 0){ +_new_ast(SizeU size, Ast_Kind kind, Token *pos, Ast_Flag flags = 0){ Ast *result = (Ast *)exp_alloc(pctx->perm, size, AF_ZeroMemory); result->flags = flags; result->kind = kind; diff --git a/ccodegen.cpp b/ccodegen.cpp index 9f007cd..a2113f0 100644 --- a/ccodegen.cpp +++ b/ccodegen.cpp @@ -500,14 +500,41 @@ gen_ast(Ast *ast){ } CASE(FOR, For){ - gen("for("); - if(node->init) gen_expr(node->init); - gen(";"); - if(node->cond) gen_expr(node->cond); - gen(";"); - if(node->iter) gen_expr(node->iter); - gen(")"); - gen_stmt_scope(node->scope); + + // Array iter + if(node->is_array_traversal){ + gen("for(S64 _i%d = 0; _i%d < ", node->pos->line, node->pos->line); + gen_expr(node->cond); + gen(".len; _i%d+=1)", node->pos->line); + gen("{"); + global_indent++; + genln(""); + gen_simple_decl(node->array_traversal_var->type, node->array_traversal_var->name); + gen(" = "); + gen_expr(node->cond); + if(node->is_also_slice_traversal) gen(".data"); + gen(" + _i%d;", node->pos->line); + For(node->scope->stmts) { + gen_line(it); + genln(""); + gen_ast(it); + } + global_indent--; + genln("}"); + } + + // Normal for loop + else{ + gen("for("); + if(node->init) gen_expr(node->init); + gen(";"); + if(node->cond) gen_expr(node->cond); + gen(";"); + if(node->iter) gen_expr(node->iter); + gen(")"); + gen_stmt_scope(node->scope); + } + BREAK(); } diff --git a/compiler.h b/compiler.h index 04db2b0..1eb865a 100644 --- a/compiler.h +++ b/compiler.h @@ -175,6 +175,7 @@ Intern_String keyword_enum; Intern_String intern_void; Intern_String intern_foreign; +Intern_String intern_it; Intern_String intern_strict; Intern_String intern_flag; @@ -240,6 +241,7 @@ lex_init(Allocator *token_string_arena, Allocator *map_allocator, Lexer *l){ intern_strict = intern_string(&l->interns, "strict"_s); intern_void = intern_string(&l->interns, "void"_s); intern_flag = intern_string(&l->interns, "flag"_s); + intern_it = intern_string(&l->interns, "it"_s); } function void diff --git a/parsing.cpp b/parsing.cpp index ed0ad64..6b37c1b 100644 --- a/parsing.cpp +++ b/parsing.cpp @@ -234,7 +234,7 @@ parse_stmt_scope(Ast_Scope *scope_defined_outside = 0){ } else if(token_match_keyword(keyword_switch)){ - Ast_Switch *result = MAKE_AST(Ast_Switch, AST_SWITCH, token, AST_STMT); + Ast_Switch *result = new_ast(Ast_Switch, AST_SWITCH, token, AST_STMT); result->value = parse_expr(); result->cases = {scratch}; @@ -245,7 +245,7 @@ parse_stmt_scope(Ast_Scope *scope_defined_outside = 0){ continue; } - Ast_Switch_Case *switch_case = MAKE_AST(Ast_Switch_Case, AST_SWITCH_CASE, token_get(), AST_STMT); + Ast_Switch_Case *switch_case = new_ast(Ast_Switch_Case, AST_SWITCH_CASE, token_get(), AST_STMT); if(token_match_pound(pctx->intern("fallthrough"_s))) switch_case->fallthrough = true; diff --git a/programs/any.kl b/programs/any.kl index e487e32..5af19e2 100644 --- a/programs/any.kl +++ b/programs/any.kl @@ -1,5 +1,4 @@ - main :: (argc: int, argv: **char): int test_arrays() test_any() @@ -14,6 +13,11 @@ test_arrays :: () assert(i+1 == array1[i]) array6: []*S64 = {&array1[0]} + for array1 + *it = 0 + for i := 0, i < length_of(array1), i+=1 + assert(0 == array1[i]) + test_any :: () some_int_value := 10 thing: Any = some_int_value diff --git a/typechecking.cpp b/typechecking.cpp index a5dee3e..344696f 100644 --- a/typechecking.cpp +++ b/typechecking.cpp @@ -566,7 +566,23 @@ resolve_stmt(Ast *ast, Ast_Type *ret){ } resolve_expr(node->init, AST_CAN_BE_NULL); - resolve_and_require_bool("Conditional in a for loop condition", node->cond, AST_CAN_BE_NULL); + Operand op = resolve_expr(node->cond, AST_CAN_BE_NULL); + if(node->cond){ + if((!node->init && !node->iter) && (is_array(op.type) || is_slice(op.type))){ + node->is_array_traversal = true; + if(is_slice(op.type)) node->is_also_slice_traversal = true; + Ast_Decl *var = new_ast(Ast_Decl, AST_VAR, node->cond->pos, AST_DECL); + var->state = DECL_RESOLVED; + var->type = type_pointer(op.type->base); + var->name = intern_it; + insert_into_scope(node->parent_scope, var); + node->array_traversal_var = var; + } + else if(!is_bool(op.type)){ + compiler_error(node->pos, "Invalid type of for loop condition %Q, required [Bool]", typestring(op.type)); + } + } + resolve_expr(node->iter, AST_CAN_BE_NULL); For(node->scope->stmts) resolve_stmt(it, ret); BREAK();