diff --git a/src/all_types.hpp b/src/all_types.hpp new file mode 100644 index 0000000000..70ab294d1a --- /dev/null +++ b/src/all_types.hpp @@ -0,0 +1,928 @@ +/* + * Copyright (c) 2015 Andrew Kelley + * + * This file is part of zig, which is MIT licensed. + * See http://opensource.org/licenses/MIT + */ + +#ifndef ZIG_ALL_TYPES_HPP +#define ZIG_ALL_TYPES_HPP + +#include "list.hpp" +#include "buffer.hpp" +#include "zig_llvm.hpp" +#include "hash_map.hpp" +#include "errmsg.hpp" + +struct AstNode; +struct ImportTableEntry; +struct AsmToken; +struct FnTableEntry; +struct BlockContext; +struct TypeTableEntry; +struct VariableTableEntry; +struct Cast; +struct BuiltinFnEntry; +struct LabelTableEntry; +struct TypeStructField; +struct CodeGen; + +enum OutType { + OutTypeUnknown, + OutTypeExe, + OutTypeLib, + OutTypeObj, +}; + +enum CodeGenBuildType { + CodeGenBuildTypeDebug, + CodeGenBuildTypeRelease, +}; + +enum CastOp { + CastOpNothing, + CastOpPtrToInt, + CastOpIntWidenOrShorten, + CastOpToUnknownSizeArray, + CastOpMaybeWrap, + CastOpPointerReinterpret, +}; + +struct Cast { + CastOp op; + // if op is CastOpArrayToString, this will be a pointer to + // the string struct on the stack + LLVMValueRef ptr; + TypeTableEntry *after_type; + AstNode *source_node; +}; + +struct Expr { + TypeTableEntry *type_entry; + // the context in which this expression is evaluated. + // for blocks, this points to the containing scope, not the block's own scope for its children. + BlockContext *block_context; + + // may be null for no cast + Cast implicit_cast; // happens first + Cast implicit_maybe_cast; // happens second +}; + +struct NumLitCodeGen { + TypeTableEntry *resolved_type; +}; + +struct StructValExprCodeGen { + TypeTableEntry *type_entry; + LLVMValueRef ptr; + AstNode *source_node; +}; + +struct TopLevelDecl { + // reminder: hash tables must be initialized before use + HashMap deps; + Buf *name; + ImportTableEntry *import; + // set this flag temporarily to detect infinite loops + bool in_current_deps; +}; + +enum NodeType { + NodeTypeRoot, + NodeTypeRootExportDecl, + NodeTypeFnProto, + NodeTypeFnDef, + NodeTypeFnDecl, + NodeTypeParamDecl, + NodeTypeType, + NodeTypeBlock, + NodeTypeExternBlock, + NodeTypeDirective, + NodeTypeReturnExpr, + NodeTypeVariableDeclaration, + NodeTypeBinOpExpr, + NodeTypeCastExpr, + NodeTypeNumberLiteral, + NodeTypeStringLiteral, + NodeTypeCharLiteral, + NodeTypeUnreachable, + NodeTypeSymbol, + NodeTypePrefixOpExpr, + NodeTypeFnCallExpr, + NodeTypeArrayAccessExpr, + NodeTypeSliceExpr, + NodeTypeFieldAccessExpr, + NodeTypeUse, + NodeTypeVoid, + NodeTypeBoolLiteral, + NodeTypeNullLiteral, + NodeTypeIfBoolExpr, + NodeTypeIfVarExpr, + NodeTypeWhileExpr, + NodeTypeLabel, + NodeTypeGoto, + NodeTypeBreak, + NodeTypeContinue, + NodeTypeAsmExpr, + NodeTypeStructDecl, + NodeTypeStructField, + NodeTypeStructValueExpr, + NodeTypeStructValueField, + NodeTypeEnumDecl, + NodeTypeEnumField, + NodeTypeCompilerFnExpr, + NodeTypeCompilerFnType, +}; + +struct AstNodeRoot { + ZigList top_level_decls; +}; + +enum VisibMod { + VisibModPrivate, + VisibModPub, + VisibModExport, +}; + +struct AstNodeFnProto { + ZigList *directives; + VisibMod visib_mod; + Buf name; + ZigList params; + AstNode *return_type; + bool is_var_args; + + // populated by semantic analyzer: + + // the extern block this fn proto is inside. can be null. + AstNode *extern_node; + // the struct decl node this fn proto is inside. can be null. + AstNode *struct_node; + // the function definition this fn proto is inside. can be null. + AstNode *fn_def_node; + FnTableEntry *fn_table_entry; + bool skip; + TopLevelDecl top_level_decl; +}; + +struct AstNodeFnDef { + AstNode *fn_proto; + AstNode *body; + + // populated by semantic analyzer + TypeTableEntry *implicit_return_type; + BlockContext *block_context; +}; + +struct AstNodeFnDecl { + AstNode *fn_proto; +}; + +struct AstNodeParamDecl { + Buf name; + AstNode *type; + + // populated by semantic analyzer + VariableTableEntry *variable; +}; + +enum AstNodeTypeType { + AstNodeTypeTypePrimitive, + AstNodeTypeTypePointer, + AstNodeTypeTypeArray, + AstNodeTypeTypeMaybe, + AstNodeTypeTypeCompilerExpr, +}; + +struct AstNodeType { + AstNodeTypeType type; + Buf primitive_name; + AstNode *child_type; + AstNode *array_size; // can be null + bool is_const; + bool is_noalias; + AstNode *compiler_expr; + + // populated by semantic analyzer + TypeTableEntry *entry; +}; + +struct AstNodeBlock { + ZigList statements; + + // populated by semantic analyzer + BlockContext *block_context; + Expr resolved_expr; +}; + +struct AstNodeReturnExpr { + // might be null in case of return void; + AstNode *expr; + + // populated by semantic analyzer: + Expr resolved_expr; +}; + +struct AstNodeVariableDeclaration { + Buf symbol; + bool is_const; + VisibMod visib_mod; + // one or both of type and expr will be non null + AstNode *type; + AstNode *expr; + + // populated by semantic analyzer + TopLevelDecl top_level_decl; + Expr resolved_expr; +}; + +enum BinOpType { + BinOpTypeInvalid, + BinOpTypeAssign, + BinOpTypeAssignTimes, + BinOpTypeAssignDiv, + BinOpTypeAssignMod, + BinOpTypeAssignPlus, + BinOpTypeAssignMinus, + BinOpTypeAssignBitShiftLeft, + BinOpTypeAssignBitShiftRight, + BinOpTypeAssignBitAnd, + BinOpTypeAssignBitXor, + BinOpTypeAssignBitOr, + BinOpTypeAssignBoolAnd, + BinOpTypeAssignBoolOr, + BinOpTypeBoolOr, + BinOpTypeBoolAnd, + BinOpTypeCmpEq, + BinOpTypeCmpNotEq, + BinOpTypeCmpLessThan, + BinOpTypeCmpGreaterThan, + BinOpTypeCmpLessOrEq, + BinOpTypeCmpGreaterOrEq, + BinOpTypeBinOr, + BinOpTypeBinXor, + BinOpTypeBinAnd, + BinOpTypeBitShiftLeft, + BinOpTypeBitShiftRight, + BinOpTypeAdd, + BinOpTypeSub, + BinOpTypeMult, + BinOpTypeDiv, + BinOpTypeMod, + BinOpTypeUnwrapMaybe, +}; + +struct AstNodeBinOpExpr { + AstNode *op1; + BinOpType bin_op; + AstNode *op2; + + // populated by semantic analyzer: + // for when op is BinOpTypeAssign + VariableTableEntry *var_entry; + Expr resolved_expr; +}; + +struct AstNodeFnCallExpr { + AstNode *fn_ref_expr; + ZigList params; + bool is_builtin; + + // populated by semantic analyzer: + BuiltinFnEntry *builtin_fn; + Expr resolved_expr; +}; + +struct AstNodeArrayAccessExpr { + AstNode *array_ref_expr; + AstNode *subscript; + + // populated by semantic analyzer: + Expr resolved_expr; +}; + +struct AstNodeSliceExpr { + AstNode *array_ref_expr; + AstNode *start; + AstNode *end; + bool is_const; + + // populated by semantic analyzer: + Expr resolved_expr; + StructValExprCodeGen resolved_struct_val_expr; +}; + +struct AstNodeFieldAccessExpr { + AstNode *struct_expr; + Buf field_name; + + // populated by semantic analyzer + int field_index; + TypeStructField *type_struct_field; + Expr resolved_expr; +}; + +struct AstNodeExternBlock { + ZigList *directives; + ZigList fn_decls; +}; + +struct AstNodeDirective { + Buf name; + Buf param; +}; + +struct AstNodeRootExportDecl { + Buf type; + Buf name; + ZigList *directives; +}; + +struct AstNodeCastExpr { + AstNode *expr; + AstNode *type; + + // populated by semantic analyzer + Cast cast; + Expr resolved_expr; +}; + +enum PrefixOp { + PrefixOpInvalid, + PrefixOpBoolNot, + PrefixOpBinNot, + PrefixOpNegation, + PrefixOpAddressOf, + PrefixOpConstAddressOf, + PrefixOpDereference, +}; + +struct AstNodePrefixOpExpr { + PrefixOp prefix_op; + AstNode *primary_expr; + + // populated by semantic analyzer + Expr resolved_expr; +}; + +struct AstNodeUse { + Buf path; + ZigList *directives; + + // populated by semantic analyzer + ImportTableEntry *import; +}; + +struct AstNodeIfBoolExpr { + AstNode *condition; + AstNode *then_block; + AstNode *else_node; // null, block node, or other if expr node + + // populated by semantic analyzer + Expr resolved_expr; +}; + +struct AstNodeIfVarExpr { + AstNodeVariableDeclaration var_decl; + AstNode *then_block; + AstNode *else_node; // null, block node, or other if expr node + + // populated by semantic analyzer + TypeTableEntry *type; + BlockContext *block_context; + Expr resolved_expr; +}; + +struct AstNodeWhileExpr { + AstNode *condition; + AstNode *body; + + // populated by semantic analyzer + bool condition_always_true; + bool contains_break; + Expr resolved_expr; +}; + +struct AstNodeLabel { + Buf name; + + // populated by semantic analyzer + LabelTableEntry *label_entry; + Expr resolved_expr; +}; + +struct AstNodeGoto { + Buf name; + + // populated by semantic analyzer + LabelTableEntry *label_entry; + Expr resolved_expr; +}; + +struct AsmOutput { + Buf asm_symbolic_name; + Buf constraint; + Buf variable_name; + AstNode *return_type; // null unless "=r" and return +}; + +struct AsmInput { + Buf asm_symbolic_name; + Buf constraint; + AstNode *expr; +}; + +struct SrcPos { + int line; + int column; +}; + +struct AstNodeAsmExpr { + bool is_volatile; + Buf asm_template; + ZigList offset_map; + ZigList token_list; + ZigList output_list; + ZigList input_list; + ZigList clobber_list; + + // populated by semantic analyzer + int return_count; + Expr resolved_expr; +}; + +struct AstNodeStructDecl { + Buf name; + ZigList fields; + ZigList fns; + ZigList *directives; + VisibMod visib_mod; + + // populated by semantic analyzer + TypeTableEntry *type_entry; + TopLevelDecl top_level_decl; +}; + +struct AstNodeStructField { + Buf name; + AstNode *type; + ZigList *directives; +}; + +struct AstNodeEnumDecl { + Buf name; + ZigList fields; + ZigList *directives; + VisibMod visib_mod; +}; + +struct AstNodeEnumField { + Buf name; + ZigList fields; // length 0 means simple enum + AstNode *val_expr; +}; + +struct AstNodeStringLiteral { + Buf buf; + bool c; + + // populated by semantic analyzer: + Expr resolved_expr; +}; + +struct AstNodeCharLiteral { + uint8_t value; + + // populated by semantic analyzer: + Expr resolved_expr; +}; + +enum NumLit { + NumLitF32, + NumLitF64, + NumLitF128, + NumLitU8, + NumLitU16, + NumLitU32, + NumLitU64, + NumLitI8, + NumLitI16, + NumLitI32, + NumLitI64, + + NumLitCount +}; + +struct AstNodeNumberLiteral { + NumLit kind; + + // overflow is true if when parsing the number, we discovered it would not + // fit without losing data in a uint64_t, int64_t, or double + bool overflow; + + union { + uint64_t x_uint; + int64_t x_int; + double x_float; + } data; + + // populated by semantic analyzer + NumLitCodeGen codegen; + Expr resolved_expr; +}; + +struct AstNodeStructValueField { + Buf name; + AstNode *expr; + + // populated by semantic analyzer + int index; +}; + +struct AstNodeStructValueExpr { + AstNode *type; + ZigList fields; + + // populated by semantic analyzer + StructValExprCodeGen codegen; + Expr resolved_expr; +}; + +struct AstNodeCompilerFnExpr { + Buf name; + AstNode *expr; + + // populated by semantic analyzer + Expr resolved_expr; +}; + +struct AstNodeCompilerFnType { + Buf name; + AstNode *type; + + // populated by semantic analyzer + Expr resolved_expr; + NumLitCodeGen resolved_num_lit; +}; + +struct AstNodeNullLiteral { + // populated by semantic analyzer + StructValExprCodeGen resolved_struct_val_expr; + Expr resolved_expr; +}; + +struct AstNodeVoidExpr { + // populated by semantic analyzer + Expr resolved_expr; +}; + +struct AstNodeUnreachableExpr { + // populated by semantic analyzer + Expr resolved_expr; +}; + +struct AstNodeSymbolExpr { + Buf symbol; + + // populated by semantic analyzer + Expr resolved_expr; +}; + +struct AstNodeBoolLiteral { + bool value; + + // populated by semantic analyzer + Expr resolved_expr; +}; + +struct AstNodeBreakExpr { + // populated by semantic analyzer + Expr resolved_expr; +}; + +struct AstNodeContinueExpr { + // populated by semantic analyzer + Expr resolved_expr; +}; + +struct AstNode { + enum NodeType type; + int line; + int column; + uint32_t create_index; // for determinism purposes + ImportTableEntry *owner; + union { + AstNodeRoot root; + AstNodeRootExportDecl root_export_decl; + AstNodeFnDef fn_def; + AstNodeFnDecl fn_decl; + AstNodeFnProto fn_proto; + AstNodeType type; + AstNodeParamDecl param_decl; + AstNodeBlock block; + AstNodeReturnExpr return_expr; + AstNodeVariableDeclaration variable_declaration; + AstNodeBinOpExpr bin_op_expr; + AstNodeExternBlock extern_block; + AstNodeDirective directive; + AstNodeCastExpr cast_expr; + AstNodePrefixOpExpr prefix_op_expr; + AstNodeFnCallExpr fn_call_expr; + AstNodeArrayAccessExpr array_access_expr; + AstNodeSliceExpr slice_expr; + AstNodeUse use; + AstNodeIfBoolExpr if_bool_expr; + AstNodeIfVarExpr if_var_expr; + AstNodeWhileExpr while_expr; + AstNodeLabel label; + AstNodeGoto goto_expr; + AstNodeAsmExpr asm_expr; + AstNodeFieldAccessExpr field_access_expr; + AstNodeStructDecl struct_decl; + AstNodeStructField struct_field; + AstNodeEnumDecl enum_decl; + AstNodeEnumField enum_field; + AstNodeStringLiteral string_literal; + AstNodeCharLiteral char_literal; + AstNodeNumberLiteral number_literal; + AstNodeStructValueExpr struct_val_expr; + AstNodeStructValueField struct_val_field; + AstNodeCompilerFnExpr compiler_fn_expr; + AstNodeCompilerFnType compiler_fn_type; + AstNodeNullLiteral null_literal; + AstNodeVoidExpr void_expr; + AstNodeUnreachableExpr unreachable_expr; + AstNodeSymbolExpr symbol_expr; + AstNodeBoolLiteral bool_literal; + AstNodeBreakExpr break_expr; + AstNodeContinueExpr continue_expr; + } data; +}; + +enum AsmTokenId { + AsmTokenIdTemplate, + AsmTokenIdPercent, + AsmTokenIdVar, +}; + +struct AsmToken { + enum AsmTokenId id; + int start; + int end; +}; + +struct TypeTableEntryPointer { + TypeTableEntry *child_type; + bool is_const; + bool is_noalias; +}; + +struct TypeTableEntryInt { + bool is_signed; +}; + +struct TypeTableEntryArray { + TypeTableEntry *child_type; + uint64_t len; +}; + +struct TypeStructField { + Buf *name; + TypeTableEntry *type_entry; +}; + +struct TypeTableEntryStruct { + AstNode *decl_node; + bool is_packed; + int field_count; + TypeStructField *fields; + uint64_t size_bytes; + bool is_invalid; // true if any fields are invalid + bool is_unknown_size_array; + // reminder: hash tables must be initialized before use + HashMap fn_table; + + // set this flag temporarily to detect infinite loops + bool embedded_in_current; + bool reported_infinite_err; +}; + +struct TypeTableEntryNumLit { + NumLit kind; +}; + +struct TypeTableEntryMaybe { + TypeTableEntry *child_type; +}; + +enum TypeTableEntryId { + TypeTableEntryIdInvalid, + TypeTableEntryIdVoid, + TypeTableEntryIdBool, + TypeTableEntryIdUnreachable, + TypeTableEntryIdInt, + TypeTableEntryIdFloat, + TypeTableEntryIdPointer, + TypeTableEntryIdArray, + TypeTableEntryIdStruct, + TypeTableEntryIdNumberLiteral, + TypeTableEntryIdMaybe, +}; + +struct TypeTableEntry { + TypeTableEntryId id; + + LLVMTypeRef type_ref; + LLVMZigDIType *di_type; + uint64_t size_in_bits; + uint64_t align_in_bits; + + Buf name; + + union { + TypeTableEntryPointer pointer; + TypeTableEntryInt integral; + TypeTableEntryArray array; + TypeTableEntryStruct structure; + TypeTableEntryNumLit num_lit; + TypeTableEntryMaybe maybe; + } data; + + // use these fields to make sure we don't duplicate type table entries for the same type + TypeTableEntry *pointer_parent[2][2]; // 0 - const. 1 - noalias + TypeTableEntry *unknown_size_array_parent[2][2]; // 0 - const. 1 - noalias + HashMap arrays_by_size; + TypeTableEntry *maybe_parent; + +}; + +struct ImporterInfo { + ImportTableEntry *import; + AstNode *source_node; +}; + +struct ImportTableEntry { + AstNode *root; + Buf *path; // relative to root_source_dir + LLVMZigDIFile *di_file; + Buf *source_code; + ZigList *line_offsets; + BlockContext *block_context; + ZigList importers; + + // reminder: hash tables must be initialized before use + HashMap fn_table; + HashMap type_table; +}; + +struct LabelTableEntry { + AstNode *label_node; + LLVMBasicBlockRef basic_block; + bool used; + bool entered_from_fallthrough; +}; + +enum FnAttrId { + FnAttrIdNaked, + FnAttrIdAlwaysInline, +}; + +struct FnTableEntry { + LLVMValueRef fn_value; + AstNode *proto_node; + AstNode *fn_def_node; + bool is_extern; + bool internal_linkage; + unsigned calling_convention; + ImportTableEntry *import_entry; + ZigList fn_attr_list; + // Required to be a pre-order traversal of the AST. (parents must come before children) + ZigList all_block_contexts; + TypeTableEntry *member_of_struct; + Buf symbol_name; + + // reminder: hash tables must be initialized before use + HashMap label_table; +}; + +enum BuiltinFnId { + BuiltinFnIdInvalid, + BuiltinFnIdArithmeticWithOverflow, + BuiltinFnIdMemcpy, + BuiltinFnIdMemset, +}; + +struct BuiltinFnEntry { + BuiltinFnId id; + Buf name; + int param_count; + TypeTableEntry *return_type; + TypeTableEntry **param_types; + LLVMValueRef fn_val; +}; + +struct CodeGen { + LLVMModuleRef module; + ZigList errors; + LLVMBuilderRef builder; + LLVMZigDIBuilder *dbuilder; + LLVMZigDICompileUnit *compile_unit; + + ZigList lib_search_paths; + + // reminder: hash tables must be initialized before use + HashMap str_table; + HashMap link_table; + HashMap import_table; + HashMap builtin_fn_table; + HashMap primitive_type_table; + HashMap unresolved_top_level_decls; + + uint32_t next_unresolved_index; + + struct { + TypeTableEntry *entry_bool; + TypeTableEntry *entry_u8; + TypeTableEntry *entry_u16; + TypeTableEntry *entry_u32; + TypeTableEntry *entry_u64; + TypeTableEntry *entry_i8; + TypeTableEntry *entry_i16; + TypeTableEntry *entry_i32; + TypeTableEntry *entry_i64; + TypeTableEntry *entry_isize; + TypeTableEntry *entry_usize; + TypeTableEntry *entry_f32; + TypeTableEntry *entry_f64; + TypeTableEntry *entry_c_string_literal; + TypeTableEntry *entry_void; + TypeTableEntry *entry_unreachable; + TypeTableEntry *entry_invalid; + } builtin_types; + + TypeTableEntry *num_lit_types[NumLitCount]; + + LLVMTargetDataRef target_data_ref; + unsigned pointer_size_bytes; + bool is_static; + bool strip_debug_symbols; + bool have_exported_main; + bool link_libc; + Buf *libc_path; + CodeGenBuildType build_type; + LLVMTargetMachineRef target_machine; + LLVMZigDIFile *dummy_di_file; + bool is_native_target; + Buf *root_source_dir; + Buf *root_out_name; + + // The function definitions this module includes. There must be a corresponding + // fn_protos entry. + ZigList fn_defs; + // The function prototypes this module includes. In the case of external declarations, + // there will not be a corresponding fn_defs entry. + ZigList fn_protos; + ZigList global_vars; + + OutType out_type; + FnTableEntry *cur_fn; + BlockContext *cur_block_context; + ZigList break_block_stack; + ZigList continue_block_stack; + bool c_stdint_used; + AstNode *root_export_decl; + int version_major; + int version_minor; + int version_patch; + bool verbose; + ErrColor err_color; + ImportTableEntry *root_import; + ImportTableEntry *bootstrap_import; + LLVMValueRef memcpy_fn_val; + bool error_during_imports; +}; + +struct VariableTableEntry { + Buf name; + TypeTableEntry *type; + LLVMValueRef value_ref; + bool is_const; + bool is_ptr; // if true, value_ref is a pointer + AstNode *decl_node; + LLVMZigDILocalVariable *di_loc_var; + int arg_index; +}; + +struct BlockContext { + AstNode *node; // either NodeTypeFnDef or NodeTypeBlock or NodeTypeRoot + FnTableEntry *fn_entry; // null at the module scope + BlockContext *parent; // null when this is the root + HashMap variable_table; + ZigList cast_expr_alloca_list; + ZigList struct_val_expr_alloca_list; + AstNode *parent_loop_node; + AstNode *next_child_parent_loop_node; + LLVMZigDIScope *di_scope; +}; + +#endif diff --git a/src/analyze.cpp b/src/analyze.cpp index be5d9b035c..47e67e480f 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -6,6 +6,7 @@ */ #include "analyze.hpp" +#include "parser.hpp" #include "error.hpp" #include "zig_llvm.hpp" #include "os.hpp" @@ -14,7 +15,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, TypeTableEntry *expected_type, AstNode *node); static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context, AstNode *node, AstNodeNumberLiteral *out_number_literal); -static void collect_type_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *type_node, DeclNode *decl_node); +static void collect_type_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *type_node, TopLevelDecl *decl_node); static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import, BlockContext *context, TypeTableEntry *expected_type, AstNode *node); @@ -317,7 +318,7 @@ static TypeTableEntry *eval_const_expr_bin_op(CodeGen *g, BlockContext *context, out_number_literal->kind = NumLitU8; out_number_literal->overflow = false; out_number_literal->data.x_uint = (op1_lit.data.x_uint != op2_lit.data.x_uint); - return node->codegen_node->expr_node.type_entry; + return get_resolved_expr(node)->type_entry; } else { return g->builtin_types.entry_invalid; } @@ -330,7 +331,7 @@ static TypeTableEntry *eval_const_expr_bin_op(CodeGen *g, BlockContext *context, out_number_literal->kind = NumLitU8; out_number_literal->overflow = false; out_number_literal->data.x_uint = (op1_lit.data.x_uint < op2_lit.data.x_uint); - return node->codegen_node->expr_node.type_entry; + return get_resolved_expr(node)->type_entry; } else { return g->builtin_types.entry_invalid; } @@ -343,7 +344,7 @@ static TypeTableEntry *eval_const_expr_bin_op(CodeGen *g, BlockContext *context, out_number_literal->kind = NumLitU64; out_number_literal->overflow = false; out_number_literal->data.x_uint = (op1_lit.data.x_uint % op2_lit.data.x_uint); - return node->codegen_node->expr_node.type_entry; + return get_resolved_expr(node)->type_entry; } else { return g->builtin_types.entry_invalid; } @@ -390,20 +391,20 @@ static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context, switch (node->type) { case NodeTypeNumberLiteral: *out_number_literal = node->data.number_literal; - return node->codegen_node->expr_node.type_entry; + return get_resolved_expr(node)->type_entry; case NodeTypeBoolLiteral: - out_number_literal->data.x_uint = node->data.bool_literal ? 1 : 0; - return node->codegen_node->expr_node.type_entry; + out_number_literal->data.x_uint = node->data.bool_literal.value ? 1 : 0; + return get_resolved_expr(node)->type_entry; case NodeTypeNullLiteral: - return node->codegen_node->expr_node.type_entry; + return get_resolved_expr(node)->type_entry; case NodeTypeBinOpExpr: return eval_const_expr_bin_op(g, context, node, out_number_literal); case NodeTypeCompilerFnType: { Buf *name = &node->data.compiler_fn_type.name; - TypeTableEntry *expr_type = node->codegen_node->expr_node.type_entry; + TypeTableEntry *expr_type = get_resolved_expr(node)->type_entry; if (buf_eql_str(name, "sizeof")) { - TypeTableEntry *target_type = node->data.compiler_fn_type.type->codegen_node->data.type_node.entry; + TypeTableEntry *target_type = node->data.compiler_fn_type.type->data.type.entry; out_number_literal->overflow = false; out_number_literal->data.x_uint = target_type->size_in_bits / 8; out_number_literal->kind = get_number_literal_kind_unsigned(out_number_literal->data.x_uint); @@ -420,11 +421,11 @@ static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context, } case NodeTypeSymbol: { - VariableTableEntry *var = find_variable(context, &node->data.symbol); + VariableTableEntry *var = find_variable(context, &node->data.symbol_expr.symbol); assert(var); AstNode *decl_node = var->decl_node; AstNode *expr_node = decl_node->data.variable_declaration.expr; - BlockContext *next_context = expr_node->codegen_node->expr_node.block_context; + BlockContext *next_context = get_resolved_expr(expr_node)->block_context; return eval_const_expr(g, next_context, expr_node, out_number_literal); } default: @@ -436,8 +437,6 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry BlockContext *context, bool noalias_allowed) { assert(node->type == NodeTypeType); - alloc_codegen_node(node); - TypeNode *type_node = &node->codegen_node->data.type_node; switch (node->data.type.type) { case AstNodeTypeTypePrimitive: { @@ -447,13 +446,13 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry table_entry = g->primitive_type_table.maybe_get(name); } if (table_entry) { - type_node->entry = table_entry->value; + node->data.type.entry = table_entry->value; } else { add_node_error(g, node, buf_sprintf("invalid type name: '%s'", buf_ptr(name))); - type_node->entry = g->builtin_types.entry_invalid; + node->data.type.entry = g->builtin_types.entry_invalid; } - return type_node->entry; + return node->data.type.entry; } case AstNodeTypeTypePointer: { @@ -468,19 +467,19 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry } resolve_type(g, node->data.type.child_type, import, context, false); - TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry; + TypeTableEntry *child_type = node->data.type.child_type->data.type.entry; assert(child_type); if (child_type->id == TypeTableEntryIdUnreachable) { add_node_error(g, node, buf_create_from_str("pointer to unreachable not allowed")); - type_node->entry = g->builtin_types.entry_invalid; - return type_node->entry; + node->data.type.entry = g->builtin_types.entry_invalid; + return node->data.type.entry; } else if (child_type->id == TypeTableEntryIdInvalid) { - type_node->entry = child_type; + node->data.type.entry = child_type; return child_type; } else { - type_node->entry = get_pointer_to_type(g, child_type, node->data.type.is_const, use_noalias); - return type_node->entry; + node->data.type.entry = get_pointer_to_type(g, child_type, node->data.type.is_const, use_noalias); + return node->data.type.entry; } } case AstNodeTypeTypeArray: @@ -501,16 +500,16 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry if (child_type->id == TypeTableEntryIdUnreachable) { add_node_error(g, node, buf_create_from_str("array of unreachable not allowed")); - type_node->entry = g->builtin_types.entry_invalid; - return type_node->entry; + node->data.type.entry = g->builtin_types.entry_invalid; + return node->data.type.entry; } if (size_node) { TypeTableEntry *size_type = analyze_expression(g, import, context, g->builtin_types.entry_usize, size_node); if (size_type->id == TypeTableEntryIdInvalid) { - type_node->entry = g->builtin_types.entry_invalid; - return type_node->entry; + node->data.type.entry = g->builtin_types.entry_invalid; + return node->data.type.entry; } AstNodeNumberLiteral number_literal; @@ -520,27 +519,27 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry if (resolved_type->data.integral.is_signed) { add_node_error(g, size_node, buf_create_from_str("array size must be unsigned integer")); - type_node->entry = g->builtin_types.entry_invalid; + node->data.type.entry = g->builtin_types.entry_invalid; } else { - type_node->entry = get_array_type(g, import, child_type, number_literal.data.x_uint); + node->data.type.entry = get_array_type(g, import, child_type, number_literal.data.x_uint); } } else { add_node_error(g, size_node, buf_create_from_str("unable to resolve constant expression")); - type_node->entry = g->builtin_types.entry_invalid; + node->data.type.entry = g->builtin_types.entry_invalid; } - return type_node->entry; + return node->data.type.entry; } else { - type_node->entry = get_unknown_size_array_type(g, import, child_type, + node->data.type.entry = get_unknown_size_array_type(g, import, child_type, node->data.type.is_const, use_noalias); - return type_node->entry; + return node->data.type.entry; } } case AstNodeTypeTypeMaybe: { resolve_type(g, node->data.type.child_type, import, context, false); - TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry; + TypeTableEntry *child_type = node->data.type.child_type->data.type.entry; assert(child_type); if (child_type->id == TypeTableEntryIdUnreachable) { add_node_error(g, node, @@ -548,22 +547,22 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry } else if (child_type->id == TypeTableEntryIdInvalid) { return child_type; } - type_node->entry = get_maybe_type(g, import, child_type); - return type_node->entry; + node->data.type.entry = get_maybe_type(g, import, child_type); + return node->data.type.entry; } case AstNodeTypeTypeCompilerExpr: { AstNode *compiler_expr_node = node->data.type.compiler_expr; Buf *fn_name = &compiler_expr_node->data.compiler_fn_expr.name; if (buf_eql_str(fn_name, "typeof")) { - type_node->entry = analyze_expression(g, import, context, nullptr, + node->data.type.entry = analyze_expression(g, import, context, nullptr, compiler_expr_node->data.compiler_fn_expr.expr); } else { add_node_error(g, node, buf_sprintf("invalid compiler function: '%s'", buf_ptr(fn_name))); - type_node->entry = g->builtin_types.entry_invalid; + node->data.type.entry = g->builtin_types.entry_invalid; } - return type_node->entry; + return node->data.type.entry; } } zig_unreachable(); @@ -631,8 +630,7 @@ static void preview_function_labels(CodeGen *g, AstNode *node, FnTableEntry *fn_ Buf *name = &label_node->data.label.name; fn_table_entry->label_table.put(name, label_entry); - alloc_codegen_node(label_node); - label_node->codegen_node->data.label_entry = label_entry; + label_node->data.label.label_entry = label_entry; } } @@ -732,7 +730,8 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import, AstNode *struct_node = proto_node->data.fn_proto.struct_node; TypeTableEntry *struct_type; if (struct_node) { - struct_type = struct_node->codegen_node->data.struct_decl_node.type_entry; + assert(struct_node->type == NodeTypeStructDecl); + struct_type = struct_node->data.struct_decl.type_entry; } else { struct_type = nullptr; } @@ -749,13 +748,14 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import, if (entry) { add_node_error(g, proto_node, buf_sprintf("redefinition of '%s'", buf_ptr(proto_name))); - proto_node->codegen_node->data.fn_proto_node.skip = true; + proto_node->data.fn_proto.skip = true; skip = true; } else if (is_pub) { + // TODO is this else if branch a mistake? auto entry = fn_table->maybe_get(proto_name); if (entry) { add_node_error(g, proto_node, buf_sprintf("redefinition of '%s'", buf_ptr(proto_name))); - proto_node->codegen_node->data.fn_proto_node.skip = true; + proto_node->data.fn_proto.skip = true; skip = true; } } @@ -804,7 +804,7 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import, resolve_function_proto(g, proto_node, fn_table_entry, import); - proto_node->codegen_node->data.fn_proto_node.fn_table_entry = fn_table_entry; + proto_node->data.fn_proto.fn_table_entry = fn_table_entry; if (fn_def_node) { preview_function_labels(g, fn_def_node->data.fn_def.body, fn_table_entry); @@ -888,8 +888,7 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode break; case NodeTypeStructDecl: { - StructDeclNode *struct_codegen = &node->codegen_node->data.struct_decl_node; - TypeTableEntry *type_entry = struct_codegen->type_entry; + TypeTableEntry *type_entry = node->data.struct_decl.type_entry; resolve_struct_type(g, import, type_entry); @@ -962,8 +961,8 @@ static TypeTableEntry *get_return_type(BlockContext *context) { AstNode *fn_proto_node = fn_entry->proto_node; assert(fn_proto_node->type == NodeTypeFnProto); AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type; - assert(return_type_node->codegen_node); - return return_type_node->codegen_node->data.type_node.entry; + assert(return_type_node->type == NodeTypeType); + return return_type_node->data.type.entry; } static bool num_lit_fits_in_other_type(CodeGen *g, TypeTableEntry *literal_type, TypeTableEntry *other_type) { @@ -1003,15 +1002,14 @@ static bool num_lit_fits_in_other_type(CodeGen *g, TypeTableEntry *literal_type, zig_unreachable(); } -static TypeTableEntry * resolve_rhs_number_literal(CodeGen *g, AstNode *non_literal_node, +static TypeTableEntry *resolve_rhs_number_literal(CodeGen *g, AstNode *non_literal_node, TypeTableEntry *non_literal_type, AstNode *literal_node, TypeTableEntry *literal_type) { - assert(literal_node->codegen_node); - NumberLiteralNode *codegen_num_lit = &literal_node->codegen_node->data.num_lit_node; + NumLitCodeGen *num_lit_codegen = get_resolved_num_lit(literal_node); if (non_literal_type && num_lit_fits_in_other_type(g, literal_type, non_literal_type)) { - assert(!codegen_num_lit->resolved_type); - codegen_num_lit->resolved_type = non_literal_type; + assert(!num_lit_codegen->resolved_type); + num_lit_codegen->resolved_type = non_literal_type; return non_literal_type; } else { return nullptr; @@ -1024,11 +1022,8 @@ static TypeTableEntry * resolve_number_literals(CodeGen *g, AstNode *node1, AstN if (type1->id == TypeTableEntryIdNumberLiteral && type2->id == TypeTableEntryIdNumberLiteral) { - assert(node1->codegen_node); - assert(node2->codegen_node); - - NumberLiteralNode *codegen_num_lit_1 = &node1->codegen_node->data.num_lit_node; - NumberLiteralNode *codegen_num_lit_2 = &node2->codegen_node->data.num_lit_node; + NumLitCodeGen *codegen_num_lit_1 = get_resolved_num_lit(node1); + NumLitCodeGen *codegen_num_lit_2 = get_resolved_num_lit(node2); assert(!codegen_num_lit_1->resolved_type); assert(!codegen_num_lit_2->resolved_type); @@ -1113,9 +1108,10 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont if (actual_type->id == TypeTableEntryIdNumberLiteral && num_lit_fits_in_other_type(g, actual_type, expected_type)) { - assert(!node->codegen_node->data.num_lit_node.resolved_type || - node->codegen_node->data.num_lit_node.resolved_type == expected_type); - node->codegen_node->data.num_lit_node.resolved_type = expected_type; + NumLitCodeGen *num_lit_code_gen = get_resolved_num_lit(node); + assert(!num_lit_code_gen->resolved_type || + num_lit_code_gen->resolved_type == expected_type); + num_lit_code_gen->resolved_type = expected_type; return expected_type; } @@ -1134,10 +1130,11 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont if (resolved_type->id == TypeTableEntryIdInvalid) { return resolved_type; } - node->codegen_node->expr_node.implicit_maybe_cast.op = CastOpMaybeWrap; - node->codegen_node->expr_node.implicit_maybe_cast.after_type = expected_type; - node->codegen_node->expr_node.implicit_maybe_cast.source_node = node; - context->cast_expr_alloca_list.append(&node->codegen_node->expr_node.implicit_maybe_cast); + Expr *expr = get_resolved_expr(node); + expr->implicit_maybe_cast.op = CastOpMaybeWrap; + expr->implicit_maybe_cast.after_type = expected_type; + expr->implicit_maybe_cast.source_node = node; + context->cast_expr_alloca_list.append(&expr->implicit_maybe_cast); return expected_type; } @@ -1147,9 +1144,10 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont expected_type->data.integral.is_signed == actual_type->data.integral.is_signed && expected_type->size_in_bits > actual_type->size_in_bits) { - node->codegen_node->expr_node.implicit_cast.after_type = expected_type; - node->codegen_node->expr_node.implicit_cast.op = CastOpIntWidenOrShorten; - node->codegen_node->expr_node.implicit_cast.source_node = node; + Expr *expr = get_resolved_expr(node); + expr->implicit_cast.after_type = expected_type; + expr->implicit_cast.op = CastOpIntWidenOrShorten; + expr->implicit_cast.source_node = node; return expected_type; } @@ -1159,10 +1157,11 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont actual_type->id == TypeTableEntryIdArray && actual_type->data.array.child_type == expected_type->data.structure.fields[0].type_entry->data.pointer.child_type) { - node->codegen_node->expr_node.implicit_cast.after_type = expected_type; - node->codegen_node->expr_node.implicit_cast.op = CastOpToUnknownSizeArray; - node->codegen_node->expr_node.implicit_cast.source_node = node; - context->cast_expr_alloca_list.append(&node->codegen_node->expr_node.implicit_cast); + Expr *expr = get_resolved_expr(node); + expr->implicit_cast.after_type = expected_type; + expr->implicit_cast.op = CastOpToUnknownSizeArray; + expr->implicit_cast.source_node = node; + context->cast_expr_alloca_list.append(&expr->implicit_cast); return expected_type; } @@ -1225,7 +1224,7 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) { if (node && node->type == NodeTypeFnDef) { AstNode *fn_proto_node = node->data.fn_def.fn_proto; - context->fn_entry = fn_proto_node->codegen_node->data.fn_proto_node.fn_table_entry; + context->fn_entry = fn_proto_node->data.fn_proto.fn_table_entry; } else if (parent) { context->fn_entry = parent->fn_entry; } @@ -1275,6 +1274,8 @@ static void get_struct_field(TypeTableEntry *struct_type, Buf *name, TypeStructF static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, AstNode *node) { + assert(node->type == NodeTypeFieldAccessExpr); + TypeTableEntry *struct_type = analyze_expression(g, import, context, nullptr, node->data.field_access_expr.struct_expr); @@ -1283,20 +1284,16 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i if (struct_type->id == TypeTableEntryIdStruct || (struct_type->id == TypeTableEntryIdPointer && struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct)) { - assert(node->codegen_node); - FieldAccessNode *codegen_field_access = &node->codegen_node->data.field_access_node; - assert(codegen_field_access); - Buf *field_name = &node->data.field_access_expr.field_name; TypeTableEntry *bare_struct_type = (struct_type->id == TypeTableEntryIdStruct) ? struct_type : struct_type->data.pointer.child_type; get_struct_field(bare_struct_type, field_name, - &codegen_field_access->type_struct_field, - &codegen_field_access->field_index); - if (codegen_field_access->type_struct_field) { - return_type = codegen_field_access->type_struct_field->type_entry; + &node->data.field_access_expr.type_struct_field, + &node->data.field_access_expr.field_index); + if (node->data.field_access_expr.type_struct_field) { + return_type = node->data.field_access_expr.type_struct_field->type_entry; } else { add_node_error(g, node, buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&struct_type->name))); @@ -1329,6 +1326,8 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, AstNode *node) { + assert(node->type == NodeTypeSliceExpr); + TypeTableEntry *array_type = analyze_expression(g, import, context, nullptr, node->data.slice_expr.array_ref_expr); @@ -1355,10 +1354,9 @@ static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import, } if (return_type->id != TypeTableEntryIdInvalid) { - assert(node->codegen_node); - node->codegen_node->data.struct_val_expr_node.type_entry = return_type; - node->codegen_node->data.struct_val_expr_node.source_node = node; - context->struct_val_expr_alloca_list.append(&node->codegen_node->data.struct_val_expr_node); + node->data.slice_expr.resolved_struct_val_expr.type_entry = return_type; + node->data.slice_expr.resolved_struct_val_expr.source_node = node; + context->struct_val_expr_alloca_list.append(&node->data.slice_expr.resolved_struct_val_expr); } analyze_expression(g, import, context, g->builtin_types.entry_usize, node->data.slice_expr.start); @@ -1463,6 +1461,8 @@ static bool is_op_allowed(TypeTableEntry *type, BinOpType op) { static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, TypeTableEntry *expected_type, AstNode *node) { + assert(node->type == NodeTypeCastExpr); + TypeTableEntry *wanted_type = resolve_type(g, node->data.cast_expr.type, import, context, false); TypeTableEntry *actual_type = analyze_expression(g, import, context, nullptr, node->data.cast_expr.expr); @@ -1472,43 +1472,41 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B return g->builtin_types.entry_invalid; } - CastNode *cast_node = &node->codegen_node->data.cast_node; - cast_node->source_node = node; - cast_node->after_type = wanted_type; + Cast *cast = &node->data.cast_expr.cast; + cast->source_node = node; + cast->after_type = wanted_type; - // special casing this for now, TODO think about casting and do a general solution if ((wanted_type == g->builtin_types.entry_isize || wanted_type == g->builtin_types.entry_usize) && actual_type->id == TypeTableEntryIdPointer) { - cast_node->op = CastOpPtrToInt; + cast->op = CastOpPtrToInt; return wanted_type; } else if (wanted_type->id == TypeTableEntryIdInt && actual_type->id == TypeTableEntryIdInt) { - cast_node->op = CastOpIntWidenOrShorten; + cast->op = CastOpIntWidenOrShorten; return wanted_type; } else if (wanted_type->id == TypeTableEntryIdStruct && wanted_type->data.structure.is_unknown_size_array && actual_type->id == TypeTableEntryIdArray && actual_type->data.array.child_type == wanted_type->data.structure.fields[0].type_entry) { - cast_node->op = CastOpToUnknownSizeArray; - context->cast_expr_alloca_list.append(cast_node); + cast->op = CastOpToUnknownSizeArray; + context->cast_expr_alloca_list.append(cast); return wanted_type; } else if (actual_type->id == TypeTableEntryIdNumberLiteral && num_lit_fits_in_other_type(g, actual_type, wanted_type)) { AstNode *literal_node = node->data.cast_expr.expr; - assert(literal_node->codegen_node); - NumberLiteralNode *codegen_num_lit = &literal_node->codegen_node->data.num_lit_node; + NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(literal_node); assert(!codegen_num_lit->resolved_type); codegen_num_lit->resolved_type = wanted_type; - cast_node->op = CastOpNothing; + cast->op = CastOpNothing; return wanted_type; } else if (actual_type->id == TypeTableEntryIdPointer && wanted_type->id == TypeTableEntryIdPointer) { - cast_node->op = CastOpPointerReinterpret; + cast->op = CastOpPointerReinterpret; return wanted_type; } else { add_node_error(g, node, @@ -1529,7 +1527,7 @@ static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, Bloc { TypeTableEntry *expected_rhs_type = nullptr; if (lhs_node->type == NodeTypeSymbol) { - Buf *name = &lhs_node->data.symbol; + Buf *name = &lhs_node->data.symbol_expr.symbol; VariableTableEntry *var = find_variable(block_context, name); if (var) { if (purpose == LValPurposeAssign && var->is_const) { @@ -1551,7 +1549,6 @@ static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, Bloc } else if (lhs_node->type == NodeTypeArrayAccessExpr) { expected_rhs_type = analyze_array_access_expr(g, import, block_context, lhs_node); } else if (lhs_node->type == NodeTypeFieldAccessExpr) { - alloc_codegen_node(lhs_node); expected_rhs_type = analyze_field_access_expr(g, import, block_context, lhs_node); } else if (lhs_node->type == NodeTypePrefixOpExpr && lhs_node->data.prefix_op_expr.prefix_op == PrefixOpDereference) @@ -1774,10 +1771,9 @@ static TypeTableEntry *analyze_null_literal_expr(CodeGen *g, ImportTableEntry *i if (expected_type) { assert(expected_type->id == TypeTableEntryIdMaybe); - assert(node->codegen_node); - node->codegen_node->data.struct_val_expr_node.type_entry = expected_type; - node->codegen_node->data.struct_val_expr_node.source_node = node; - block_context->struct_val_expr_alloca_list.append(&node->codegen_node->data.struct_val_expr_node); + node->data.null_literal.resolved_struct_val_expr.type_entry = expected_type; + node->data.null_literal.resolved_struct_val_expr.source_node = node; + block_context->struct_val_expr_alloca_list.append(&node->data.null_literal.resolved_struct_val_expr); return expected_type; } else { @@ -1796,7 +1792,7 @@ static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry buf_sprintf("number literal too large to be represented in any type")); return g->builtin_types.entry_invalid; } else if (expected_type) { - NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node; + NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node); assert(!codegen_num_lit->resolved_type); TypeTableEntry *after_implicit_cast_resolved_type = resolve_type_compatibility(g, block_context, node, expected_type, num_lit_type); @@ -1837,10 +1833,9 @@ static TypeTableEntry *analyze_struct_val_expr(CodeGen *g, ImportTableEntry *imp return g->builtin_types.entry_invalid; } - assert(node->codegen_node); - node->codegen_node->data.struct_val_expr_node.type_entry = type_entry; - node->codegen_node->data.struct_val_expr_node.source_node = node; - context->struct_val_expr_alloca_list.append(&node->codegen_node->data.struct_val_expr_node); + node->data.struct_val_expr.codegen.type_entry = type_entry; + node->data.struct_val_expr.codegen.source_node = node; + context->struct_val_expr_alloca_list.append(&node->data.struct_val_expr.codegen); int expr_field_count = struct_val_expr->fields.length; int actual_field_count = type_entry->data.structure.field_count; @@ -1848,6 +1843,8 @@ static TypeTableEntry *analyze_struct_val_expr(CodeGen *g, ImportTableEntry *imp int *field_use_counts = allocate(actual_field_count); for (int i = 0; i < expr_field_count; i += 1) { AstNode *val_field_node = struct_val_expr->fields.at(i); + assert(val_field_node->type == NodeTypeStructValueField); + int field_index; TypeStructField *type_field = find_struct_type_field(type_entry, &val_field_node->data.struct_val_field.name, &field_index); @@ -1865,8 +1862,7 @@ static TypeTableEntry *analyze_struct_val_expr(CodeGen *g, ImportTableEntry *imp continue; } - alloc_codegen_node(val_field_node); - val_field_node->codegen_node->data.struct_val_field_node.index = field_index; + val_field_node->data.struct_val_field.index = field_index; analyze_expression(g, import, context, type_field->type_entry, val_field_node->data.struct_val_field.expr); @@ -1885,6 +1881,8 @@ static TypeTableEntry *analyze_struct_val_expr(CodeGen *g, ImportTableEntry *imp static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, TypeTableEntry *expected_type, AstNode *node) { + assert(node->type == NodeTypeWhileExpr); + AstNode *condition_node = node->data.while_expr.condition; AstNode *while_body_node = node->data.while_expr.body; TypeTableEntry *condition_type = analyze_expression(g, import, context, @@ -1907,8 +1905,8 @@ static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, assert(resolved_type->id == TypeTableEntryIdBool); bool constant_cond_value = number_literal.data.x_uint; if (constant_cond_value) { - node->codegen_node->data.while_node.condition_always_true = true; - if (!node->codegen_node->data.while_node.contains_break) { + node->data.while_expr.condition_always_true = true; + if (!node->data.while_expr.contains_break) { expr_return_type = g->builtin_types.entry_unreachable; } } @@ -1921,12 +1919,14 @@ static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, TypeTableEntry *expected_type, AstNode *node) { + assert(node->type == NodeTypeBreak); + AstNode *loop_node = context->parent_loop_node; if (loop_node) { - loop_node->codegen_node->data.while_node.contains_break = true; + assert(loop_node->type == NodeTypeWhileExpr); + loop_node->data.while_expr.contains_break = true; } else { - add_node_error(g, node, - buf_sprintf("'break' expression outside loop")); + add_node_error(g, node, buf_sprintf("'break' expression outside loop")); } return g->builtin_types.entry_unreachable; } @@ -1935,8 +1935,7 @@ static TypeTableEntry *analyze_continue_expr(CodeGen *g, ImportTableEntry *impor TypeTableEntry *expected_type, AstNode *node) { if (!context->parent_loop_node) { - add_node_error(g, node, - buf_sprintf("'continue' expression outside loop")); + add_node_error(g, node, buf_sprintf("'continue' expression outside loop")); } return g->builtin_types.entry_unreachable; } @@ -1981,7 +1980,7 @@ static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import, assert(node->type == NodeTypeIfVarExpr); BlockContext *child_context = new_block_context(node, context); - node->codegen_node->data.if_var_node.block_context = child_context; + node->data.if_var_expr.block_context = child_context; analyze_variable_declaration_raw(g, import, child_context, node, &node->data.if_var_expr.var_decl, true); @@ -2032,8 +2031,10 @@ static TypeTableEntry *analyze_compiler_fn_type(CodeGen *g, ImportTableEntry *im static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, TypeTableEntry *expected_type, AstNode *node) { + assert(node->type == NodeTypeFnCallExpr); + AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; - Buf *name = &fn_ref_expr->data.symbol; + Buf *name = &fn_ref_expr->data.symbol_expr.symbol; auto entry = g->builtin_fn_table.maybe_get(name); @@ -2041,8 +2042,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry BuiltinFnEntry *builtin_fn = entry->value; int actual_param_count = node->data.fn_call_expr.params.length; - assert(node->codegen_node); - node->codegen_node->data.fn_call_node.builtin_fn = builtin_fn; + node->data.fn_call_expr.builtin_fn = builtin_fn; if (builtin_fn->param_count != actual_param_count) { add_node_error(g, node, @@ -2155,7 +2155,7 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import if (node->data.fn_call_expr.is_builtin) { return analyze_builtin_fn_call_expr(g, import, context, expected_type, node); } - name = &fn_ref_expr->data.symbol; + name = &fn_ref_expr->data.symbol_expr.symbol; } else { add_node_error(g, node, buf_sprintf("function pointers not yet supported")); @@ -2210,13 +2210,15 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import AstNode *param_decl_node = fn_proto->params.at(fn_proto_i); assert(param_decl_node->type == NodeTypeParamDecl); AstNode *param_type_node = param_decl_node->data.param_decl.type; - if (param_type_node->codegen_node) - expected_param_type = param_type_node->codegen_node->data.type_node.entry; + assert(param_type_node->type == NodeTypeType); + if (param_type_node->data.type.entry) { + expected_param_type = param_type_node->data.type.entry; + } } analyze_expression(g, import, context, expected_param_type, child); } - return fn_proto->return_type->codegen_node->data.type_node.entry; + return fn_proto->return_type->data.type.entry; } } @@ -2224,18 +2226,17 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, TypeTableEntry *expected_type, AstNode *node) { TypeTableEntry *return_type = nullptr; - alloc_codegen_node(node); switch (node->type) { case NodeTypeBlock: { BlockContext *child_context = new_block_context(node, context); - node->codegen_node->data.block_node.block_context = child_context; + node->data.block.block_context = child_context; return_type = g->builtin_types.entry_void; for (int i = 0; i < node->data.block.statements.length; i += 1) { AstNode *child = node->data.block.statements.at(i); if (child->type == NodeTypeLabel) { - LabelTableEntry *label_entry = child->codegen_node->data.label_entry; + LabelTableEntry *label_entry = child->data.label.label_entry; assert(label_entry); label_entry->entered_from_fallthrough = (return_type->id != TypeTableEntryIdUnreachable); return_type = g->builtin_types.entry_void; @@ -2288,13 +2289,13 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, case NodeTypeGoto: { FnTableEntry *fn_table_entry = get_context_fn_entry(context); - auto table_entry = fn_table_entry->label_table.maybe_get(&node->data.go_to.name); + auto table_entry = fn_table_entry->label_table.maybe_get(&node->data.goto_expr.name); if (table_entry) { - node->codegen_node->data.label_entry = table_entry->value; + node->data.goto_expr.label_entry = table_entry->value; table_entry->value->used = true; } else { add_node_error(g, node, - buf_sprintf("use of undeclared label '%s'", buf_ptr(&node->data.go_to.name))); + buf_sprintf("use of undeclared label '%s'", buf_ptr(&node->data.goto_expr.name))); } return_type = g->builtin_types.entry_unreachable; break; @@ -2380,7 +2381,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, case NodeTypeSymbol: { - return_type = analyze_variable_name(g, import, context, node, &node->data.symbol); + return_type = analyze_variable_name(g, import, context, node, &node->data.symbol_expr.symbol); break; } case NodeTypeCastExpr: @@ -2507,8 +2508,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, assert(return_type); resolve_type_compatibility(g, context, node, expected_type, return_type); - node->codegen_node->expr_node.type_entry = return_type; - node->codegen_node->expr_node.block_context = context; + get_resolved_expr(node)->type_entry = return_type; + get_resolved_expr(node)->block_context = context; return return_type; } @@ -2519,15 +2520,14 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo AstNode *fn_proto_node = node->data.fn_def.fn_proto; assert(fn_proto_node->type == NodeTypeFnProto); - if (fn_proto_node->codegen_node->data.fn_proto_node.skip) { + if (fn_proto_node->data.fn_proto.skip) { // we detected an error with this function definition which prevents us // from further analyzing it. return; } - alloc_codegen_node(node); BlockContext *context = new_block_context(node, import->block_context); - node->codegen_node->data.fn_def_node.block_context = context; + node->data.fn_def.block_context = context; AstNodeFnProto *fn_proto = &fn_proto_node->data.fn_proto; bool is_exported = (fn_proto->visib_mod == VisibModExport); @@ -2538,7 +2538,7 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo // define local variables for parameters AstNodeParamDecl *param_decl = ¶m_decl_node->data.param_decl; assert(param_decl->type->type == NodeTypeType); - TypeTableEntry *type = param_decl->type->codegen_node->data.type_node.entry; + TypeTableEntry *type = param_decl->type->data.type.entry; if (is_exported && type->id == TypeTableEntryIdStruct) { add_node_error(g, param_decl_node, @@ -2552,8 +2552,7 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo variable_entry->decl_node = param_decl_node; variable_entry->arg_index = i; - alloc_codegen_node(param_decl_node); - param_decl_node->codegen_node->data.param_decl_node.variable = variable_entry; + param_decl_node->data.param_decl.variable = variable_entry; VariableTableEntry *existing_entry = find_local_variable(context, &variable_entry->name); if (!existing_entry) { @@ -2571,13 +2570,13 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo } } - TypeTableEntry *expected_type = fn_proto->return_type->codegen_node->data.type_node.entry; + TypeTableEntry *expected_type = fn_proto->return_type->data.type.entry; TypeTableEntry *block_return_type = analyze_expression(g, import, context, expected_type, node->data.fn_def.body); - node->codegen_node->data.fn_def_node.implicit_return_type = block_return_type; + node->data.fn_def.implicit_return_type = block_return_type; { - FnTableEntry *fn_table_entry = fn_proto_node->codegen_node->data.fn_proto_node.fn_table_entry; + FnTableEntry *fn_table_entry = fn_proto_node->data.fn_proto.fn_table_entry; auto it = fn_table_entry->label_table.entry_iterator(); for (;;) { auto *entry = it.next(); @@ -2656,7 +2655,7 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode } static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *expr_node, - DeclNode *decl_node) + TopLevelDecl *decl_node) { switch (expr_node->type) { case NodeTypeNumberLiteral: @@ -2672,7 +2671,7 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode // no dependencies on other top level declarations break; case NodeTypeSymbol: - decl_node->deps.put(&expr_node->data.symbol, expr_node); + decl_node->deps.put(&expr_node->data.symbol_expr.symbol, expr_node); break; case NodeTypeBinOpExpr: collect_expr_decl_deps(g, import, expr_node->data.bin_op_expr.op1, decl_node); @@ -2787,7 +2786,7 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode } } -static void collect_type_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *type_node, DeclNode *decl_node) { +static void collect_type_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *type_node, TopLevelDecl *decl_node) { assert(type_node->type == NodeTypeType); switch (type_node->data.type.type) { case AstNodeTypeTypePrimitive: @@ -2824,16 +2823,13 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast switch (node->type) { case NodeTypeStructDecl: { - alloc_codegen_node(node); - StructDeclNode *struct_codegen = &node->codegen_node->data.struct_decl_node; - Buf *name = &node->data.struct_decl.name; auto table_entry = g->primitive_type_table.maybe_get(name); if (!table_entry) { table_entry = import->type_table.maybe_get(name); } if (table_entry) { - struct_codegen->type_entry = table_entry->value; + node->data.struct_decl.type_entry = table_entry->value; add_node_error(g, node, buf_sprintf("redefinition of '%s'", buf_ptr(name))); } else { @@ -2848,7 +2844,7 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast // put off adding the debug type until we do the full struct body // this type is incomplete until we do another pass import->type_table.put(&entry->name, entry); - struct_codegen->type_entry = entry; + node->data.struct_decl.type_entry = entry; bool is_pub = (node->data.struct_decl.visib_mod != VisibModPrivate); if (is_pub) { @@ -2867,14 +2863,15 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast } // determine which other top level declarations this struct depends on. - DeclNode *decl_node = &node->codegen_node->decl_node; + TopLevelDecl *decl_node = &node->data.struct_decl.top_level_decl; + decl_node->deps.init(1); for (int i = 0; i < node->data.struct_decl.fields.length; i += 1) { AstNode *field_node = node->data.struct_decl.fields.at(i); AstNode *type_node = field_node->data.struct_field.type; collect_type_decl_deps(g, import, type_node, decl_node); } - node->codegen_node->decl_node.name = name; - node->codegen_node->decl_node.import = import; + decl_node->name = name; + decl_node->import = import; if (decl_node->deps.size() > 0) { g->unresolved_top_level_decls.put(name, node); } else { @@ -2913,8 +2910,8 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast case NodeTypeVariableDeclaration: { // determine which other top level declarations this variable declaration depends on. - alloc_codegen_node(node); - DeclNode *decl_node = &node->codegen_node->decl_node; + TopLevelDecl *decl_node = &node->data.variable_declaration.top_level_decl; + decl_node->deps.init(1); if (node->data.variable_declaration.type) { collect_type_decl_deps(g, import, node->data.variable_declaration.type, decl_node); } @@ -2922,8 +2919,8 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast collect_expr_decl_deps(g, import, node->data.variable_declaration.expr, decl_node); } Buf *name = &node->data.variable_declaration.symbol; - node->codegen_node->decl_node.name = name; - node->codegen_node->decl_node.import = import; + decl_node->name = name; + decl_node->import = import; if (decl_node->deps.size() > 0) { g->unresolved_top_level_decls.put(name, node); } else { @@ -2934,8 +2931,8 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast case NodeTypeFnProto: { // determine which other top level declarations this function prototype depends on. - alloc_codegen_node(node); - DeclNode *decl_node = &node->codegen_node->decl_node; + TopLevelDecl *decl_node = &node->data.fn_proto.top_level_decl; + decl_node->deps.init(1); for (int i = 0; i < node->data.fn_proto.params.length; i += 1) { AstNode *param_node = node->data.fn_proto.params.at(i); assert(param_node->type == NodeTypeParamDecl); @@ -2943,8 +2940,8 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast } Buf *name = &node->data.fn_proto.name; - node->codegen_node->decl_node.name = name; - node->codegen_node->decl_node.import = import; + decl_node->name = name; + decl_node->import = import; if (decl_node->deps.size() > 0) { g->unresolved_top_level_decls.put(name, node); } else { @@ -2999,7 +2996,7 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast } static void recursive_resolve_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) { - auto it = node->codegen_node->decl_node.deps.entry_iterator(); + auto it = get_resolved_top_level_decl(node)->deps.entry_iterator(); for (;;) { auto *entry = it.next(); if (!entry) @@ -3012,23 +3009,24 @@ static void recursive_resolve_decl(CodeGen *g, ImportTableEntry *import, AstNode AstNode *child_node = unresolved_entry->value; - if (child_node->codegen_node->decl_node.in_current_deps) { + if (get_resolved_top_level_decl(child_node)->in_current_deps) { // dependency loop. we'll let the fact that it's not in the respective // table cause an error in resolve_top_level_decl. continue; } // set temporary flag - child_node->codegen_node->decl_node.in_current_deps = true; + TopLevelDecl *top_level_decl = get_resolved_top_level_decl(child_node); + top_level_decl->in_current_deps = true; - recursive_resolve_decl(g, child_node->codegen_node->decl_node.import, child_node); + recursive_resolve_decl(g, top_level_decl->import, child_node); // unset temporary flag - child_node->codegen_node->decl_node.in_current_deps = false; + top_level_decl->in_current_deps = false; } resolve_top_level_decl(g, import, node); - g->unresolved_top_level_decls.remove(node->codegen_node->decl_node.name); + g->unresolved_top_level_decls.remove(get_resolved_top_level_decl(node)->name); } static void resolve_top_level_declarations_root(CodeGen *g, ImportTableEntry *import, AstNode *node) { @@ -3051,12 +3049,13 @@ static void resolve_top_level_declarations_root(CodeGen *g, ImportTableEntry *im } // set temporary flag - decl_node->codegen_node->decl_node.in_current_deps = true; + TopLevelDecl *top_level_decl = get_resolved_top_level_decl(decl_node); + top_level_decl->in_current_deps = true; - recursive_resolve_decl(g, decl_node->codegen_node->decl_node.import, decl_node); + recursive_resolve_decl(g, top_level_decl->import, decl_node); // unset temporary flag - decl_node->codegen_node->decl_node.in_current_deps = false; + top_level_decl->in_current_deps = false; } } @@ -3089,7 +3088,7 @@ void semantic_analyze(CodeGen *g) { buf_sprintf("invalid directive: '%s'", buf_ptr(name))); } - ImportTableEntry *target_import = child->codegen_node->data.import_node.import; + ImportTableEntry *target_import = child->data.use.import; assert(target_import); target_import->importers.append({import, child}); @@ -3144,9 +3143,186 @@ void semantic_analyze(CodeGen *g) { } } -void alloc_codegen_node(AstNode *node) { - assert(!node->codegen_node); - node->codegen_node = allocate(1); - node->codegen_node->decl_node.deps.init(1); +Expr *get_resolved_expr(AstNode *node) { + switch (node->type) { + case NodeTypeReturnExpr: + return &node->data.return_expr.resolved_expr; + case NodeTypeBinOpExpr: + return &node->data.bin_op_expr.resolved_expr; + case NodeTypeCastExpr: + return &node->data.cast_expr.resolved_expr; + case NodeTypePrefixOpExpr: + return &node->data.prefix_op_expr.resolved_expr; + case NodeTypeFnCallExpr: + return &node->data.fn_call_expr.resolved_expr; + case NodeTypeArrayAccessExpr: + return &node->data.array_access_expr.resolved_expr; + case NodeTypeSliceExpr: + return &node->data.slice_expr.resolved_expr; + case NodeTypeFieldAccessExpr: + return &node->data.field_access_expr.resolved_expr; + case NodeTypeIfBoolExpr: + return &node->data.if_bool_expr.resolved_expr; + case NodeTypeIfVarExpr: + return &node->data.if_var_expr.resolved_expr; + case NodeTypeWhileExpr: + return &node->data.while_expr.resolved_expr; + case NodeTypeAsmExpr: + return &node->data.asm_expr.resolved_expr; + case NodeTypeStructValueExpr: + return &node->data.struct_val_expr.resolved_expr; + case NodeTypeNumberLiteral: + return &node->data.number_literal.resolved_expr; + case NodeTypeStringLiteral: + return &node->data.string_literal.resolved_expr; + case NodeTypeBlock: + return &node->data.block.resolved_expr; + case NodeTypeVoid: + return &node->data.void_expr.resolved_expr; + case NodeTypeUnreachable: + return &node->data.unreachable_expr.resolved_expr; + case NodeTypeSymbol: + return &node->data.symbol_expr.resolved_expr; + case NodeTypeVariableDeclaration: + return &node->data.variable_declaration.resolved_expr; + case NodeTypeCharLiteral: + return &node->data.char_literal.resolved_expr; + case NodeTypeBoolLiteral: + return &node->data.bool_literal.resolved_expr; + case NodeTypeNullLiteral: + return &node->data.null_literal.resolved_expr; + case NodeTypeGoto: + return &node->data.goto_expr.resolved_expr; + case NodeTypeBreak: + return &node->data.break_expr.resolved_expr; + case NodeTypeContinue: + return &node->data.continue_expr.resolved_expr; + case NodeTypeCompilerFnExpr: + return &node->data.compiler_fn_expr.resolved_expr; + case NodeTypeCompilerFnType: + return &node->data.compiler_fn_type.resolved_expr; + case NodeTypeLabel: + return &node->data.label.resolved_expr; + case NodeTypeRoot: + case NodeTypeRootExportDecl: + case NodeTypeFnProto: + case NodeTypeFnDef: + case NodeTypeFnDecl: + case NodeTypeParamDecl: + case NodeTypeType: + case NodeTypeExternBlock: + case NodeTypeDirective: + case NodeTypeUse: + case NodeTypeStructDecl: + case NodeTypeStructField: + case NodeTypeStructValueField: + case NodeTypeEnumDecl: + case NodeTypeEnumField: + zig_unreachable(); + } } +NumLitCodeGen *get_resolved_num_lit(AstNode *node) { + switch (node->type) { + case NodeTypeNumberLiteral: + return &node->data.number_literal.codegen; + case NodeTypeCompilerFnType: + return &node->data.compiler_fn_type.resolved_num_lit; + case NodeTypeReturnExpr: + case NodeTypeBinOpExpr: + case NodeTypeCastExpr: + case NodeTypePrefixOpExpr: + case NodeTypeFnCallExpr: + case NodeTypeArrayAccessExpr: + case NodeTypeSliceExpr: + case NodeTypeFieldAccessExpr: + case NodeTypeIfBoolExpr: + case NodeTypeIfVarExpr: + case NodeTypeWhileExpr: + case NodeTypeAsmExpr: + case NodeTypeStructValueExpr: + case NodeTypeRoot: + case NodeTypeRootExportDecl: + case NodeTypeFnProto: + case NodeTypeFnDef: + case NodeTypeFnDecl: + case NodeTypeParamDecl: + case NodeTypeType: + case NodeTypeBlock: + case NodeTypeExternBlock: + case NodeTypeDirective: + case NodeTypeVariableDeclaration: + case NodeTypeStringLiteral: + case NodeTypeCharLiteral: + case NodeTypeUnreachable: + case NodeTypeSymbol: + case NodeTypeUse: + case NodeTypeVoid: + case NodeTypeBoolLiteral: + case NodeTypeNullLiteral: + case NodeTypeLabel: + case NodeTypeGoto: + case NodeTypeBreak: + case NodeTypeContinue: + case NodeTypeStructDecl: + case NodeTypeStructField: + case NodeTypeStructValueField: + case NodeTypeEnumDecl: + case NodeTypeEnumField: + case NodeTypeCompilerFnExpr: + zig_unreachable(); + } +} + +TopLevelDecl *get_resolved_top_level_decl(AstNode *node) { + switch (node->type) { + case NodeTypeVariableDeclaration: + return &node->data.variable_declaration.top_level_decl; + case NodeTypeFnProto: + return &node->data.fn_proto.top_level_decl; + case NodeTypeStructDecl: + return &node->data.struct_decl.top_level_decl; + case NodeTypeNumberLiteral: + case NodeTypeReturnExpr: + case NodeTypeBinOpExpr: + case NodeTypeCastExpr: + case NodeTypePrefixOpExpr: + case NodeTypeFnCallExpr: + case NodeTypeArrayAccessExpr: + case NodeTypeSliceExpr: + case NodeTypeFieldAccessExpr: + case NodeTypeIfBoolExpr: + case NodeTypeIfVarExpr: + case NodeTypeWhileExpr: + case NodeTypeAsmExpr: + case NodeTypeStructValueExpr: + case NodeTypeRoot: + case NodeTypeRootExportDecl: + case NodeTypeFnDef: + case NodeTypeFnDecl: + case NodeTypeParamDecl: + case NodeTypeType: + case NodeTypeBlock: + case NodeTypeExternBlock: + case NodeTypeDirective: + case NodeTypeStringLiteral: + case NodeTypeCharLiteral: + case NodeTypeUnreachable: + case NodeTypeSymbol: + case NodeTypeUse: + case NodeTypeVoid: + case NodeTypeBoolLiteral: + case NodeTypeNullLiteral: + case NodeTypeLabel: + case NodeTypeGoto: + case NodeTypeBreak: + case NodeTypeContinue: + case NodeTypeStructField: + case NodeTypeStructValueField: + case NodeTypeEnumDecl: + case NodeTypeEnumField: + case NodeTypeCompilerFnExpr: + case NodeTypeCompilerFnType: + zig_unreachable(); + } +} diff --git a/src/analyze.hpp b/src/analyze.hpp index 95082365fd..ec9c6ac705 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -8,414 +8,16 @@ #ifndef ZIG_ANALYZE_HPP #define ZIG_ANALYZE_HPP -#include "codegen.hpp" -#include "hash_map.hpp" -#include "zig_llvm.hpp" -#include "errmsg.hpp" - -struct FnTableEntry; -struct BlockContext; -struct TypeTableEntry; -struct VariableTableEntry; -struct CastNode; -struct StructValExprNode; - -struct TypeTableEntryPointer { - TypeTableEntry *child_type; - bool is_const; - bool is_noalias; -}; - -struct TypeTableEntryInt { - bool is_signed; -}; - -struct TypeTableEntryArray { - TypeTableEntry *child_type; - uint64_t len; -}; - -struct TypeStructField { - Buf *name; - TypeTableEntry *type_entry; -}; - -struct TypeTableEntryStruct { - AstNode *decl_node; - bool is_packed; - int field_count; - TypeStructField *fields; - uint64_t size_bytes; - bool is_invalid; // true if any fields are invalid - bool is_unknown_size_array; - // reminder: hash tables must be initialized before use - HashMap fn_table; - - // set this flag temporarily to detect infinite loops - bool embedded_in_current; - bool reported_infinite_err; -}; - -struct TypeTableEntryNumLit { - NumLit kind; -}; - -struct TypeTableEntryMaybe { - TypeTableEntry *child_type; -}; - -enum TypeTableEntryId { - TypeTableEntryIdInvalid, - TypeTableEntryIdVoid, - TypeTableEntryIdBool, - TypeTableEntryIdUnreachable, - TypeTableEntryIdInt, - TypeTableEntryIdFloat, - TypeTableEntryIdPointer, - TypeTableEntryIdArray, - TypeTableEntryIdStruct, - TypeTableEntryIdNumberLiteral, - TypeTableEntryIdMaybe, -}; - -struct TypeTableEntry { - TypeTableEntryId id; - - LLVMTypeRef type_ref; - LLVMZigDIType *di_type; - uint64_t size_in_bits; - uint64_t align_in_bits; - - Buf name; - - union { - TypeTableEntryPointer pointer; - TypeTableEntryInt integral; - TypeTableEntryArray array; - TypeTableEntryStruct structure; - TypeTableEntryNumLit num_lit; - TypeTableEntryMaybe maybe; - } data; - - // use these fields to make sure we don't duplicate type table entries for the same type - TypeTableEntry *pointer_parent[2][2]; // 0 - const. 1 - noalias - TypeTableEntry *unknown_size_array_parent[2][2]; // 0 - const. 1 - noalias - HashMap arrays_by_size; - TypeTableEntry *maybe_parent; - -}; - -struct ImporterInfo { - ImportTableEntry *import; - AstNode *source_node; -}; - -struct ImportTableEntry { - AstNode *root; - Buf *path; // relative to root_source_dir - LLVMZigDIFile *di_file; - Buf *source_code; - ZigList *line_offsets; - BlockContext *block_context; - ZigList importers; - - // reminder: hash tables must be initialized before use - HashMap fn_table; - HashMap type_table; -}; - -struct LabelTableEntry { - AstNode *label_node; - LLVMBasicBlockRef basic_block; - bool used; - bool entered_from_fallthrough; -}; - -enum FnAttrId { - FnAttrIdNaked, - FnAttrIdAlwaysInline, -}; - -struct FnTableEntry { - LLVMValueRef fn_value; - AstNode *proto_node; - AstNode *fn_def_node; - bool is_extern; - bool internal_linkage; - unsigned calling_convention; - ImportTableEntry *import_entry; - ZigList fn_attr_list; - // Required to be a pre-order traversal of the AST. (parents must come before children) - ZigList all_block_contexts; - TypeTableEntry *member_of_struct; - Buf symbol_name; - - // reminder: hash tables must be initialized before use - HashMap label_table; -}; - -enum BuiltinFnId { - BuiltinFnIdInvalid, - BuiltinFnIdArithmeticWithOverflow, - BuiltinFnIdMemcpy, - BuiltinFnIdMemset, -}; - -struct BuiltinFnEntry { - BuiltinFnId id; - Buf name; - int param_count; - TypeTableEntry *return_type; - TypeTableEntry **param_types; - LLVMValueRef fn_val; -}; - -struct CodeGen { - LLVMModuleRef module; - ZigList errors; - LLVMBuilderRef builder; - LLVMZigDIBuilder *dbuilder; - LLVMZigDICompileUnit *compile_unit; - - ZigList lib_search_paths; - - // reminder: hash tables must be initialized before use - HashMap str_table; - HashMap link_table; - HashMap import_table; - HashMap builtin_fn_table; - HashMap primitive_type_table; - HashMap unresolved_top_level_decls; - - uint32_t next_unresolved_index; - - struct { - TypeTableEntry *entry_bool; - TypeTableEntry *entry_u8; - TypeTableEntry *entry_u16; - TypeTableEntry *entry_u32; - TypeTableEntry *entry_u64; - TypeTableEntry *entry_i8; - TypeTableEntry *entry_i16; - TypeTableEntry *entry_i32; - TypeTableEntry *entry_i64; - TypeTableEntry *entry_isize; - TypeTableEntry *entry_usize; - TypeTableEntry *entry_f32; - TypeTableEntry *entry_f64; - TypeTableEntry *entry_c_string_literal; - TypeTableEntry *entry_void; - TypeTableEntry *entry_unreachable; - TypeTableEntry *entry_invalid; - } builtin_types; - - TypeTableEntry *num_lit_types[NumLitCount]; - - LLVMTargetDataRef target_data_ref; - unsigned pointer_size_bytes; - bool is_static; - bool strip_debug_symbols; - bool have_exported_main; - bool link_libc; - Buf *libc_path; - CodeGenBuildType build_type; - LLVMTargetMachineRef target_machine; - LLVMZigDIFile *dummy_di_file; - bool is_native_target; - Buf *root_source_dir; - Buf *root_out_name; - - // The function definitions this module includes. There must be a corresponding - // fn_protos entry. - ZigList fn_defs; - // The function prototypes this module includes. In the case of external declarations, - // there will not be a corresponding fn_defs entry. - ZigList fn_protos; - ZigList global_vars; - - OutType out_type; - FnTableEntry *cur_fn; - BlockContext *cur_block_context; - ZigList break_block_stack; - ZigList continue_block_stack; - bool c_stdint_used; - AstNode *root_export_decl; - int version_major; - int version_minor; - int version_patch; - bool verbose; - ErrColor err_color; - ImportTableEntry *root_import; - ImportTableEntry *bootstrap_import; - LLVMValueRef memcpy_fn_val; - bool error_during_imports; -}; - -struct VariableTableEntry { - Buf name; - TypeTableEntry *type; - LLVMValueRef value_ref; - bool is_const; - bool is_ptr; // if true, value_ref is a pointer - AstNode *decl_node; - LLVMZigDILocalVariable *di_loc_var; - int arg_index; -}; - -struct BlockContext { - AstNode *node; // either NodeTypeFnDef or NodeTypeBlock or NodeTypeRoot - FnTableEntry *fn_entry; // null at the module scope - BlockContext *parent; // null when this is the root - HashMap variable_table; - ZigList cast_expr_alloca_list; - ZigList struct_val_expr_alloca_list; - AstNode *parent_loop_node; - AstNode *next_child_parent_loop_node; - LLVMZigDIScope *di_scope; -}; - -struct TypeNode { - TypeTableEntry *entry; -}; - -struct FnProtoNode { - FnTableEntry *fn_table_entry; - bool skip; -}; - -struct FnDefNode { - TypeTableEntry *implicit_return_type; - BlockContext *block_context; -}; - - -struct AssignNode { - VariableTableEntry *var_entry; -}; - -struct BlockNode { - BlockContext *block_context; -}; - -struct StructDeclNode { - TypeTableEntry *type_entry; -}; - -struct FieldAccessNode { - int field_index; - TypeStructField *type_struct_field; -}; - -enum CastOp { - CastOpNothing, - CastOpPtrToInt, - CastOpIntWidenOrShorten, - CastOpToUnknownSizeArray, - CastOpMaybeWrap, - CastOpPointerReinterpret, -}; - -struct CastNode { - CastOp op; - // if op is CastOpArrayToString, this will be a pointer to - // the string struct on the stack - LLVMValueRef ptr; - TypeTableEntry *after_type; - AstNode *source_node; -}; - -struct ExprNode { - TypeTableEntry *type_entry; - // the context in which this expression is evaluated. - // for blocks, this points to the containing scope, not the block's own scope for its children. - BlockContext *block_context; - - // may be null for no cast - CastNode implicit_cast; // happens first - CastNode implicit_maybe_cast; // happens second -}; - -struct NumberLiteralNode { - TypeTableEntry *resolved_type; -}; - -struct VarDeclNode { - TypeTableEntry *type; -}; - -struct StructValFieldNode { - int index; -}; - -struct StructValExprNode { - TypeTableEntry *type_entry; - LLVMValueRef ptr; - AstNode *source_node; -}; - -struct IfVarNode { - BlockContext *block_context; -}; - -struct ParamDeclNode { - VariableTableEntry *variable; -}; - -struct ImportNode { - ImportTableEntry *import; -}; - -struct WhileNode { - bool condition_always_true; - bool contains_break; -}; - -struct FnCallNode { - BuiltinFnEntry *builtin_fn; -}; - -struct DeclNode { - HashMap deps; - Buf *name; - ImportTableEntry *import; - // set this flag temporarily to detect infinite loops - bool in_current_deps; -}; - -// TODO get rid of this structure and put the data directly in the appropriate AST node -struct CodeGenNode { - union { - TypeNode type_node; // for NodeTypeType - FnDefNode fn_def_node; // for NodeTypeFnDef - FnProtoNode fn_proto_node; // for NodeTypeFnProto - LabelTableEntry *label_entry; // for NodeTypeGoto and NodeTypeLabel - AssignNode assign_node; // for NodeTypeBinOpExpr where op is BinOpTypeAssign - BlockNode block_node; // for NodeTypeBlock - StructDeclNode struct_decl_node; // for NodeTypeStructDecl - FieldAccessNode field_access_node; // for NodeTypeFieldAccessExpr - CastNode cast_node; // for NodeTypeCastExpr - // note: I've been using this field on some non-number literal nodes too. - NumberLiteralNode num_lit_node; // for NodeTypeNumberLiteral - VarDeclNode var_decl_node; // for NodeTypeVariableDeclaration - StructValFieldNode struct_val_field_node; // for NodeTypeStructValueField - // note: I've been using this field on some non-struct val expressions too. - StructValExprNode struct_val_expr_node; // for NodeTypeStructValueExpr - IfVarNode if_var_node; // for NodeTypeStructValueExpr - ParamDeclNode param_decl_node; // for NodeTypeParamDecl - ImportNode import_node; // for NodeTypeUse - WhileNode while_node; // for NodeTypeWhileExpr - FnCallNode fn_call_node; // for NodeTypeFnCallExpr - } data; - ExprNode expr_node; // for all the expression nodes - DeclNode decl_node; // for all top level decls -}; +#include "all_types.hpp" void semantic_analyze(CodeGen *g); void add_node_error(CodeGen *g, AstNode *node, Buf *msg); -void alloc_codegen_node(AstNode *node); TypeTableEntry *new_type_table_entry(TypeTableEntryId id); TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const, bool is_noalias); VariableTableEntry *find_variable(BlockContext *context, Buf *name); BlockContext *new_block_context(AstNode *node, BlockContext *parent); +Expr *get_resolved_expr(AstNode *node); +NumLitCodeGen *get_resolved_num_lit(AstNode *node); +TopLevelDecl *get_resolved_top_level_decl(AstNode *node); #endif diff --git a/src/codegen.cpp b/src/codegen.cpp index 4df4960596..b46ec52e9c 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -75,9 +75,7 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType b static TypeTableEntry *get_type_for_type_node(CodeGen *g, AstNode *type_node) { assert(type_node->type == NodeTypeType); - assert(type_node->codegen_node); - assert(type_node->codegen_node->data.type_node.entry); - return type_node->codegen_node->data.type_node.entry; + return type_node->data.type.entry; } static TypeTableEntry *fn_proto_type_from_type_node(CodeGen *g, AstNode *type_node) { @@ -138,15 +136,16 @@ static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str, bool c) { } static TypeTableEntry *get_expr_type(AstNode *node) { - TypeTableEntry *cast_type = node->codegen_node->expr_node.implicit_cast.after_type; - return cast_type ? cast_type : node->codegen_node->expr_node.type_entry; + Expr *expr = get_resolved_expr(node); + TypeTableEntry *cast_type = expr->implicit_cast.after_type; + return cast_type ? cast_type : expr->type_entry; } static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { assert(node->type == NodeTypeFnCallExpr); AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; assert(fn_ref_expr->type == NodeTypeSymbol); - BuiltinFnEntry *builtin_fn = node->codegen_node->data.fn_call_node.builtin_fn; + BuiltinFnEntry *builtin_fn = node->data.fn_call_expr.builtin_fn; switch (builtin_fn->id) { case BuiltinFnIdInvalid: @@ -265,7 +264,7 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { // Assume that the expression evaluates to a simple name and return the buf // TODO after we support function pointers we can make this generic assert(fn_ref_expr->type == NodeTypeSymbol); - Buf *name = &fn_ref_expr->data.symbol; + Buf *name = &fn_ref_expr->data.symbol_expr.symbol; struct_type = nullptr; first_param_expr = nullptr; @@ -388,8 +387,8 @@ static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **ou LLVMValueRef struct_ptr; if (struct_expr_node->type == NodeTypeSymbol) { - VariableTableEntry *var = find_variable(struct_expr_node->codegen_node->expr_node.block_context, - &struct_expr_node->data.symbol); + VariableTableEntry *var = find_variable(get_resolved_expr(struct_expr_node)->block_context, + &struct_expr_node->data.symbol_expr.symbol); assert(var); if (var->is_ptr && var->type->id == TypeTableEntryIdPointer) { @@ -413,14 +412,12 @@ static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **ou assert(LLVMGetTypeKind(LLVMTypeOf(struct_ptr)) == LLVMPointerTypeKind); assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(struct_ptr))) == LLVMStructTypeKind); - FieldAccessNode *codegen_field_access = &node->codegen_node->data.field_access_node; + assert(node->data.field_access_expr.field_index >= 0); - assert(codegen_field_access->field_index >= 0); - - *out_type_entry = codegen_field_access->type_struct_field->type_entry; + *out_type_entry = node->data.field_access_expr.type_struct_field->type_entry; add_debug_source_node(g, node); - return LLVMBuildStructGEP(g->builder, struct_ptr, codegen_field_access->field_index, ""); + return LLVMBuildStructGEP(g->builder, struct_ptr, node->data.field_access_expr.field_index, ""); } static LLVMValueRef gen_slice_expr(CodeGen *g, AstNode *node) { @@ -429,7 +426,7 @@ static LLVMValueRef gen_slice_expr(CodeGen *g, AstNode *node) { AstNode *array_ref_node = node->data.slice_expr.array_ref_expr; TypeTableEntry *array_type = get_expr_type(array_ref_node); - LLVMValueRef tmp_struct_ptr = node->codegen_node->data.struct_val_expr_node.ptr; + LLVMValueRef tmp_struct_ptr = node->data.slice_expr.resolved_struct_val_expr.ptr; LLVMValueRef array_ptr = gen_array_base_ptr(g, array_ref_node); if (array_type->id == TypeTableEntryIdArray) { @@ -545,8 +542,8 @@ static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node, LLVMValueRef target_ref; if (node->type == NodeTypeSymbol) { - VariableTableEntry *var = find_variable(expr_node->codegen_node->expr_node.block_context, - &node->data.symbol); + VariableTableEntry *var = find_variable(get_resolved_expr(expr_node)->block_context, + &node->data.symbol_expr.symbol); assert(var); // semantic checking ensures no variables are constant assert(!var->is_const); @@ -630,7 +627,7 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) { } static LLVMValueRef gen_bare_cast(CodeGen *g, AstNode *node, LLVMValueRef expr_val, - TypeTableEntry *actual_type, TypeTableEntry *wanted_type, CastNode *cast_node) + TypeTableEntry *actual_type, TypeTableEntry *wanted_type, Cast *cast_node) { switch (cast_node->op) { case CastOpNothing: @@ -705,7 +702,7 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) { TypeTableEntry *actual_type = get_expr_type(node->data.cast_expr.expr); TypeTableEntry *wanted_type = get_expr_type(node); - CastNode *cast_node = &node->codegen_node->data.cast_node; + Cast *cast_node = &node->data.cast_expr.cast; return gen_bare_cast(g, node, expr_val, actual_type, wanted_type, cast_node); @@ -1218,7 +1215,7 @@ static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) { assert(node->data.if_var_expr.var_decl.expr); BlockContext *old_block_context = g->cur_block_context; - BlockContext *new_block_context = node->codegen_node->data.if_var_node.block_context; + BlockContext *new_block_context = node->data.if_var_expr.block_context; LLVMValueRef init_val; gen_var_decl_raw(g, node, &node->data.if_var_expr.var_decl, new_block_context, true, &init_val); @@ -1242,7 +1239,7 @@ static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *i assert(block_node->type == NodeTypeBlock); BlockContext *old_block_context = g->cur_block_context; - g->cur_block_context = block_node->codegen_node->data.block_node.block_context; + g->cur_block_context = block_node->data.block.block_context; LLVMValueRef return_value; for (int i = 0; i < block_node->data.block.statements.length; i += 1) { @@ -1347,7 +1344,7 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) { if (!is_return) { VariableTableEntry *variable = find_variable( - node->codegen_node->expr_node.block_context, + get_resolved_expr(node)->block_context, &asm_output->variable_name); assert(variable); param_types[param_index] = LLVMTypeOf(variable->value_ref); @@ -1396,7 +1393,7 @@ static LLVMValueRef gen_null_literal(CodeGen *g, AstNode *node) { TypeTableEntry *type_entry = get_expr_type(node); assert(type_entry->id == TypeTableEntryIdMaybe); - LLVMValueRef tmp_struct_ptr = node->codegen_node->data.struct_val_expr_node.ptr; + LLVMValueRef tmp_struct_ptr = node->data.null_literal.resolved_struct_val_expr.ptr; add_debug_source_node(g, node); LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 1, ""); @@ -1416,12 +1413,13 @@ static LLVMValueRef gen_struct_val_expr(CodeGen *g, AstNode *node) { int field_count = type_entry->data.structure.field_count; assert(field_count == node->data.struct_val_expr.fields.length); - StructValExprNode *struct_val_expr_node = &node->codegen_node->data.struct_val_expr_node; + StructValExprCodeGen *struct_val_expr_node = &node->data.struct_val_expr.codegen; LLVMValueRef tmp_struct_ptr = struct_val_expr_node->ptr; for (int i = 0; i < field_count; i += 1) { AstNode *field_node = node->data.struct_val_expr.fields.at(i); - int index = field_node->codegen_node->data.struct_val_field_node.index; + assert(field_node->type == NodeTypeStructValueField); + int index = field_node->data.struct_val_field.index; TypeStructField *type_struct_field = &type_entry->data.structure.fields[index]; assert(buf_eql_buf(type_struct_field->name, &field_node->data.struct_val_field.name)); @@ -1439,8 +1437,8 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) { assert(node->data.while_expr.condition); assert(node->data.while_expr.body); - bool condition_always_true = node->codegen_node->data.while_node.condition_always_true; - bool contains_break = node->codegen_node->data.while_node.contains_break; + bool condition_always_true = node->data.while_expr.condition_always_true; + bool contains_break = node->data.while_expr.contains_break; if (condition_always_true) { // generate a forever loop @@ -1559,17 +1557,17 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) { LLVMValueRef init_val; return gen_var_decl_raw(g, node, &node->data.variable_declaration, - node->codegen_node->expr_node.block_context, false, &init_val); + get_resolved_expr(node)->block_context, false, &init_val); } static LLVMValueRef gen_number_literal_raw(CodeGen *g, AstNode *source_node, - NumberLiteralNode *codegen_num_lit, AstNodeNumberLiteral *num_lit_node) + NumLitCodeGen *codegen_num_lit, AstNodeNumberLiteral *num_lit_node) { TypeTableEntry *type_entry = codegen_num_lit->resolved_type; assert(type_entry); // override the expression type for number literals - source_node->codegen_node->expr_node.type_entry = type_entry; + get_resolved_expr(source_node)->type_entry = type_entry; if (type_entry->id == TypeTableEntryIdInt) { // here the union has int64_t and uint64_t and we purposefully read @@ -1594,7 +1592,7 @@ static LLVMValueRef gen_compiler_fn_type(CodeGen *g, AstNode *node) { Buf *name = &node->data.compiler_fn_type.name; TypeTableEntry *type_entry = get_type_for_type_node(g, node->data.compiler_fn_type.type); if (buf_eql_str(name, "sizeof")) { - NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node; + NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node); AstNodeNumberLiteral num_lit_node; num_lit_node.kind = type_entry->data.num_lit.kind; num_lit_node.overflow = false; @@ -1632,7 +1630,7 @@ static LLVMValueRef gen_compiler_fn_type(CodeGen *g, AstNode *node) { static LLVMValueRef gen_number_literal(CodeGen *g, AstNode *node) { assert(node->type == NodeTypeNumberLiteral); - NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node; + NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node); assert(codegen_num_lit); return gen_number_literal_raw(g, node, codegen_num_lit, &node->data.number_literal); @@ -1664,7 +1662,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { case NodeTypeVoid: return nullptr; case NodeTypeBoolLiteral: - if (node->data.bool_literal) + if (node->data.bool_literal.value) return LLVMConstAllOnes(LLVMInt1Type()); else return LLVMConstNull(LLVMInt1Type()); @@ -1696,8 +1694,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { case NodeTypeSymbol: { VariableTableEntry *variable = find_variable( - node->codegen_node->expr_node.block_context, - &node->data.symbol); + get_resolved_expr(node)->block_context, + &node->data.symbol_expr.symbol); assert(variable); if (variable->type->id == TypeTableEntryIdVoid) { return nullptr; @@ -1721,14 +1719,14 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { return gen_block(g, node, nullptr); case NodeTypeGoto: add_debug_source_node(g, node); - return LLVMBuildBr(g->builder, node->codegen_node->data.label_entry->basic_block); + return LLVMBuildBr(g->builder, node->data.goto_expr.label_entry->basic_block); case NodeTypeBreak: return gen_break(g, node); case NodeTypeContinue: return gen_continue(g, node); case NodeTypeLabel: { - LabelTableEntry *label_entry = node->codegen_node->data.label_entry; + LabelTableEntry *label_entry = node->data.label.label_entry; assert(label_entry); LLVMBasicBlockRef basic_block = label_entry->basic_block; if (label_entry->entered_from_fallthrough) { @@ -1770,19 +1768,19 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { return val; } - assert(node->codegen_node); + Expr *expr = get_resolved_expr(node); - TypeTableEntry *before_type = node->codegen_node->expr_node.type_entry; + TypeTableEntry *before_type = expr->type_entry; if (before_type && before_type->id == TypeTableEntryIdUnreachable) { return val; } - CastNode *cast_node = &node->codegen_node->expr_node.implicit_cast; + Cast *cast_node = &expr->implicit_cast; if (cast_node->after_type) { val = gen_bare_cast(g, node, val, before_type, cast_node->after_type, cast_node); before_type = cast_node->after_type; } - cast_node = &node->codegen_node->expr_node.implicit_maybe_cast; + cast_node = &expr->implicit_maybe_cast; if (cast_node->after_type) { val = gen_bare_cast(g, node, val, before_type, cast_node->after_type, cast_node); } @@ -1798,7 +1796,7 @@ static void build_label_blocks(CodeGen *g, AstNode *block_node) { continue; Buf *name = &label_node->data.label.name; - label_node->codegen_node->data.label_entry->basic_block = LLVMAppendBasicBlock( + label_node->data.label.label_entry->basic_block = LLVMAppendBasicBlock( g->cur_fn->fn_value, buf_ptr(name)); } @@ -1944,13 +1942,7 @@ static void do_code_gen(CodeGen *g) { LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn, "entry"); LLVMPositionBuilderAtEnd(g->builder, entry_block); - CodeGenNode *codegen_node = fn_def_node->codegen_node; - assert(codegen_node); - - FnDefNode *codegen_fn_def = &codegen_node->data.fn_def_node; - assert(codegen_fn_def); - - codegen_fn_def->block_context->di_scope = LLVMZigSubprogramToScope(subprogram); + fn_def_node->data.fn_def.block_context->di_scope = LLVMZigSubprogramToScope(subprogram); int non_void_param_count = count_non_void_params(g, &fn_proto->params); assert(non_void_param_count == (int)LLVMCountParams(fn)); @@ -1963,7 +1955,7 @@ static void do_code_gen(CodeGen *g) { assert(param_decl->type == NodeTypeParamDecl); if (is_param_decl_type_void(g, param_decl)) continue; - VariableTableEntry *parameter_variable = fn_def_node->codegen_node->data.fn_def_node.block_context->variable_table.get(¶m_decl->data.param_decl.name); + VariableTableEntry *parameter_variable = fn_def_node->data.fn_def.block_context->variable_table.get(¶m_decl->data.param_decl.name); parameter_variable->value_ref = params[non_void_index]; non_void_index += 1; } @@ -2019,14 +2011,14 @@ static void do_code_gen(CodeGen *g) { // allocate structs which are the result of casts for (int cea_i = 0; cea_i < block_context->cast_expr_alloca_list.length; cea_i += 1) { - CastNode *cast_node = block_context->cast_expr_alloca_list.at(cea_i); + Cast *cast_node = block_context->cast_expr_alloca_list.at(cea_i); add_debug_source_node(g, cast_node->source_node); cast_node->ptr = LLVMBuildAlloca(g->builder, cast_node->after_type->type_ref, ""); } // allocate structs which are struct value expressions for (int alloca_i = 0; alloca_i < block_context->struct_val_expr_alloca_list.length; alloca_i += 1) { - StructValExprNode *struct_val_expr_node = block_context->struct_val_expr_alloca_list.at(alloca_i); + StructValExprCodeGen *struct_val_expr_node = block_context->struct_val_expr_alloca_list.at(alloca_i); add_debug_source_node(g, struct_val_expr_node->source_node); struct_val_expr_node->ptr = LLVMBuildAlloca(g->builder, struct_val_expr_node->type_entry->type_ref, ""); @@ -2041,15 +2033,15 @@ static void do_code_gen(CodeGen *g) { if (is_param_decl_type_void(g, param_decl)) continue; - VariableTableEntry *variable = param_decl->codegen_node->data.param_decl_node.variable; + VariableTableEntry *variable = param_decl->data.param_decl.variable; LLVMZigDILocation *debug_loc = LLVMZigGetDebugLoc(param_decl->line + 1, param_decl->column + 1, - codegen_fn_def->block_context->di_scope); + fn_def_node->data.fn_def.block_context->di_scope); LLVMZigInsertDeclareAtEnd(g->dbuilder, variable->value_ref, variable->di_loc_var, debug_loc, entry_block); } - TypeTableEntry *implicit_return_type = codegen_fn_def->implicit_return_type; + TypeTableEntry *implicit_return_type = fn_def_node->data.fn_def.implicit_return_type; gen_block(g, fn_def_node->data.fn_def.body, implicit_return_type); } @@ -2549,8 +2541,6 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path, Buf *import_code = buf_alloc(); bool found_it = false; - alloc_codegen_node(top_level_decl); - for (int path_i = 0; path_i < g->lib_search_paths.length; path_i += 1) { Buf *search_path = g->lib_search_paths.at(path_i); os_path_join(search_path, import_target_path, &full_path); @@ -2570,7 +2560,7 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path, auto entry = g->import_table.maybe_get(abs_full_path); if (entry) { found_it = true; - top_level_decl->codegen_node->data.import_node.import = entry->value; + top_level_decl->data.use.import = entry->value; } else { if ((err = os_fetch_file_path(abs_full_path, import_code))) { if (err == ErrorFileNotFound) { @@ -2582,7 +2572,7 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path, goto done_looking_at_imports; } } - top_level_decl->codegen_node->data.import_node.import = codegen_add_code(g, + top_level_decl->data.use.import = codegen_add_code(g, abs_full_path, search_path, &top_level_decl->data.use.path, import_code); found_it = true; } @@ -2682,9 +2672,8 @@ void codegen_add_root_code(CodeGen *g, Buf *src_dir, Buf *src_basename, Buf *sou static void to_c_type(CodeGen *g, AstNode *type_node, Buf *out_buf) { assert(type_node->type == NodeTypeType); - assert(type_node->codegen_node); - TypeTableEntry *type_entry = type_node->codegen_node->data.type_node.entry; + TypeTableEntry *type_entry = type_node->data.type.entry; assert(type_entry); if (type_entry == g->builtin_types.entry_u8) { diff --git a/src/codegen.hpp b/src/codegen.hpp index 18baaa27ae..b7cf9097d3 100644 --- a/src/codegen.hpp +++ b/src/codegen.hpp @@ -11,21 +11,8 @@ #include "parser.hpp" #include "errmsg.hpp" -struct CodeGen; - -enum OutType { - OutTypeUnknown, - OutTypeExe, - OutTypeLib, - OutTypeObj, -}; - CodeGen *codegen_create(Buf *root_source_dir); -enum CodeGenBuildType { - CodeGenBuildTypeDebug, - CodeGenBuildTypeRelease, -}; void codegen_set_build_type(CodeGen *codegen, CodeGenBuildType build_type); void codegen_set_is_static(CodeGen *codegen, bool is_static); void codegen_set_strip(CodeGen *codegen, bool strip); diff --git a/src/parser.cpp b/src/parser.cpp index bcdb58b545..b791902366 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -356,8 +356,7 @@ void ast_print(AstNode *node, int indent) { fprintf(stderr, "Unreachable\n"); break; case NodeTypeSymbol: - fprintf(stderr, "Symbol %s\n", - buf_ptr(&node->data.symbol)); + fprintf(stderr, "Symbol %s\n", buf_ptr(&node->data.symbol_expr.symbol)); break; case NodeTypeUse: fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.use.path)); @@ -366,7 +365,8 @@ void ast_print(AstNode *node, int indent) { fprintf(stderr, "%s\n", node_type_str(node->type)); break; case NodeTypeBoolLiteral: - fprintf(stderr, "%s '%s'\n", node_type_str(node->type), node->data.bool_literal ? "true" : "false"); + fprintf(stderr, "%s '%s'\n", node_type_str(node->type), + node->data.bool_literal.value ? "true" : "false"); break; case NodeTypeNullLiteral: fprintf(stderr, "%s\n", node_type_str(node->type)); @@ -401,7 +401,7 @@ void ast_print(AstNode *node, int indent) { fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.label.name)); break; case NodeTypeGoto: - fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.go_to.name)); + fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.goto_expr.name)); break; case NodeTypeBreak: fprintf(stderr, "%s\n", node_type_str(node->type)); @@ -1369,12 +1369,12 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool return node; } else if (token->id == TokenIdKeywordTrue) { AstNode *node = ast_create_node(pc, NodeTypeBoolLiteral, token); - node->data.bool_literal = true; + node->data.bool_literal.value = true; *token_index += 1; return node; } else if (token->id == TokenIdKeywordFalse) { AstNode *node = ast_create_node(pc, NodeTypeBoolLiteral, token); - node->data.bool_literal = false; + node->data.bool_literal.value = false; *token_index += 1; return node; } else if (token->id == TokenIdKeywordNull) { @@ -1385,7 +1385,7 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool *token_index += 1; Token *name_tok = ast_eat_token(pc, token_index, TokenIdSymbol); AstNode *name_node = ast_create_node(pc, NodeTypeSymbol, name_tok); - ast_buf_from_token(pc, name_tok, &name_node->data.symbol); + ast_buf_from_token(pc, name_tok, &name_node->data.symbol_expr.symbol); AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, token); node->data.fn_call_expr.fn_ref_expr = name_node; @@ -1401,7 +1401,7 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool } else { *token_index += 1; AstNode *node = ast_create_node(pc, NodeTypeSymbol, token); - ast_buf_from_token(pc, token, &node->data.symbol); + ast_buf_from_token(pc, token, &node->data.symbol_expr.symbol); return node; } } else if (token->id == TokenIdKeywordGoto) { @@ -1412,7 +1412,7 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool *token_index += 1; ast_expect_token(pc, dest_symbol, TokenIdSymbol); - ast_buf_from_token(pc, dest_symbol, &node->data.go_to.name); + ast_buf_from_token(pc, dest_symbol, &node->data.goto_expr.name); return node; } else if (token->id == TokenIdKeywordBreak) { AstNode *node = ast_create_node(pc, NodeTypeBreak, token); diff --git a/src/parser.hpp b/src/parser.hpp index a0b6555664..debe406594 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -8,450 +8,10 @@ #ifndef ZIG_PARSER_HPP #define ZIG_PARSER_HPP -#include "list.hpp" -#include "buffer.hpp" +#include "all_types.hpp" #include "tokenizer.hpp" #include "errmsg.hpp" -struct AstNode; -struct CodeGenNode; -struct ImportTableEntry; -struct AsmToken; - -enum NodeType { - NodeTypeRoot, - NodeTypeRootExportDecl, - NodeTypeFnProto, - NodeTypeFnDef, - NodeTypeFnDecl, - NodeTypeParamDecl, - NodeTypeType, - NodeTypeBlock, - NodeTypeExternBlock, - NodeTypeDirective, - NodeTypeReturnExpr, - NodeTypeVariableDeclaration, - NodeTypeBinOpExpr, - NodeTypeCastExpr, - NodeTypeNumberLiteral, - NodeTypeStringLiteral, - NodeTypeCharLiteral, - NodeTypeUnreachable, - NodeTypeSymbol, - NodeTypePrefixOpExpr, - NodeTypeFnCallExpr, - NodeTypeArrayAccessExpr, - NodeTypeSliceExpr, - NodeTypeFieldAccessExpr, - NodeTypeUse, - NodeTypeVoid, - NodeTypeBoolLiteral, - NodeTypeNullLiteral, - NodeTypeIfBoolExpr, - NodeTypeIfVarExpr, - NodeTypeWhileExpr, - NodeTypeLabel, - NodeTypeGoto, - NodeTypeBreak, - NodeTypeContinue, - NodeTypeAsmExpr, - NodeTypeStructDecl, - NodeTypeStructField, - NodeTypeStructValueExpr, - NodeTypeStructValueField, - NodeTypeEnumDecl, - NodeTypeEnumField, - NodeTypeCompilerFnExpr, - NodeTypeCompilerFnType, -}; - -struct AstNodeRoot { - ZigList top_level_decls; -}; - -enum VisibMod { - VisibModPrivate, - VisibModPub, - VisibModExport, -}; - -struct AstNodeFnProto { - ZigList *directives; - VisibMod visib_mod; - Buf name; - ZigList params; - AstNode *return_type; - bool is_var_args; - - // the extern block this fn proto is inside. can be null. - // populated by semantic analyzer. - AstNode *extern_node; - // the struct decl node this fn proto is inside. can be null. - // populated by semantic analyzer. - AstNode *struct_node; - // the function definition this fn proto is inside. can be null. - // populated by semantic analyzer. - AstNode *fn_def_node; -}; - -struct AstNodeFnDef { - AstNode *fn_proto; - AstNode *body; -}; - -struct AstNodeFnDecl { - AstNode *fn_proto; -}; - -struct AstNodeParamDecl { - Buf name; - AstNode *type; -}; - -enum AstNodeTypeType { - AstNodeTypeTypePrimitive, - AstNodeTypeTypePointer, - AstNodeTypeTypeArray, - AstNodeTypeTypeMaybe, - AstNodeTypeTypeCompilerExpr, -}; - -struct AstNodeType { - AstNodeTypeType type; - Buf primitive_name; - AstNode *child_type; - AstNode *array_size; // can be null - bool is_const; - bool is_noalias; - AstNode *compiler_expr; -}; - -struct AstNodeBlock { - ZigList statements; -}; - -struct AstNodeReturnExpr { - // might be null in case of return void; - AstNode *expr; -}; - -struct AstNodeVariableDeclaration { - Buf symbol; - bool is_const; - VisibMod visib_mod; - // one or both of type and expr will be non null - AstNode *type; - AstNode *expr; -}; - -enum BinOpType { - BinOpTypeInvalid, - BinOpTypeAssign, - BinOpTypeAssignTimes, - BinOpTypeAssignDiv, - BinOpTypeAssignMod, - BinOpTypeAssignPlus, - BinOpTypeAssignMinus, - BinOpTypeAssignBitShiftLeft, - BinOpTypeAssignBitShiftRight, - BinOpTypeAssignBitAnd, - BinOpTypeAssignBitXor, - BinOpTypeAssignBitOr, - BinOpTypeAssignBoolAnd, - BinOpTypeAssignBoolOr, - BinOpTypeBoolOr, - BinOpTypeBoolAnd, - BinOpTypeCmpEq, - BinOpTypeCmpNotEq, - BinOpTypeCmpLessThan, - BinOpTypeCmpGreaterThan, - BinOpTypeCmpLessOrEq, - BinOpTypeCmpGreaterOrEq, - BinOpTypeBinOr, - BinOpTypeBinXor, - BinOpTypeBinAnd, - BinOpTypeBitShiftLeft, - BinOpTypeBitShiftRight, - BinOpTypeAdd, - BinOpTypeSub, - BinOpTypeMult, - BinOpTypeDiv, - BinOpTypeMod, - BinOpTypeUnwrapMaybe, -}; - -struct AstNodeBinOpExpr { - AstNode *op1; - BinOpType bin_op; - AstNode *op2; -}; - -struct AstNodeFnCallExpr { - AstNode *fn_ref_expr; - ZigList params; - bool is_builtin; -}; - -struct AstNodeArrayAccessExpr { - AstNode *array_ref_expr; - AstNode *subscript; -}; - -struct AstNodeSliceExpr { - AstNode *array_ref_expr; - AstNode *start; - AstNode *end; - bool is_const; -}; - -struct AstNodeFieldAccessExpr { - AstNode *struct_expr; - Buf field_name; -}; - -struct AstNodeExternBlock { - ZigList *directives; - ZigList fn_decls; -}; - -struct AstNodeDirective { - Buf name; - Buf param; -}; - -struct AstNodeRootExportDecl { - Buf type; - Buf name; - ZigList *directives; -}; - -struct AstNodeCastExpr { - AstNode *expr; - AstNode *type; -}; - -enum PrefixOp { - PrefixOpInvalid, - PrefixOpBoolNot, - PrefixOpBinNot, - PrefixOpNegation, - PrefixOpAddressOf, - PrefixOpConstAddressOf, - PrefixOpDereference, -}; - -struct AstNodePrefixOpExpr { - PrefixOp prefix_op; - AstNode *primary_expr; -}; - -struct AstNodeUse { - Buf path; - ZigList *directives; -}; - -struct AstNodeIfBoolExpr { - AstNode *condition; - AstNode *then_block; - AstNode *else_node; // null, block node, or other if expr node -}; - -struct AstNodeIfVarExpr { - AstNodeVariableDeclaration var_decl; - AstNode *then_block; - AstNode *else_node; // null, block node, or other if expr node -}; - -struct AstNodeWhileExpr { - AstNode *condition; - AstNode *body; -}; - -struct AstNodeLabel { - Buf name; -}; - -struct AstNodeGoto { - Buf name; -}; - -struct AsmOutput { - Buf asm_symbolic_name; - Buf constraint; - Buf variable_name; - AstNode *return_type; // null unless "=r" and return -}; - -struct AsmInput { - Buf asm_symbolic_name; - Buf constraint; - AstNode *expr; -}; - -struct SrcPos { - int line; - int column; -}; - -struct AstNodeAsmExpr { - bool is_volatile; - Buf asm_template; - ZigList offset_map; - ZigList token_list; - ZigList output_list; - ZigList input_list; - ZigList clobber_list; - int return_count; // populated by analyze -}; - -struct AstNodeStructDecl { - Buf name; - ZigList fields; - ZigList fns; - ZigList *directives; - VisibMod visib_mod; -}; - -struct AstNodeStructField { - Buf name; - AstNode *type; - ZigList *directives; -}; - -struct AstNodeEnumDecl { - Buf name; - ZigList fields; - ZigList *directives; - VisibMod visib_mod; -}; - -struct AstNodeEnumField { - Buf name; - ZigList fields; // length 0 means simple enum - AstNode *val_expr; -}; - -struct AstNodeStringLiteral { - Buf buf; - bool c; -}; - -struct AstNodeCharLiteral { - uint8_t value; -}; - -enum NumLit { - NumLitF32, - NumLitF64, - NumLitF128, - NumLitU8, - NumLitU16, - NumLitU32, - NumLitU64, - NumLitI8, - NumLitI16, - NumLitI32, - NumLitI64, - - NumLitCount -}; - -struct AstNodeNumberLiteral { - NumLit kind; - - // overflow is true if when parsing the number, we discovered it would not - // fit without losing data in a uint64_t, int64_t, or double - bool overflow; - - union { - uint64_t x_uint; - int64_t x_int; - double x_float; - } data; -}; - -struct AstNodeStructValueField { - Buf name; - AstNode *expr; -}; - -struct AstNodeStructValueExpr { - AstNode *type; - ZigList fields; -}; - -struct AstNodeCompilerFnExpr { - Buf name; - AstNode *expr; -}; - -struct AstNodeCompilerFnType { - Buf name; - AstNode *type; -}; - -struct AstNode { - enum NodeType type; - int line; - int column; - uint32_t create_index; // for determinism purposes - CodeGenNode *codegen_node; - ImportTableEntry *owner; - union { - AstNodeRoot root; - AstNodeRootExportDecl root_export_decl; - AstNodeFnDef fn_def; - AstNodeFnDecl fn_decl; - AstNodeFnProto fn_proto; - AstNodeType type; - AstNodeParamDecl param_decl; - AstNodeBlock block; - AstNodeReturnExpr return_expr; - AstNodeVariableDeclaration variable_declaration; - AstNodeBinOpExpr bin_op_expr; - AstNodeExternBlock extern_block; - AstNodeDirective directive; - AstNodeCastExpr cast_expr; - AstNodePrefixOpExpr prefix_op_expr; - AstNodeFnCallExpr fn_call_expr; - AstNodeArrayAccessExpr array_access_expr; - AstNodeSliceExpr slice_expr; - AstNodeUse use; - AstNodeIfBoolExpr if_bool_expr; - AstNodeIfVarExpr if_var_expr; - AstNodeWhileExpr while_expr; - AstNodeLabel label; - AstNodeGoto go_to; - AstNodeAsmExpr asm_expr; - AstNodeFieldAccessExpr field_access_expr; - AstNodeStructDecl struct_decl; - AstNodeStructField struct_field; - AstNodeEnumDecl enum_decl; - AstNodeEnumField enum_field; - AstNodeStringLiteral string_literal; - AstNodeCharLiteral char_literal; - AstNodeNumberLiteral number_literal; - AstNodeStructValueExpr struct_val_expr; - AstNodeStructValueField struct_val_field; - AstNodeCompilerFnExpr compiler_fn_expr; - AstNodeCompilerFnType compiler_fn_type; - Buf symbol; - bool bool_literal; - } data; -}; - -enum AsmTokenId { - AsmTokenIdTemplate, - AsmTokenIdPercent, - AsmTokenIdVar, -}; - -struct AsmToken { - enum AsmTokenId id; - int start; - int end; -}; - __attribute__ ((format (printf, 2, 3))) void ast_token_error(Token *token, const char *format, ...);