Cleaning up parsing / typechecking of calls slightly, adding any vargs

This commit is contained in:
Krzosa Karol
2022-06-20 09:28:38 +02:00
parent aa5741203f
commit 4e288dcfab
7 changed files with 84 additions and 67 deletions

26
ast.cpp
View File

@@ -57,7 +57,7 @@ enum{
AST_STRICT = bit_flag(3), AST_STRICT = bit_flag(3),
AST_AGGREGATE = bit_flag(4), AST_AGGREGATE = bit_flag(4),
AST_AGGREGATE_CHILD = bit_flag(5), AST_AGGREGATE_CHILD = bit_flag(5),
AST_ITEM_INCLUDED = bit_flag(6), AST_ANY_VARGS = bit_flag(6),
AST_ATOM = bit_flag(7), AST_ATOM = bit_flag(7),
AST_FOREIGN = bit_flag(8), AST_FOREIGN = bit_flag(8),
AST_DECL = bit_flag(9), AST_DECL = bit_flag(9),
@@ -88,13 +88,23 @@ struct Ast_Atom: Ast_Expr{
INLINE_VALUE_FIELDS; INLINE_VALUE_FIELDS;
}; };
struct Ast_Call_Item: Ast_Expr{ typedef U32 Ast_Call_Item_Flag;
Ast_Atom *name; // for calls only name, for compounds name | index enum{
Ast_Expr *item; CALL_INDEX = bit_flag(1),
Ast_Expr *index; 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; Intern_String resolved_name;
S64 resolved_index;
}; };
struct Ast_Call: Ast_Expr{ struct Ast_Call: Ast_Expr{
@@ -270,9 +280,9 @@ struct Ast_Decl: Ast{
result->pos = ipos; \ result->pos = ipos; \
result->di = ++pctx->unique_ids 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 * 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); Ast *result = (Ast *)exp_alloc(pctx->perm, size, AF_ZeroMemory);
result->flags = flags; result->flags = flags;
result->kind = kind; result->kind = kind;

View File

@@ -54,6 +54,7 @@ enum Token_Kind{
TK_ThreeDots, TK_ThreeDots,
TK_Semicolon, TK_Semicolon,
TK_Dot, TK_Dot,
TK_TwoDots,
TK_NewLine, TK_NewLine,
TK_Colon, TK_Colon,

View File

@@ -381,13 +381,15 @@ lex__stream(Lexer *lexer){
}break; }break;
case '.': { case '.': {
if(lexc(s) == '.' && lexci(s,1) == '.') { if(lexc(s) == '.'){
lex_advance(s); lex_advance(s); lex_advance(s);
if(lexci(s,1) == '.') {
lex_advance(s);
t.kind = TK_ThreeDots; t.kind = TK_ThreeDots;
} }
else { else t.kind = TK_TwoDots;
t.kind = TK_Dot;
} }
else t.kind = TK_Dot;
} break; } break;
case '\'':{ case '\'':{

View File

@@ -43,6 +43,7 @@ want to export all the symbols, we can namespace them optionally.
@todo @todo
[ ] - Probably need to give Ast_Expr a Value field, then I can express Type nicely [ ] - 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 [ ] - 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 [ ] - #test construct that would gather all tests and run them on start of program or something
[ ] - Foreign import that would link library [ ] - Foreign import that would link library

View File

@@ -164,27 +164,27 @@ parse_expr_call(Ast_Expr *left, Token_Kind close_kind){
Array<Ast_Call_Item *> exprs = {scratch}; Array<Ast_Call_Item *> exprs = {scratch};
while(!token_is(close_kind)){ while(!token_is(close_kind)){
Token *token = token_get(); Ast_Call_Item *item_comp = ast_new(Ast_Call_Item, AST_CALL_ITEM, token_get(), AST_EXPR);
Ast_Atom *name = 0; item_comp->item = parse_expr();
Ast_Expr *index = 0;
Ast_Expr *item = parse_expr();
if(token_match(TK_Assign)){ if(token_match(TK_Assign)){
assert(is_flag_set(item->flags, AST_ATOM)); assert(is_flag_set(item_comp->item->flags, AST_ATOM));
if(item->kind != AST_IDENT){
index = item; if(item_comp->item->kind != AST_IDENT){
} else{ item_comp->index = item_comp->item;
name = (Ast_Atom *)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);
} }
if(name && index) compiler_error(token, "Both index and name are present, that is invalid"); item_comp->item = parse_expr();
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); exprs.add(item_comp);
if(!token_match(TK_Comma)){ if(!token_match(TK_Comma)){
break; break;
} }
@@ -234,7 +234,7 @@ parse_stmt_scope(Ast_Scope *scope_defined_outside = 0){
} }
else if(token_match_keyword(keyword_switch)){ 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->value = parse_expr();
result->cases = {scratch}; result->cases = {scratch};
@@ -245,7 +245,7 @@ parse_stmt_scope(Ast_Scope *scope_defined_outside = 0){
continue; 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))) if(token_match_pound(pctx->intern("fallthrough"_s)))
switch_case->fallthrough = true; switch_case->fallthrough = true;
@@ -392,27 +392,27 @@ function Ast_Lambda *
parse_lambda(Token *token){ parse_lambda(Token *token){
Scratch scratch; Scratch scratch;
B32 has_var_args = false;
Array<Ast_Decl *> params = {scratch}; Array<Ast_Decl *> params = {scratch};
if(!token_is(TK_CloseParen)){ if(!token_is(TK_CloseParen)){
for(;;){ for(;;){
Token *name = token_get(); Token *name = token_get();
if(token_match(TK_Identifier)){ if(token_match(TK_Identifier)){
token_expect(TK_Colon); 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_TwoDots)){
if(token_match(TK_Assign)) { set_flag(param->flags, AST_ANY_VARGS);
default_value = parse_expr(); }
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); 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"); else compiler_error(name, "Expected [Identifier] or [...] when parsing lambda arguments");
if(!token_match(TK_Comma)) if(!token_match(TK_Comma))

View File

@@ -13,10 +13,9 @@ test_arrays :: ()
assert(i+1 == array1[i]) assert(i+1 == array1[i])
array6: []*S64 = {&array1[0]} array6: []*S64 = {&array1[0]}
for array1 for array1;; *it = 0
*it = 0 for array2;; *it = 0
for i := 0, i < length_of(array1), i+=1 for i := 0, i < length_of(array1), i+=1;; assert(0 == array1[i])
assert(0 == array1[i])
test_any :: () test_any :: ()
some_int_value := 10 some_int_value := 10
@@ -25,6 +24,9 @@ test_any :: ()
imp_any := thing imp_any := thing
assert(thing.type != Any) assert(thing.type != Any)
any_array := []Any{some_int_value, thing} any_array := []Any{some_int_value, thing}
for any_array
assert(it.type == S64)
Some_Struct :: struct Some_Struct :: struct
thing: int thing: int

View File

@@ -571,11 +571,11 @@ resolve_stmt(Ast *ast, Ast_Type *ret){
if((!node->init && !node->iter) && (is_array(op.type) || is_slice(op.type))){ if((!node->init && !node->iter) && (is_array(op.type) || is_slice(op.type))){
node->is_array_traversal = true; node->is_array_traversal = true;
if(is_slice(op.type)) node->is_also_slice_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->state = DECL_RESOLVED;
var->type = type_pointer(op.type->base); var->type = type_pointer(op.type->base);
var->name = intern_it; var->name = intern_it;
insert_into_scope(node->parent_scope, var); insert_into_scope(node->scope, var);
node->array_traversal_var = var; node->array_traversal_var = var;
} }
else if(!is_bool(op.type)){ else if(!is_bool(op.type)){
@@ -744,10 +744,10 @@ resolve_compound_array(Ast_Call *node, Ast_Type *type){
S64 default_counter = 0; S64 default_counter = 0;
For(node->exprs){ For(node->exprs){
if(it->name) if(is_flag_set(it->call_flags, CALL_NAME))
compiler_error(it->pos, "Array doesn't have named fields"); 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; default_counter = -1;
Operand op = require_const_int(it->index, AST_CANT_BE_NULL); 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??? 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){ resolve_compound_struct(Ast_Call *node, Ast_Type *type){
S64 default_counter = 0; S64 default_counter = 0;
For(node->exprs){ For(node->exprs){
if(it->index) if(is_flag_set(it->call_flags, CALL_INDEX))
compiler_error(it->pos, "Struct cant be indexed"); compiler_error(it->pos, "Index specifier in a struct compound expression is not legal");
Ast_Type *item_type = 0; Ast_Type *item_type = 0;
if(it->name){ if(is_flag_set(it->call_flags, CALL_NAME)){
For_Named(type->agg.members, m){ For_Named(type->agg.members, m){
if(it->name->intern_val == m.name){ if(it->name->intern_val == m.name){
it->resolved_name = 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; Ast_Call_Item *item = 0;
For(node->exprs){ 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; Ast_Atom *name = it->name;
assert(name->kind == AST_IDENT); assert(name->kind == AST_IDENT);
was_name_indexed = true; was_name_indexed = true;
@@ -1128,7 +1129,7 @@ resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_context){
} }
if(item){ 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); 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); make_sure_value_is_compatible_with_type(item->pos, &expr, lambda_arg->type, TYPE_AND_EXPR_REQUIRED);
item->resolved_type = lambda_arg->type; 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); 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_type = lambda_arg->expr->resolved_type;
call_item->resolved_index = lambda->args.get_index(&lambda_arg); 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); items.add(call_item);
} }
else compiler_error(lambda_arg->pos, "Required value in lambda call was not passed"); 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 // @note: check if all arguments are included and cleanup
For(node->exprs){ 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"); 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); return operand_rvalue(name.type->func.ret);