From 4e288dcfab3c2ab1134989a5a31b37f6622b178b Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Mon, 20 Jun 2022 09:28:38 +0200 Subject: [PATCH] Cleaning up parsing / typechecking of calls slightly, adding any vargs --- ast.cpp | 44 ++++++++++++++++++++++++--------------- compiler.h | 1 + lexing.cpp | 14 +++++++------ main.cpp | 1 + parsing.cpp | 54 ++++++++++++++++++++++++------------------------ programs/any.kl | 10 +++++---- typechecking.cpp | 27 ++++++++++++------------ 7 files changed, 84 insertions(+), 67 deletions(-) diff --git a/ast.cpp b/ast.cpp index 5bb031e..c253363 100644 --- a/ast.cpp +++ b/ast.cpp @@ -52,17 +52,17 @@ enum Ast_Kind: U32{ typedef U32 Ast_Flag; enum{ - AST_EXPR = bit_flag(1), - AST_STMT = bit_flag(2), - AST_STRICT = bit_flag(3), - AST_AGGREGATE = bit_flag(4), + AST_EXPR = bit_flag(1), + AST_STMT = bit_flag(2), + AST_STRICT = bit_flag(3), + AST_AGGREGATE = bit_flag(4), AST_AGGREGATE_CHILD = bit_flag(5), - AST_ITEM_INCLUDED = bit_flag(6), - AST_ATOM = bit_flag(7), - AST_FOREIGN = bit_flag(8), - AST_DECL = bit_flag(9), - AST_GLOBAL = bit_flag(10), - AST_FLAG = bit_flag(11), + AST_ANY_VARGS = bit_flag(6), + AST_ATOM = bit_flag(7), + AST_FOREIGN = bit_flag(8), + AST_DECL = bit_flag(9), + AST_GLOBAL = bit_flag(10), + AST_FLAG = bit_flag(11), }; struct Ast{ @@ -88,13 +88,23 @@ struct Ast_Atom: Ast_Expr{ INLINE_VALUE_FIELDS; }; -struct Ast_Call_Item: Ast_Expr{ - Ast_Atom *name; // for calls only name, for compounds name | index - Ast_Expr *item; - Ast_Expr *index; +typedef U32 Ast_Call_Item_Flag; +enum{ + CALL_INDEX = bit_flag(1), + CALL_NAME = bit_flag(2), + CALL_DOT_ANY = bit_flag(3), + CALL_INCLUDED= bit_flag(4), +}; +struct Ast_Call_Item: Ast_Expr{ + Ast_Call_Item_Flag call_flags; + S32 resolved_index; + Ast_Expr *item; + union { + Ast_Atom *name; + Ast_Expr *index; + }; Intern_String resolved_name; - S64 resolved_index; }; struct Ast_Call: Ast_Expr{ @@ -270,9 +280,9 @@ struct Ast_Decl: Ast{ result->pos = ipos; \ result->di = ++pctx->unique_ids -#define new_ast(T,kind,pos,flags) (T *)_new_ast(sizeof(T), kind, pos, flags) +#define ast_new(T,kind,pos,flags) (T *)_ast_new(sizeof(T), kind, pos, flags) function Ast * -_new_ast(SizeU size, Ast_Kind kind, Token *pos, Ast_Flag flags = 0){ +_ast_new(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/compiler.h b/compiler.h index 1eb865a..5621278 100644 --- a/compiler.h +++ b/compiler.h @@ -54,6 +54,7 @@ enum Token_Kind{ TK_ThreeDots, TK_Semicolon, TK_Dot, + TK_TwoDots, TK_NewLine, TK_Colon, diff --git a/lexing.cpp b/lexing.cpp index 7c2f2aa..7906e5e 100644 --- a/lexing.cpp +++ b/lexing.cpp @@ -381,13 +381,15 @@ lex__stream(Lexer *lexer){ }break; case '.': { - if(lexc(s) == '.' && lexci(s,1) == '.') { - lex_advance(s); lex_advance(s); - t.kind = TK_ThreeDots; - } - else { - t.kind = TK_Dot; + if(lexc(s) == '.'){ + lex_advance(s); + if(lexci(s,1) == '.') { + lex_advance(s); + t.kind = TK_ThreeDots; + } + else t.kind = TK_TwoDots; } + else t.kind = TK_Dot; } break; case '\'':{ diff --git a/main.cpp b/main.cpp index 4e284cd..7bdaac7 100644 --- a/main.cpp +++ b/main.cpp @@ -43,6 +43,7 @@ want to export all the symbols, we can namespace them optionally. @todo [ ] - Probably need to give Ast_Expr a Value field, then I can express Type nicely [ ] - I would love for String, slice, Any etc. to have their struct declarations in source files, I also would want for stuff like string.str to work without weird special cases +[ ] - Var args with Any [ ] - #test construct that would gather all tests and run them on start of program or something [ ] - Foreign import that would link library diff --git a/parsing.cpp b/parsing.cpp index 6b37c1b..90ba7fa 100644 --- a/parsing.cpp +++ b/parsing.cpp @@ -164,27 +164,27 @@ parse_expr_call(Ast_Expr *left, Token_Kind close_kind){ Array exprs = {scratch}; while(!token_is(close_kind)){ - Token *token = token_get(); - Ast_Atom *name = 0; - Ast_Expr *index = 0; - - Ast_Expr *item = parse_expr(); + Ast_Call_Item *item_comp = ast_new(Ast_Call_Item, AST_CALL_ITEM, token_get(), AST_EXPR); + item_comp->item = parse_expr(); if(token_match(TK_Assign)){ - assert(is_flag_set(item->flags, AST_ATOM)); - if(item->kind != AST_IDENT){ - index = item; - } else{ - name = (Ast_Atom *)item; + assert(is_flag_set(item_comp->item->flags, AST_ATOM)); + + if(item_comp->item->kind != AST_IDENT){ + item_comp->index = item_comp->item; + set_flag(item_comp->call_flags, CALL_INDEX); } - item = parse_expr(); + else{ + item_comp->name = (Ast_Atom *)item_comp->item; + set_flag(item_comp->call_flags, CALL_NAME); + } + + item_comp->item = parse_expr(); } - if(name && index) compiler_error(token, "Both index and name are present, that is invalid"); - if(close_kind == TK_OpenParen && index) compiler_error(token, "Lambda calls can't have indexed arguments"); + if(close_kind == TK_OpenParen && is_flag_set(item_comp->call_flags, CALL_INDEX)) + compiler_error(item_comp->pos, "Lambda calls can't have indexed arguments"); - Ast_Call_Item *item_comp = ast_call_item(token, name, index, item); exprs.add(item_comp); - if(!token_match(TK_Comma)){ break; } @@ -234,7 +234,7 @@ parse_stmt_scope(Ast_Scope *scope_defined_outside = 0){ } else if(token_match_keyword(keyword_switch)){ - Ast_Switch *result = new_ast(Ast_Switch, AST_SWITCH, token, AST_STMT); + Ast_Switch *result = ast_new(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 = new_ast(Ast_Switch_Case, AST_SWITCH_CASE, token_get(), AST_STMT); + Ast_Switch_Case *switch_case = ast_new(Ast_Switch_Case, AST_SWITCH_CASE, token_get(), AST_STMT); if(token_match_pound(pctx->intern("fallthrough"_s))) switch_case->fallthrough = true; @@ -392,27 +392,27 @@ function Ast_Lambda * parse_lambda(Token *token){ Scratch scratch; - B32 has_var_args = false; Array params = {scratch}; if(!token_is(TK_CloseParen)){ for(;;){ Token *name = token_get(); if(token_match(TK_Identifier)){ token_expect(TK_Colon); - Ast_Expr *typespec = parse_expr(); + Ast_Decl *param = ast_new(Ast_Decl, AST_VAR, name, AST_DECL); + param->name = name->intern_val; - Ast_Expr *default_value = 0; - if(token_match(TK_Assign)) { - default_value = parse_expr(); + if(token_match(TK_TwoDots)){ + set_flag(param->flags, AST_ANY_VARGS); + } + + else{ + param->typespec = parse_expr(); + if(token_match(TK_Assign)) + param->expr = parse_expr(); } - Ast_Decl *param = ast_var(name, typespec, name->intern_val, default_value); params.add(param); } - else if(token_match(TK_ThreeDots)){ - has_var_args = true; - break; - } else compiler_error(name, "Expected [Identifier] or [...] when parsing lambda arguments"); if(!token_match(TK_Comma)) diff --git a/programs/any.kl b/programs/any.kl index 5af19e2..96607c2 100644 --- a/programs/any.kl +++ b/programs/any.kl @@ -13,10 +13,9 @@ 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]) + for array1;; *it = 0 + for array2;; *it = 0 + for i := 0, i < length_of(array1), i+=1;; assert(0 == array1[i]) test_any :: () some_int_value := 10 @@ -25,6 +24,9 @@ test_any :: () imp_any := thing assert(thing.type != Any) any_array := []Any{some_int_value, thing} + for any_array + assert(it.type == S64) + Some_Struct :: struct thing: int diff --git a/typechecking.cpp b/typechecking.cpp index 344696f..2e297bf 100644 --- a/typechecking.cpp +++ b/typechecking.cpp @@ -571,11 +571,11 @@ resolve_stmt(Ast *ast, Ast_Type *ret){ 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); + Ast_Decl *var = ast_new(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); + insert_into_scope(node->scope, var); node->array_traversal_var = var; } else if(!is_bool(op.type)){ @@ -744,10 +744,10 @@ resolve_compound_array(Ast_Call *node, Ast_Type *type){ S64 default_counter = 0; For(node->exprs){ - if(it->name) - compiler_error(it->pos, "Array doesn't have named fields"); + if(is_flag_set(it->call_flags, CALL_NAME)) + compiler_error(it->pos, "Arrays can't have named compound expression arguments"); - if(it->index){ + if(is_flag_set(it->call_flags, CALL_INDEX)){ default_counter = -1; Operand op = require_const_int(it->index, AST_CANT_BE_NULL); S64 i = bigint_as_signed(&op.value.big_int_val); // @todo: what happens when big num is here??? @@ -772,11 +772,11 @@ function void resolve_compound_struct(Ast_Call *node, Ast_Type *type){ S64 default_counter = 0; For(node->exprs){ - if(it->index) - compiler_error(it->pos, "Struct cant be indexed"); + if(is_flag_set(it->call_flags, CALL_INDEX)) + compiler_error(it->pos, "Index specifier in a struct compound expression is not legal"); Ast_Type *item_type = 0; - if(it->name){ + if(is_flag_set(it->call_flags, CALL_NAME)){ For_Named(type->agg.members, m){ if(it->name->intern_val == m.name){ it->resolved_name = m.name; @@ -1109,7 +1109,8 @@ resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_context){ Ast_Call_Item *item = 0; For(node->exprs){ - if(it->name){ + assert(!is_flag_set(it->call_flags, CALL_INDEX)); + if(is_flag_set(it->call_flags, CALL_NAME)){ Ast_Atom *name = it->name; assert(name->kind == AST_IDENT); was_name_indexed = true; @@ -1128,7 +1129,7 @@ resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_context){ } if(item){ - set_flag(item->flags, AST_ITEM_INCLUDED); + set_flag(item->call_flags, CALL_INCLUDED); Operand expr = resolve_expr(item->item, AST_CANT_BE_NULL, lambda_arg->type); make_sure_value_is_compatible_with_type(item->pos, &expr, lambda_arg->type, TYPE_AND_EXPR_REQUIRED); item->resolved_type = lambda_arg->type; @@ -1141,7 +1142,7 @@ resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_context){ Ast_Call_Item *call_item = ast_call_item(lambda_arg->expr->pos, 0, 0, lambda_arg->expr); call_item->resolved_type = lambda_arg->expr->resolved_type; call_item->resolved_index = lambda->args.get_index(&lambda_arg); - set_flag(call_item->flags, AST_ITEM_INCLUDED); + set_flag(call_item->call_flags, CALL_INCLUDED); items.add(call_item); } else compiler_error(lambda_arg->pos, "Required value in lambda call was not passed"); @@ -1153,9 +1154,9 @@ resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_context){ // @note: check if all arguments are included and cleanup For(node->exprs){ - if(!is_flag_set(it->flags, AST_ITEM_INCLUDED)) + if(!is_flag_set(it->call_flags, CALL_INCLUDED)) compiler_error(it->pos, "Invalid argument to function call"); - else unset_flag(it->flags, AST_ITEM_INCLUDED); + else unset_flag(it->call_flags, CALL_INCLUDED); } return operand_rvalue(name.type->func.ret);