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_AGGREGATE = bit_flag(4),
AST_AGGREGATE_CHILD = bit_flag(5),
AST_ITEM_INCLUDED = bit_flag(6),
AST_ANY_VARGS = bit_flag(6),
AST_ATOM = bit_flag(7),
AST_FOREIGN = bit_flag(8),
AST_DECL = bit_flag(9),
@@ -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;

View File

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

View File

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

View File

@@ -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

View File

@@ -164,27 +164,27 @@ parse_expr_call(Ast_Expr *left, Token_Kind close_kind){
Array<Ast_Call_Item *> 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);
}
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");
item_comp->item = parse_expr();
}
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<Ast_Decl *> 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))

View File

@@ -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

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))){
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);