//----------------------------------------------------------------------------- // AST //----------------------------------------------------------------------------- enum Ast_Kind: U32{ AST_NONE, AST_PACKAGE, AST_VALUE, AST_CAST, AST_IDENT, AST_INDEX, AST_UNARY, AST_BINARY, AST_CALL_ITEM, AST_CALL, AST_POINTER, AST_ARRAY, AST_FOR, AST_IF, AST_IF_NODE, AST_RETURN, AST_BLOCK, AST_PASS, AST_LAMBDA, AST_LAMBDA_ARG, AST_ENUM, AST_ENUM_MEMBER, AST_STRUCT, AST_CONST, AST_VAR, }; typedef U32 Ast_Flag; enum{ AST_EXPR = bit_flag(1), AST_STMT = bit_flag(2), AST_BINDING = 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), }; struct Ast{ U64 id; Token *pos; Ast_Kind kind; Ast *parent; Ast_Flag flags; }; struct Ast_Resolved_Type; struct Ast_Expr:Ast{}; #define VALUE_FIELDS \ Ast_Resolved_Type *type; \ union{ \ bool bool_val; \ F64 f64_val; \ Intern_String intern_val; \ BigInt big_int_val;\ Ast_Resolved_Type *type_val; \ }; #define INLINE_VALUE_FIELDS union{Value value; struct{VALUE_FIELDS};} struct Value{VALUE_FIELDS}; // BigInt big_int_val; struct Ast_Atom: Ast_Expr{ INLINE_VALUE_FIELDS; }; struct Ast_Call_Item: Ast_Expr{ Ast_Atom *name; // index | name Ast_Expr *index; Ast_Expr *item; }; struct Ast_Call: Ast_Expr{ Ast_Resolved_Type *type; // @todo: to map Ast_Expr *name; Array exprs; }; struct Ast_Unary: Ast_Expr{ Token_Kind op; Ast_Expr *expr; U64 padding[3]; // For folding constants into atoms }; struct Ast_Cast: Ast_Expr{ Ast_Expr *expr; Ast_Expr *typespec; }; struct Ast_Index: Ast_Expr{ Ast_Expr *expr; Ast_Expr *index; }; struct Ast_Binary: Ast_Expr{ Token_Kind op; Ast_Expr *left; Ast_Expr *right; }; // Problem: We are parsing out of order, in the middle of parsing a function // we can jump down a different function, we cant therfore use global map. // Each scope needs to have it's checked locals list. To lookup syms we need to // look into global scope and to the locals list. // struct Ast_Block : Ast { // Stmts for global scope Array stmts; // Array members; }; struct Ast_Return: Ast{ Ast_Expr *expr; }; struct Ast_If_Node: Ast{ Ast_Expr *expr ; Ast_Block *block; Ast_Binary*init; }; struct Ast_If: Ast{ Array ifs; }; struct Ast_Pass: Ast{}; struct Ast_For: Ast{ Ast_Expr *init; Ast_Expr *cond; Ast_Expr *iter; Ast_Block *block; }; struct Ast_Lambda_Arg: Ast_Expr{ Intern_String name; Ast_Expr *typespec; Ast_Expr *default_value; }; struct Ast_Lambda : Ast_Expr { Array args; Ast_Expr *ret; Ast_Block *block; B32 has_var_args; }; struct Ast_Array: Ast_Expr{ Ast_Expr *base; Ast_Expr *expr; }; struct Ast_Named:Ast{ Intern_String name; }; enum Ast_Decl_State{ DECL_NOT_RESOLVED, DECL_RESOLVED, DECL_RESOLVING, }; /* How does current declaration order resolver works: * First we put all the global declarations into the global scope (when parsing) all unresolved * All the types are declared INCOMPLETE and RESOLVED * We descent the tree by resolving each of the named declarations, we resolve by their name When we start resolving we set RESOLVING flag and when we complete RESOLVED flag and put into ordered list * When we meet a symbol (named declaration) while descending the tree, we resolve that symbol instead before resolving current declaration. * When we meet a declaration that requires size of a type - field access, var assignment, we need to call "complete_type", it sets COMPLETING flag. This call resolves all the dependencies of that type, sets size of type and marks it as COMPLETE and puts into ordered list. If it detects COMPLETING while resolving, we got a circular dependency. That might happen when we have that struct without pointer inside itself. We need a new algorithm to process structs we probably want default values so constants can be evaluated first, also it's pretty weird that only top scope gets special treatment Idea 1 New algorithm, at some point in a constant we might see the struct inside which is the constant. struct is unresolved so we probably call resolve_name on struct and struct continues resolving omitting already resolved and declaration that requires the struct size. Problem is what happens when we meet a member that references a constant and that constant has reference to struct. Idea 2 We resolve first members without default values, we add to queue dependencies then we resolve constants. And at the end we resolve the queued values. */ struct Ast_Scope{ Array resolved; Array children; Array constants; }; struct Ast_Decl: Ast{ Ast_Decl_State state; // kind:AST_CONST: subkind:AST_STRUCT, AST_ENUM, AST_EXPR(can be TYPE_TYPE), AST_LAMBDA // kind:AST_VAR : subkind:AST_EXPR, AST_LAMBDA Intern_String name; Ast_Kind sub_kind; Ast_Scope *scope; Ast_Resolved_Type *type; }; struct Ast_Var: Ast_Named{ Ast_Expr *typespec; Ast_Expr *expr; }; struct Ast_Const; struct Ast_Resolved_Type; struct Ast_Struct: Ast{ // Required to be Ast_Struct or Ast_Var or Ast_Const Array members; Array const_members; Ast_Resolved_Type *type; }; struct Ast_Enum_Member: Ast{ Intern_String name; Ast_Expr *value; }; struct Ast_Enum: Ast{ Ast_Expr *typespec; Array members; }; struct Ast_Const: Ast_Named{ union{ Ast *ast; Ast_Expr *value; Ast_Struct *agg; Ast_Enum *enu; }; }; struct Ast_Package:Ast{ Intern_String name; Array decls; Array ordered; }; //----------------------------------------------------------------------------- // AST Constructors beginning with expressions //----------------------------------------------------------------------------- #define AST_NEW(T,ikind,ipos,iflags) \ Ast_##T *result = exp_alloc_type(pctx->perm, Ast_##T, AF_ZeroMemory);\ result->flags = iflags; \ result->kind = AST_##ikind; \ result->pos = ipos; \ result->id = ++pctx->unique_ids function Ast_Atom * ast_str(Token *pos, Intern_String string){ AST_NEW(Atom, VALUE, pos, AST_EXPR | AST_ATOM); result->type = untyped_string; result->intern_val = string; return result; } function Ast_Atom * ast_ident(Token *pos, Intern_String string){ AST_NEW(Atom, IDENT, pos, AST_EXPR | AST_ATOM); result->intern_val = string; return result; } function Ast_Atom * ast_bool(Token *pos, B32 bool_val){ AST_NEW(Atom, VALUE, pos, AST_EXPR | AST_ATOM); result->bool_val = bool_val; result->type = untyped_bool; return result; } function Ast_Atom * ast_float(Token *pos, F64 value){ AST_NEW(Atom, VALUE, pos, AST_EXPR | AST_ATOM); result->type = untyped_float; result->f64_val = value; return result; } function Ast_Atom * ast_int(Token *pos, BigInt val){ AST_NEW(Atom, VALUE, pos, AST_EXPR | AST_ATOM); result->type = untyped_int; result->big_int_val = bigint_copy(pctx->perm, &val); return result; } function Ast_Atom * ast_int(Token *pos, U64 value){ return ast_int(pos, bigint_u64(value)); } function Ast_Expr * ast_expr_binary(Ast_Expr *left, Ast_Expr *right, Token *op){ AST_NEW(Binary, BINARY, op, AST_EXPR); result->op = op->kind; result->left = left; result->right = right; result->left->parent = result; if(result->right) result->right->parent = result; return result; } function Ast_Call * ast_call(Token *pos, Ast_Expr *name, Array exprs){ AST_NEW(Call, CALL, pos, AST_EXPR); result->name = name; result->exprs = exprs.tight_copy(pctx->perm); if(result->name) result->name->parent = result; For(result->exprs) it->parent = result; return result; } function Ast_Call_Item * ast_call_item(Token *pos, Ast_Expr *index, Ast_Atom *name, Ast_Expr *item){ AST_NEW(Call_Item, CALL_ITEM, pos, AST_EXPR); result->name = name; result->index = index; result->item = item; if(result->name) result->name->parent = result; if(result->index) result->index->parent = result; item->parent = result; return result; } function Ast_Expr * ast_expr_cast(Token *pos, Ast_Expr *expr, Ast_Expr *typespec){ AST_NEW(Cast, CAST, pos, AST_EXPR); result->flags = AST_EXPR; result->expr = expr; result->typespec = typespec; expr->parent = result; typespec->parent = result; return result; } function Ast_Expr * ast_expr_unary(Token *pos, Token_Kind op, Ast_Expr *expr){ AST_NEW(Unary, UNARY, pos, AST_EXPR); result->flags = AST_EXPR; result->expr = expr; result->op = op; expr->parent = result; return result; } function Ast_Expr * ast_expr_index(Token *pos, Ast_Expr *expr, Ast_Expr *index){ AST_NEW(Index, INDEX, pos, AST_EXPR); result->flags = AST_EXPR; result->expr = expr; result->index = index; expr->parent = result; index->parent = result; return result; } function Ast_Lambda * ast_lambda(Token *pos, Array params, B32 has_var_args, Ast_Expr *ret, Ast_Block *block){ AST_NEW(Lambda, LAMBDA, pos, AST_EXPR); result->flags = AST_EXPR; result->args = params.tight_copy(pctx->perm); result->block = block; result->ret = ret; result->has_var_args = has_var_args; if(!ret) result->ret = ast_ident(result->pos, intern_void); if(result->block) result->block->parent = result; result->ret->parent = result; For(result->args) it->parent = result; return result; } function Ast_Lambda_Arg * ast_expr_lambda_arg(Token *pos, Intern_String name, Ast_Expr *typespec, Ast_Expr *default_value){ AST_NEW(Lambda_Arg, LAMBDA_ARG, pos, AST_EXPR); result->flags = AST_EXPR; result->name = name; result->typespec = typespec; result->default_value = default_value; result->typespec->parent = result; if(result->default_value) result->default_value->parent = result; return result; } function Ast_Block * ast_block(Token *pos, Array stmts){ AST_NEW(Block, BLOCK, pos, AST_STMT); result->stmts = stmts.tight_copy(pctx->perm); For(result->stmts) it->parent = result; return result; } function Ast_If * ast_if(Token *pos, Array ifs){ AST_NEW(If, IF, pos, AST_STMT); result->ifs = ifs.tight_copy(pctx->perm); For(result->ifs) it->parent = result; return result; } function Ast_For * ast_for(Token *pos, Ast_Expr *init, Ast_Expr *cond, Ast_Expr *iter, Ast_Block *block){ AST_NEW(For, FOR, pos, AST_STMT); result->init = init; result->cond = cond; result->iter = iter; result->block = block; if(result->init) result->init->parent = result; if(result->cond) result->cond->parent = result; if(result->iter) result->iter->parent = result; result->block->parent = result; return result; } function Ast_Pass * ast_pass(Token *pos){ AST_NEW(Pass, PASS, pos, AST_STMT); return result; } function Ast_Return * ast_return(Token *pos, Ast_Expr *expr){ AST_NEW(Return, RETURN, pos, AST_STMT); if(expr){ assert(is_flag_set(expr->flags, AST_EXPR)); result->expr = expr; result->expr->parent = result; } return result; } function Ast_If_Node * ast_if_node(Token *pos, Ast_Expr *init, Ast_Expr *expr, Ast_Block *block){ AST_NEW(If_Node, IF_NODE, pos, AST_STMT); result->block = block; result->expr = expr; result->init = (Ast_Binary *)init; if(result->block) result->block->parent = result; if(result->expr) result->expr->parent = result; if(result->init) { assert(init->kind == AST_BINARY); result->init->parent = result; } return result; } function Ast_Array * ast_array(Token *pos, Ast_Expr *expr){ AST_NEW(Array, ARRAY, pos, AST_EXPR); result->expr = expr; if(result->expr) result->expr->parent = result; return result; } function Ast_Enum_Member * ast_enum_member(Token *pos, Intern_String name, Ast_Expr *default_value){ AST_NEW(Enum_Member, ENUM_MEMBER, pos, AST_AGGREGATE_CHILD); result->name = name; result->value = default_value; if(result->value) result->value->parent = result; return result; } function Ast_Enum * ast_enum(Token *pos, Ast_Expr *typespec, Array members){ AST_NEW(Enum, ENUM, pos, AST_AGGREGATE); result->members = members.tight_copy(pctx->perm); result->typespec = typespec; if(result->typespec) result->typespec->parent = result; For(result->members){ it->parent = result; } return result; } function Ast_Struct * ast_struct(Token *pos, Array members, Array const_members){ AST_NEW(Struct, STRUCT, pos, AST_AGGREGATE); result->members = members.tight_copy(pctx->perm); result->const_members = const_members.tight_copy(pctx->perm); For(result->members) { assert(is_flag_set(it->flags, AST_BINDING)); assert(it->kind == AST_VAR); it->parent = result; } For(result->const_members) { assert(is_flag_set(it->flags, AST_BINDING)); assert(it->kind == AST_CONST); it->parent = result; } return result; } //----------------------------------------------------------------------------- // Declarations //----------------------------------------------------------------------------- function Ast_Var * ast_var(Token *pos, Ast_Expr *typespec, Intern_String name, Ast_Expr *expr){ AST_NEW(Var, VAR, pos, AST_BINDING); result->expr = expr; result->typespec = typespec; result->name = name; if(result->expr) result->expr->parent = result; if(result->typespec) result->typespec->parent = result; return result; } function Ast_Const * ast_const(Token *pos, Intern_String name, Ast_Expr *value){ assert(is_flag_set(value->flags, AST_AGGREGATE) || is_flag_set(value->flags, AST_EXPR) ); AST_NEW(Const, CONST, pos, AST_BINDING); result->value = value; result->name = name; result->value->parent = result; return result; } function Ast_Package * ast_package(Token *pos, String name, Array decls){ AST_NEW(Package, PACKAGE, pos, 0); result->decls = decls.tight_copy(pctx->perm); result->ordered = array_make(pctx->perm, decls.len); result->name = intern_string(&pctx->interns, name); For(result->decls) it->parent = result; return result; } //----------------------------------------------------------------------------- // Value //----------------------------------------------------------------------------- function Value value_bool(B32 v){ Value value; value.bool_val = v; value.type = untyped_bool; return value; } function Value value_int(BigInt b){ Value value; value.big_int_val = b; value.type = untyped_int; return value; } function Value value_int(S64 s64){ Value value; value.type = untyped_int; bigint_init_signed(&value.big_int_val, s64); return value; } function Value value_float(F64 b){ Value value; value.f64_val = b; value.type = untyped_float; return value; } function Value value_float(BigInt a){ Value value; value.f64_val = bigint_as_float(&a); value.type = untyped_float; return value; } //----------------------------------------------------------------------------- // Utillities //----------------------------------------------------------------------------- function Ast_Struct * const_try_getting_struct(Ast *ast){ assert(ast->kind == AST_CONST); Ast_Const *constant = (Ast_Const *)ast; if(constant->value->kind == AST_STRUCT){ return (Ast_Struct *)constant->value; } return 0; } function Ast_Struct * const_get_struct(Ast *ast){ auto result = const_try_getting_struct(ast); assert(result); return result; } function Ast_Lambda * const_try_getting_lambda(Ast *ast){ assert(ast->kind == AST_CONST); Ast_Const *constant = (Ast_Const *)ast; if(constant->value->kind == AST_LAMBDA){ return (Ast_Lambda *)constant->value; } return 0; } function Ast_Lambda * const_get_lambda(Ast *ast){ auto result = const_try_getting_lambda(ast); assert(result); return result; } function Intern_String ast_get_name(Ast *ast){ assert(is_flag_set(ast->flags, AST_BINDING)); auto constant = (Ast_Named *)ast; return constant->name; } function B32 ast_is_struct(Ast *ast){ if(ast->kind == AST_CONST){ auto a = (Ast_Const *)ast; B32 result = a->agg->kind == AST_STRUCT; return result; } return false; } function B32 is_ident(Ast *ast){ B32 result = ast->kind == AST_IDENT; return result; } function B32 is_binary(Ast *ast){ B32 result = ast->kind == AST_BINARY; return result; } function B32 is_atom(Ast *ast){ B32 result = is_flag_set(ast->flags, AST_ATOM); return result; } function Ast * query_struct(Ast_Struct *agg, Intern_String string){ For(agg->members){ if(it->name == string){ return it; } } For(agg->const_members){ if(it->name == string){ return it; } } return 0; } function Ast_Enum_Member * query_enum(Ast_Enum *enu, Intern_String string){ For(enu->members){ if(it->name == string){ return it; } } return 0; }