// Lexer::interns::map::allocator - array allocator, resizing // Lexer::tokens - array allocator, resizing // // Parser::ast_arena - arena for asts // Lexer::interns::string_allocator - arena for interns // Intern_String keyword_struct; Intern_String keyword_union; Intern_String keyword_return; Intern_String keyword_if; Intern_String keyword_else; Intern_String keyword_for; Intern_String keyword_cast; Intern_String keyword_enum; Intern_String intern_void; Intern_String intern_int; Intern_String intern_str; Intern_String intern_unsigned; struct Ast_Package; struct Sym; struct Parse_Ctx:Lexer{ Allocator *perm; // Stores: AST, tokens, interns Allocator *heap; U64 unique_ids; Map type_map; Ast_Package *resolving_package; Map resolved; Map syms; S32 scope; Array local_syms; Token empty_token; S64 indent; String_Builder gen; Intern_String intern(String string){ return intern_string(&interns, string); } void init(Allocator *perm_allocator, Allocator *heap_allocator){ perm = perm_allocator; heap = heap_allocator; gen = {perm}; resolved = {heap}; syms = {heap}; type_map = {heap}; local_syms = {heap}; lex_init(perm, heap, this); keyword_struct= intern("struct"_s); keyword_union = intern("union"_s); keyword_cast = intern("cast"_s); keyword_return = intern("return"_s); keyword_if = intern("if"_s); keyword_else = intern("else"_s); keyword_for = intern("for"_s); keyword_enum = intern_string(&interns, "enum"_s); interns.first_keyword = keyword_struct.str; interns.last_keyword = keyword_enum.str; intern_void = intern_string(&interns, "void"_s); intern_int = intern_string(&interns, "int"_s); intern_str = intern_string(&interns, "String"_s); intern_unsigned = intern_string(&interns, "unsigned"_s); } }; thread_local Parse_Ctx *pctx; //----------------------------------------------------------------------------- // AST //----------------------------------------------------------------------------- enum Ast_Kind{ AST_NONE, AST_PACKAGE, AST_STR, AST_INT, AST_CAST, AST_IDENT, AST_INDEX, AST_UNARY, AST_BINARY, AST_COMPOUND_ITEM, AST_COMPOUND, AST_POINTER, AST_ARRAY, AST_INIT, AST_IF, AST_IF_NODE, AST_RETURN, AST_BLOCK, AST_LAMBDA, AST_LAMBDA_ARG, AST_CONST, AST_VAR, AST_TYPESPEC_IDENT, AST_TYPESPEC_POINTER, AST_TYPESPEC_ARRAY, AST_TYPESPEC_LAMBDA }; struct Ast{ U64 id; Token *pos; Ast_Kind kind; // @todo? // bool is_atom: 1; // bool is_stmt: 1; // bool is_expr: 1; // bool is_decl: 1; // bool is_named: 1; }; struct Ast_Resolved_Type; struct Ast_Expr:Ast{}; struct Ast_Atom: Ast_Expr{ union{ Intern_String intern_val; U64 int_val; }; }; struct Ast_Compound_Item: Ast_Expr{ Ast_Atom *name; // index | name Ast_Expr *index; Ast_Expr *item; }; struct Ast_Compound: Ast_Expr{ Ast_Resolved_Type *type; Ast_Expr *typespec; Array exprs; }; struct Ast_Unary: Ast_Expr{ Token_Kind op; Ast_Expr *expr; }; 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; }; struct Ast_Block : Ast { Array stmts; }; struct Ast_Return: Ast{ Ast_Expr *expr; }; struct Ast_Init: Ast{ Token_Kind op; Ast_Atom *ident; Ast_Expr *expr; }; struct Ast_If_Node: Ast{ Ast_Expr *expr ; Ast_Block *block; Ast_Init *init; }; struct Ast_If: Ast{ Array ifs; }; struct Ast_Lambda_Arg: Ast_Expr{ Intern_String name; Ast_Expr *typespec; }; struct Ast_Lambda : Ast_Expr { Array args; Ast_Expr *ret; Ast_Block *block; }; struct Ast_Array: Ast_Expr{ Ast_Expr *base; Ast_Expr *expr; }; struct Ast_Named:Ast{ Intern_String name; }; struct Ast_Var: Ast_Named{ Ast_Expr *typespec; Ast_Expr *expr; }; struct Ast_Const: Ast_Named{ Ast_Expr *expr; }; struct Ast_Package:Ast{ Intern_String name; Array decls; Array ordered; }; //----------------------------------------------------------------------------- // AST Constructors beginning with expressions //----------------------------------------------------------------------------- #define AST_NEW(T,ikind,ipos) \ Ast_##T *result = exp_alloc_type(pctx->perm, Ast_##T, AF_ZeroMemory);\ 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, STR, pos); result->intern_val = string; return result; } function Ast_Atom * ast_ident(Token *pos, Intern_String string){ AST_NEW(Atom, IDENT, pos); result->intern_val = string; return result; } function Ast_Atom * ast_int(Token *pos, S64 integer){ AST_NEW(Atom, INT, pos); result->int_val = integer; return result; } function Ast_Expr * ast_expr_binary(Ast_Expr *left, Ast_Expr *right, Token *op){ AST_NEW(Binary, BINARY, op); result->op = op->kind; result->left = left; result->right = right; return result; } function Ast_Compound * ast_expr_compound(Token *pos, Ast_Expr *typespec, Array exprs){ AST_NEW(Compound, COMPOUND, pos); result->typespec = typespec; result->exprs = exprs.tight_copy(pctx->perm); return result; } function Ast_Compound_Item * ast_expr_compound_item(Token *pos, Ast_Expr *index, Ast_Atom *name, Ast_Expr *item){ AST_NEW(Compound_Item, COMPOUND_ITEM, pos); result->name = name; result->index = index; result->item = item; return result; } function Ast_Expr * ast_expr_cast(Token *pos, Ast_Expr *expr, Ast_Expr *typespec){ AST_NEW(Cast, CAST, pos); result->expr = expr; result->typespec = typespec; return result; } function Ast_Expr * ast_expr_unary(Token *pos, Token_Kind op, Ast_Expr *expr){ AST_NEW(Unary, UNARY, pos); result->expr = expr; result->op = op; return result; } function Ast_Expr * ast_expr_index(Token *pos, Ast_Expr *expr, Ast_Expr *index){ AST_NEW(Index, INDEX, pos); result->expr = expr; result->index = index; return result; } function Ast_Lambda * ast_lambda(Token *pos, Array params, Ast_Expr *ret, Ast_Block *block){ AST_NEW(Lambda, LAMBDA, pos); result->args = params.tight_copy(pctx->perm); result->ret = ret; result->block = block; if(!ret){ result->ret = ast_ident(0, intern_void); } return result; } function Ast_Expr * ast_expr_lambda_empty(Token *pos){ AST_NEW(Expr, LAMBDA, pos); return result; } function Ast_Lambda_Arg * ast_expr_lambda_arg(Token *pos, Intern_String name, Ast_Expr *typespec){ AST_NEW(Lambda_Arg, LAMBDA_ARG, pos); result->name = name; result->typespec = typespec; return result; } function Ast_Block * ast_block(Token *pos, Array stmts){ AST_NEW(Block, BLOCK, pos); result->stmts = stmts.tight_copy(pctx->perm); return result; } function Ast_If * ast_if(Token *pos, Array ifs){ AST_NEW(If, IF, pos); result->ifs = ifs.tight_copy(pctx->perm); return result; } function Ast_If_Node * ast_if_node(Token *pos, Ast_Init *init, Ast_Expr *expr, Ast_Block *block){ AST_NEW(If_Node, IF_NODE, pos); result->block = block; result->expr = expr; result->init = init; return result; } function Ast_Init * ast_init(Token *pos, Token_Kind op, Ast_Atom *ident, Ast_Expr *expr){ AST_NEW(Init, INIT, pos); result->op = op; result->ident = ident; result->expr = expr; return result; } function Ast_Array * ast_array(Token *pos, Ast_Expr *base){ AST_NEW(Array, ARRAY, pos); result->base = base; return result; } //----------------------------------------------------------------------------- // Declarations //----------------------------------------------------------------------------- function Ast_Var * ast_var(Token *pos, Ast_Expr *typespec, Intern_String name, Ast_Expr *expr){ AST_NEW(Var, VAR, pos); result->expr = expr; result->typespec = typespec; result->name = name; return result; } function Ast_Const * ast_const(Token *pos, Intern_String name, Ast_Expr *expr){ AST_NEW(Const, CONST, pos); result->expr = expr; result->name = name; return result; } function Ast_Package * ast_package(Token *pos, String name, Array decls){ AST_NEW(Package, PACKAGE, pos); result->decls = decls.tight_copy(pctx->perm); result->ordered = array_make(pctx->perm, decls.len); result->name = intern_string(&pctx->interns, name); return result; }