| author | |
| committer | |
| log | 75efc313299af89c69c5f2b4a7c2758753ed36c3 |
| tree | 6bee1174842149ad36378a8c241b760af4db77df |
| parent | 2f0e4e9cb26df7a6f6251d0e865d0d964680831e |
9 files changed, 379 insertions(+), 254 deletions(-)
README.md+9-3| ... | ... | @@ -64,6 +64,8 @@ compromises backward compatibility. |
| 64 | 64 | * main function with command line arguments |
| 65 | 65 | * void pointer constant |
| 66 | 66 | * sizeof |
| 67 | * address of operator | |
| 68 | * global variables | |
| 67 | 69 | * static initializers |
| 68 | 70 | * assert |
| 69 | 71 | * function pointers |
| ... | ... | @@ -202,9 +204,13 @@ MultiplyOperator : token(Star) | token(Slash) | token(Percent) |
| 202 | 204 | |
| 203 | 205 | CastExpression : PrefixOpExpression token(as) Type | PrefixOpExpression |
| 204 | 206 | |
| 205 | PrefixOpExpression : PrefixOp FnCallExpression | FnCallExpression | |
| 207 | PrefixOpExpression : PrefixOp SuffixOpExpression | SuffixOpExpression | |
| 206 | 208 | |
| 207 | FnCallExpression : PrimaryExpression token(LParen) list(Expression, token(Comma)) token(RParen) | PrimaryExpression | |
| 209 | SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression) | |
| 210 | ||
| 211 | FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen) | |
| 212 | ||
| 213 | ArrayAccessExpression : token(LBracket) Expression token(RBracket) | |
| 208 | 214 | |
| 209 | 215 | PrefixOp : token(Not) | token(Dash) | token(Tilde) |
| 210 | 216 | |
| ... | ... | @@ -220,7 +226,7 @@ KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False) |
| 220 | 226 | ## Operator Precedence |
| 221 | 227 | |
| 222 | 228 | ``` |
| 223 | x() | |
| 229 | x() x[] | |
| 224 | 230 | !x -x ~x |
| 225 | 231 | as |
| 226 | 232 | * / % |
example/arrays/arrays.zig created+16| ... | ... | @@ -0,0 +1,16 @@ |
| 1 | export executable "arrays"; | |
| 2 | ||
| 3 | #link("c") | |
| 4 | extern { | |
| 5 | fn puts(s: *const u8) -> i32; | |
| 6 | fn exit(code: i32) -> unreachable; | |
| 7 | } | |
| 8 | ||
| 9 | export fn _start() -> unreachable { | |
| 10 | let mut array : [i32; 10]; | |
| 11 | ||
| 12 | array[4] = array[1] + 5; | |
| 13 | ||
| 14 | ||
| 15 | exit(0); | |
| 16 | } |
src/analyze.cpp+64-7| ... | ... | @@ -6,11 +6,45 @@ |
| 6 | 6 | */ |
| 7 | 7 | |
| 8 | 8 | #include "analyze.hpp" |
| 9 | #include "semantic_info.hpp" | |
| 10 | 9 | #include "error.hpp" |
| 11 | 10 | #include "zig_llvm.hpp" |
| 12 | 11 | #include "os.hpp" |
| 13 | 12 | |
| 13 | static AstNode *first_executing_node(AstNode *node) { | |
| 14 | switch (node->type) { | |
| 15 | case NodeTypeFnCallExpr: | |
| 16 | return first_executing_node(node->data.fn_call_expr.fn_ref_expr); | |
| 17 | case NodeTypeRoot: | |
| 18 | case NodeTypeRootExportDecl: | |
| 19 | case NodeTypeFnProto: | |
| 20 | case NodeTypeFnDef: | |
| 21 | case NodeTypeFnDecl: | |
| 22 | case NodeTypeParamDecl: | |
| 23 | case NodeTypeType: | |
| 24 | case NodeTypeBlock: | |
| 25 | case NodeTypeExternBlock: | |
| 26 | case NodeTypeDirective: | |
| 27 | case NodeTypeReturnExpr: | |
| 28 | case NodeTypeVariableDeclaration: | |
| 29 | case NodeTypeBinOpExpr: | |
| 30 | case NodeTypeCastExpr: | |
| 31 | case NodeTypeNumberLiteral: | |
| 32 | case NodeTypeStringLiteral: | |
| 33 | case NodeTypeUnreachable: | |
| 34 | case NodeTypeSymbol: | |
| 35 | case NodeTypePrefixOpExpr: | |
| 36 | case NodeTypeArrayAccessExpr: | |
| 37 | case NodeTypeUse: | |
| 38 | case NodeTypeVoid: | |
| 39 | case NodeTypeBoolLiteral: | |
| 40 | case NodeTypeIfExpr: | |
| 41 | case NodeTypeLabel: | |
| 42 | case NodeTypeGoto: | |
| 43 | return node; | |
| 44 | } | |
| 45 | zig_panic("unreachable"); | |
| 46 | } | |
| 47 | ||
| 14 | 48 | void add_node_error(CodeGen *g, AstNode *node, Buf *msg) { |
| 15 | 49 | ErrorMsg *err = allocate<ErrorMsg>(1); |
| 16 | 50 | err->line_start = node->line; |
| ... | ... | @@ -48,9 +82,10 @@ static void set_root_export_version(CodeGen *g, Buf *version_buf, AstNode *node) |
| 48 | 82 | } |
| 49 | 83 | } |
| 50 | 84 | |
| 51 | TypeTableEntry *new_type_table_entry() { | |
| 85 | TypeTableEntry *new_type_table_entry(TypeTableEntryId id) { | |
| 52 | 86 | TypeTableEntry *entry = allocate<TypeTableEntry>(1); |
| 53 | 87 | entry->arrays_by_size.init(2); |
| 88 | entry->id = id; | |
| 54 | 89 | return entry; |
| 55 | 90 | } |
| 56 | 91 | |
| ... | ... | @@ -61,7 +96,7 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool |
| 61 | 96 | if (*parent_pointer) { |
| 62 | 97 | return *parent_pointer; |
| 63 | 98 | } else { |
| 64 | TypeTableEntry *entry = new_type_table_entry(); | |
| 99 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPointer); | |
| 65 | 100 | entry->type_ref = LLVMPointerType(child_type->type_ref, 0); |
| 66 | 101 | buf_resize(&entry->name, 0); |
| 67 | 102 | buf_appendf(&entry->name, "*%s %s", is_const ? "const" : "mut", buf_ptr(&child_type->name)); |
| ... | ... | @@ -80,7 +115,7 @@ static TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, in |
| 80 | 115 | if (existing_entry) { |
| 81 | 116 | return existing_entry->value; |
| 82 | 117 | } else { |
| 83 | TypeTableEntry *entry = new_type_table_entry(); | |
| 118 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArray); | |
| 84 | 119 | entry->type_ref = LLVMArrayType(child_type->type_ref, array_size); |
| 85 | 120 | buf_resize(&entry->name, 0); |
| 86 | 121 | buf_appendf(&entry->name, "[%s; %d]", buf_ptr(&child_type->name), array_size); |
| ... | ... | @@ -357,6 +392,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, |
| 357 | 392 | case NodeTypeBlock: |
| 358 | 393 | case NodeTypeBinOpExpr: |
| 359 | 394 | case NodeTypeFnCallExpr: |
| 395 | case NodeTypeArrayAccessExpr: | |
| 360 | 396 | case NodeTypeNumberLiteral: |
| 361 | 397 | case NodeTypeStringLiteral: |
| 362 | 398 | case NodeTypeUnreachable: |
| ... | ... | @@ -466,7 +502,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 466 | 502 | // ignore void statements once we enter unreachable land. |
| 467 | 503 | continue; |
| 468 | 504 | } |
| 469 | add_node_error(g, child, buf_sprintf("unreachable code")); | |
| 505 | add_node_error(g, first_executing_node(child), buf_sprintf("unreachable code")); | |
| 470 | 506 | break; |
| 471 | 507 | } |
| 472 | 508 | return_type = analyze_expression(g, import, child_context, nullptr, child); |
| ... | ... | @@ -641,14 +677,21 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 641 | 677 | |
| 642 | 678 | case NodeTypeFnCallExpr: |
| 643 | 679 | { |
| 644 | Buf *name = hack_get_fn_call_name(g, node->data.fn_call_expr.fn_ref_expr); | |
| 680 | AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; | |
| 681 | if (fn_ref_expr->type != NodeTypeSymbol) { | |
| 682 | add_node_error(g, node, | |
| 683 | buf_sprintf("function pointers not allowed")); | |
| 684 | break; | |
| 685 | } | |
| 686 | ||
| 687 | Buf *name = &fn_ref_expr->data.symbol; | |
| 645 | 688 | |
| 646 | 689 | auto entry = import->fn_table.maybe_get(name); |
| 647 | 690 | if (!entry) |
| 648 | 691 | entry = g->fn_table.maybe_get(name); |
| 649 | 692 | |
| 650 | 693 | if (!entry) { |
| 651 | add_node_error(g, node, | |
| 694 | add_node_error(g, fn_ref_expr, | |
| 652 | 695 | buf_sprintf("undefined function: '%s'", buf_ptr(name))); |
| 653 | 696 | // still analyze the parameters, even though we don't know what to expect |
| 654 | 697 | for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { |
| ... | ... | @@ -691,6 +734,19 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 691 | 734 | break; |
| 692 | 735 | } |
| 693 | 736 | |
| 737 | case NodeTypeArrayAccessExpr: | |
| 738 | { | |
| 739 | // here we are always reading the array | |
| 740 | TypeTableEntry *lhs_type = analyze_expression(g, import, context, nullptr, | |
| 741 | node->data.array_access_expr.array_ref_expr); | |
| 742 | if (lhs_type->id == TypeTableEntryIdArray) { | |
| 743 | zig_panic("TODO"); | |
| 744 | } else { | |
| 745 | add_node_error(g, node, buf_sprintf("array access of non-array")); | |
| 746 | } | |
| 747 | ||
| 748 | break; | |
| 749 | } | |
| 694 | 750 | case NodeTypeNumberLiteral: |
| 695 | 751 | // TODO: generic literal int type |
| 696 | 752 | return_type = g->builtin_types.entry_i32; |
| ... | ... | @@ -897,6 +953,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, |
| 897 | 953 | case NodeTypeBlock: |
| 898 | 954 | case NodeTypeBinOpExpr: |
| 899 | 955 | case NodeTypeFnCallExpr: |
| 956 | case NodeTypeArrayAccessExpr: | |
| 900 | 957 | case NodeTypeNumberLiteral: |
| 901 | 958 | case NodeTypeStringLiteral: |
| 902 | 959 | case NodeTypeUnreachable: |
src/analyze.hpp+205-6| ... | ... | @@ -8,17 +8,216 @@ |
| 8 | 8 | #ifndef ZIG_ANALYZE_HPP |
| 9 | 9 | #define ZIG_ANALYZE_HPP |
| 10 | 10 | |
| 11 | struct CodeGen; | |
| 12 | struct AstNode; | |
| 13 | struct Buf; | |
| 11 | #include "codegen.hpp" | |
| 12 | #include "hash_map.hpp" | |
| 13 | #include "zig_llvm.hpp" | |
| 14 | #include "errmsg.hpp" | |
| 14 | 15 | |
| 15 | struct TypeTableEntry; | |
| 16 | struct LocalVariableTableEntry; | |
| 16 | struct FnTableEntry; | |
| 17 | 17 | struct BlockContext; |
| 18 | struct TypeTableEntry; | |
| 19 | ||
| 20 | struct TypeTableEntryPointer { | |
| 21 | TypeTableEntry *pointer_child; | |
| 22 | bool pointer_is_const; | |
| 23 | }; | |
| 24 | ||
| 25 | struct TypeTableEntryInt { | |
| 26 | bool is_signed; | |
| 27 | }; | |
| 28 | ||
| 29 | enum TypeTableEntryId { | |
| 30 | TypeTableEntryIdInvalid, | |
| 31 | TypeTableEntryIdVoid, | |
| 32 | TypeTableEntryIdBool, | |
| 33 | TypeTableEntryIdUnreachable, | |
| 34 | TypeTableEntryIdInt, | |
| 35 | TypeTableEntryIdFloat, | |
| 36 | TypeTableEntryIdPointer, | |
| 37 | TypeTableEntryIdArray, | |
| 38 | }; | |
| 39 | ||
| 40 | struct TypeTableEntry { | |
| 41 | TypeTableEntryId id; | |
| 42 | ||
| 43 | LLVMTypeRef type_ref; | |
| 44 | LLVMZigDIType *di_type; | |
| 45 | uint64_t size_in_bits; | |
| 46 | uint64_t align_in_bits; | |
| 47 | ||
| 48 | Buf name; | |
| 49 | ||
| 50 | union { | |
| 51 | TypeTableEntryPointer pointer; | |
| 52 | TypeTableEntryInt integral; | |
| 53 | } data; | |
| 54 | ||
| 55 | // use these fields to make sure we don't duplicate type table entries for the same type | |
| 56 | TypeTableEntry *pointer_const_parent; | |
| 57 | TypeTableEntry *pointer_mut_parent; | |
| 58 | HashMap<int, TypeTableEntry *, int_hash, int_eq> arrays_by_size; | |
| 59 | ||
| 60 | }; | |
| 61 | ||
| 62 | struct ImportTableEntry { | |
| 63 | AstNode *root; | |
| 64 | Buf *path; // relative to root_source_dir | |
| 65 | LLVMZigDIFile *di_file; | |
| 66 | Buf *source_code; | |
| 67 | ZigList<int> *line_offsets; | |
| 68 | ||
| 69 | // reminder: hash tables must be initialized before use | |
| 70 | HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table; | |
| 71 | }; | |
| 72 | ||
| 73 | struct LabelTableEntry { | |
| 74 | AstNode *label_node; | |
| 75 | LLVMBasicBlockRef basic_block; | |
| 76 | bool used; | |
| 77 | bool entered_from_fallthrough; | |
| 78 | }; | |
| 79 | ||
| 80 | struct FnTableEntry { | |
| 81 | LLVMValueRef fn_value; | |
| 82 | AstNode *proto_node; | |
| 83 | AstNode *fn_def_node; | |
| 84 | bool is_extern; | |
| 85 | bool internal_linkage; | |
| 86 | unsigned calling_convention; | |
| 87 | ImportTableEntry *import_entry; | |
| 88 | ||
| 89 | // reminder: hash tables must be initialized before use | |
| 90 | HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table; | |
| 91 | }; | |
| 92 | ||
| 93 | struct CodeGen { | |
| 94 | LLVMModuleRef module; | |
| 95 | ZigList<ErrorMsg*> errors; | |
| 96 | LLVMBuilderRef builder; | |
| 97 | LLVMZigDIBuilder *dbuilder; | |
| 98 | LLVMZigDICompileUnit *compile_unit; | |
| 99 | ||
| 100 | // reminder: hash tables must be initialized before use | |
| 101 | HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table; | |
| 102 | HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table; | |
| 103 | HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table; | |
| 104 | HashMap<Buf *, bool, buf_hash, buf_eql_buf> link_table; | |
| 105 | HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table; | |
| 106 | ||
| 107 | struct { | |
| 108 | TypeTableEntry *entry_bool; | |
| 109 | TypeTableEntry *entry_u8; | |
| 110 | TypeTableEntry *entry_i32; | |
| 111 | TypeTableEntry *entry_f32; | |
| 112 | TypeTableEntry *entry_string_literal; | |
| 113 | TypeTableEntry *entry_void; | |
| 114 | TypeTableEntry *entry_unreachable; | |
| 115 | TypeTableEntry *entry_invalid; | |
| 116 | } builtin_types; | |
| 117 | ||
| 118 | LLVMTargetDataRef target_data_ref; | |
| 119 | unsigned pointer_size_bytes; | |
| 120 | bool is_static; | |
| 121 | bool strip_debug_symbols; | |
| 122 | CodeGenBuildType build_type; | |
| 123 | LLVMTargetMachineRef target_machine; | |
| 124 | bool is_native_target; | |
| 125 | Buf *root_source_dir; | |
| 126 | Buf *root_out_name; | |
| 127 | ||
| 128 | // The function definitions this module includes. There must be a corresponding | |
| 129 | // fn_protos entry. | |
| 130 | ZigList<FnTableEntry *> fn_defs; | |
| 131 | // The function prototypes this module includes. In the case of external declarations, | |
| 132 | // there will not be a corresponding fn_defs entry. | |
| 133 | ZigList<FnTableEntry *> fn_protos; | |
| 134 | ||
| 135 | OutType out_type; | |
| 136 | FnTableEntry *cur_fn; | |
| 137 | LLVMBasicBlockRef cur_basic_block; | |
| 138 | BlockContext *cur_block_context; | |
| 139 | bool c_stdint_used; | |
| 140 | AstNode *root_export_decl; | |
| 141 | int version_major; | |
| 142 | int version_minor; | |
| 143 | int version_patch; | |
| 144 | bool verbose; | |
| 145 | ErrColor err_color; | |
| 146 | ImportTableEntry *root_import; | |
| 147 | }; | |
| 148 | ||
| 149 | struct LocalVariableTableEntry { | |
| 150 | Buf name; | |
| 151 | TypeTableEntry *type; | |
| 152 | LLVMValueRef value_ref; | |
| 153 | bool is_const; | |
| 154 | bool is_ptr; // if true, value_ref is a pointer | |
| 155 | AstNode *decl_node; | |
| 156 | LLVMZigDILocalVariable *di_loc_var; | |
| 157 | int arg_index; | |
| 158 | }; | |
| 159 | ||
| 160 | struct BlockContext { | |
| 161 | AstNode *node; // either NodeTypeFnDef or NodeTypeBlock | |
| 162 | BlockContext *root; // always points to the BlockContext with the NodeTypeFnDef | |
| 163 | BlockContext *parent; // nullptr when this is the root | |
| 164 | HashMap<Buf *, LocalVariableTableEntry *, buf_hash, buf_eql_buf> variable_table; | |
| 165 | LLVMZigDIScope *di_scope; | |
| 166 | }; | |
| 167 | ||
| 168 | struct TypeNode { | |
| 169 | TypeTableEntry *entry; | |
| 170 | }; | |
| 171 | ||
| 172 | struct FnProtoNode { | |
| 173 | FnTableEntry *fn_table_entry; | |
| 174 | }; | |
| 175 | ||
| 176 | struct FnDefNode { | |
| 177 | TypeTableEntry *implicit_return_type; | |
| 178 | BlockContext *block_context; | |
| 179 | bool skip; | |
| 180 | // Required to be a pre-order traversal of the AST. (parents must come before children) | |
| 181 | ZigList<BlockContext *> all_block_contexts; | |
| 182 | }; | |
| 183 | ||
| 184 | struct ExprNode { | |
| 185 | TypeTableEntry *type_entry; | |
| 186 | // the context in which this expression is evaluated. | |
| 187 | // for blocks, this points to the containing scope, not the block's own scope for its children. | |
| 188 | BlockContext *block_context; | |
| 189 | }; | |
| 190 | ||
| 191 | struct AssignNode { | |
| 192 | LocalVariableTableEntry *var_entry; | |
| 193 | }; | |
| 194 | ||
| 195 | struct BlockNode { | |
| 196 | BlockContext *block_context; | |
| 197 | }; | |
| 198 | ||
| 199 | struct CodeGenNode { | |
| 200 | union { | |
| 201 | TypeNode type_node; // for NodeTypeType | |
| 202 | FnDefNode fn_def_node; // for NodeTypeFnDef | |
| 203 | FnProtoNode fn_proto_node; // for NodeTypeFnProto | |
| 204 | LabelTableEntry *label_entry; // for NodeTypeGoto and NodeTypeLabel | |
| 205 | AssignNode assign_node; // for NodeTypeBinOpExpr where op is BinOpTypeAssign | |
| 206 | BlockNode block_node; // for NodeTypeBlock | |
| 207 | } data; | |
| 208 | ExprNode expr_node; // for all the expression nodes | |
| 209 | }; | |
| 210 | ||
| 211 | static inline Buf *hack_get_fn_call_name(CodeGen *g, AstNode *node) { | |
| 212 | // Assume that the expression evaluates to a simple name and return the buf | |
| 213 | // TODO after type checking works we should be able to remove this hack | |
| 214 | assert(node->type == NodeTypeSymbol); | |
| 215 | return &node->data.symbol; | |
| 216 | } | |
| 18 | 217 | |
| 19 | 218 | void semantic_analyze(CodeGen *g); |
| 20 | 219 | void add_node_error(CodeGen *g, AstNode *node, Buf *msg); |
| 21 | TypeTableEntry *new_type_table_entry(); | |
| 220 | TypeTableEntry *new_type_table_entry(TypeTableEntryId id); | |
| 22 | 221 | TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const); |
| 23 | 222 | LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name); |
| 24 | 223 |
src/codegen.cpp+38-24| ... | ... | @@ -11,7 +11,6 @@ |
| 11 | 11 | #include "os.hpp" |
| 12 | 12 | #include "config.h" |
| 13 | 13 | #include "error.hpp" |
| 14 | #include "semantic_info.hpp" | |
| 15 | 14 | #include "analyze.hpp" |
| 16 | 15 | #include "errmsg.hpp" |
| 17 | 16 | |
| ... | ... | @@ -168,6 +167,12 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { |
| 168 | 167 | } |
| 169 | 168 | } |
| 170 | 169 | |
| 170 | static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node) { | |
| 171 | assert(node->type == NodeTypeArrayAccessExpr); | |
| 172 | ||
| 173 | zig_panic("TODO gen arary access"); | |
| 174 | } | |
| 175 | ||
| 171 | 176 | static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) { |
| 172 | 177 | assert(node->type == NodeTypePrefixOpExpr); |
| 173 | 178 | assert(node->data.prefix_op_expr.primary_expr); |
| ... | ... | @@ -229,49 +234,55 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) { |
| 229 | 234 | return LLVMBuildShl(g->builder, val1, val2, ""); |
| 230 | 235 | case BinOpTypeBitShiftRight: |
| 231 | 236 | add_debug_source_node(g, node); |
| 232 | if (op1_type->is_signed_int) { | |
| 237 | if (op1_type->id == TypeTableEntryIdInt) { | |
| 233 | 238 | return LLVMBuildAShr(g->builder, val1, val2, ""); |
| 234 | 239 | } else { |
| 235 | 240 | return LLVMBuildLShr(g->builder, val1, val2, ""); |
| 236 | 241 | } |
| 237 | 242 | case BinOpTypeAdd: |
| 238 | 243 | add_debug_source_node(g, node); |
| 239 | if (op1_type->is_float) { | |
| 244 | if (op1_type->id == TypeTableEntryIdFloat) { | |
| 240 | 245 | return LLVMBuildFAdd(g->builder, val1, val2, ""); |
| 241 | 246 | } else { |
| 242 | 247 | return LLVMBuildNSWAdd(g->builder, val1, val2, ""); |
| 243 | 248 | } |
| 244 | 249 | case BinOpTypeSub: |
| 245 | 250 | add_debug_source_node(g, node); |
| 246 | if (op1_type->is_float) { | |
| 251 | if (op1_type->id == TypeTableEntryIdFloat) { | |
| 247 | 252 | return LLVMBuildFSub(g->builder, val1, val2, ""); |
| 248 | 253 | } else { |
| 249 | 254 | return LLVMBuildNSWSub(g->builder, val1, val2, ""); |
| 250 | 255 | } |
| 251 | 256 | case BinOpTypeMult: |
| 252 | 257 | add_debug_source_node(g, node); |
| 253 | if (op1_type->is_float) { | |
| 258 | if (op1_type->id == TypeTableEntryIdFloat) { | |
| 254 | 259 | return LLVMBuildFMul(g->builder, val1, val2, ""); |
| 255 | 260 | } else { |
| 256 | 261 | return LLVMBuildNSWMul(g->builder, val1, val2, ""); |
| 257 | 262 | } |
| 258 | 263 | case BinOpTypeDiv: |
| 259 | 264 | add_debug_source_node(g, node); |
| 260 | if (op1_type->is_float) { | |
| 265 | if (op1_type->id == TypeTableEntryIdFloat) { | |
| 261 | 266 | return LLVMBuildFDiv(g->builder, val1, val2, ""); |
| 262 | } else if (op1_type->is_signed_int) { | |
| 263 | return LLVMBuildSDiv(g->builder, val1, val2, ""); | |
| 264 | 267 | } else { |
| 265 | return LLVMBuildUDiv(g->builder, val1, val2, ""); | |
| 268 | assert(op1_type->id == TypeTableEntryIdInt); | |
| 269 | if (op1_type->data.integral.is_signed) { | |
| 270 | return LLVMBuildSDiv(g->builder, val1, val2, ""); | |
| 271 | } else { | |
| 272 | return LLVMBuildUDiv(g->builder, val1, val2, ""); | |
| 273 | } | |
| 266 | 274 | } |
| 267 | 275 | case BinOpTypeMod: |
| 268 | 276 | add_debug_source_node(g, node); |
| 269 | if (op1_type->is_float) { | |
| 277 | if (op1_type->id == TypeTableEntryIdFloat) { | |
| 270 | 278 | return LLVMBuildFRem(g->builder, val1, val2, ""); |
| 271 | } else if (op1_type->is_signed_int) { | |
| 272 | return LLVMBuildSRem(g->builder, val1, val2, ""); | |
| 273 | 279 | } else { |
| 274 | return LLVMBuildURem(g->builder, val1, val2, ""); | |
| 280 | assert(op1_type->id == TypeTableEntryIdInt); | |
| 281 | if (op1_type->data.integral.is_signed) { | |
| 282 | return LLVMBuildSRem(g->builder, val1, val2, ""); | |
| 283 | } else { | |
| 284 | return LLVMBuildURem(g->builder, val1, val2, ""); | |
| 285 | } | |
| 275 | 286 | } |
| 276 | 287 | case BinOpTypeBoolOr: |
| 277 | 288 | case BinOpTypeBoolAnd: |
| ... | ... | @@ -337,11 +348,13 @@ static LLVMValueRef gen_cmp_expr(CodeGen *g, AstNode *node) { |
| 337 | 348 | assert(op1_type == op2_type); |
| 338 | 349 | |
| 339 | 350 | add_debug_source_node(g, node); |
| 340 | if (op1_type->is_float) { | |
| 351 | if (op1_type->id == TypeTableEntryIdFloat) { | |
| 341 | 352 | LLVMRealPredicate pred = cmp_op_to_real_predicate(node->data.bin_op_expr.bin_op); |
| 342 | 353 | return LLVMBuildFCmp(g->builder, pred, val1, val2, ""); |
| 343 | 354 | } else { |
| 344 | LLVMIntPredicate pred = cmp_op_to_int_predicate(node->data.bin_op_expr.bin_op, op1_type->is_signed_int); | |
| 355 | assert(op1_type->id == TypeTableEntryIdInt); | |
| 356 | LLVMIntPredicate pred = cmp_op_to_int_predicate(node->data.bin_op_expr.bin_op, | |
| 357 | op1_type->data.integral.is_signed); | |
| 345 | 358 | return LLVMBuildICmp(g->builder, pred, val1, val2, ""); |
| 346 | 359 | } |
| 347 | 360 | } |
| ... | ... | @@ -596,6 +609,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { |
| 596 | 609 | return gen_prefix_op_expr(g, node); |
| 597 | 610 | case NodeTypeFnCallExpr: |
| 598 | 611 | return gen_fn_call_expr(g, node); |
| 612 | case NodeTypeArrayAccessExpr: | |
| 613 | return gen_array_access_expr(g, node); | |
| 599 | 614 | case NodeTypeUnreachable: |
| 600 | 615 | add_debug_source_node(g, node); |
| 601 | 616 | return LLVMBuildUnreachable(g->builder); |
| ... | ... | @@ -865,12 +880,12 @@ static void do_code_gen(CodeGen *g) { |
| 865 | 880 | static void define_primitive_types(CodeGen *g) { |
| 866 | 881 | { |
| 867 | 882 | // if this type is anywhere in the AST, we should never hit codegen. |
| 868 | TypeTableEntry *entry = new_type_table_entry(); | |
| 883 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInvalid); | |
| 869 | 884 | buf_init_from_str(&entry->name, "(invalid)"); |
| 870 | 885 | g->builtin_types.entry_invalid = entry; |
| 871 | 886 | } |
| 872 | 887 | { |
| 873 | TypeTableEntry *entry = new_type_table_entry(); | |
| 888 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdBool); | |
| 874 | 889 | entry->type_ref = LLVMInt1Type(); |
| 875 | 890 | buf_init_from_str(&entry->name, "bool"); |
| 876 | 891 | entry->size_in_bits = 1; |
| ... | ... | @@ -882,7 +897,7 @@ static void define_primitive_types(CodeGen *g) { |
| 882 | 897 | g->builtin_types.entry_bool = entry; |
| 883 | 898 | } |
| 884 | 899 | { |
| 885 | TypeTableEntry *entry = new_type_table_entry(); | |
| 900 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); | |
| 886 | 901 | entry->type_ref = LLVMInt8Type(); |
| 887 | 902 | buf_init_from_str(&entry->name, "u8"); |
| 888 | 903 | entry->size_in_bits = 8; |
| ... | ... | @@ -895,12 +910,12 @@ static void define_primitive_types(CodeGen *g) { |
| 895 | 910 | } |
| 896 | 911 | g->builtin_types.entry_string_literal = get_pointer_to_type(g, g->builtin_types.entry_u8, true); |
| 897 | 912 | { |
| 898 | TypeTableEntry *entry = new_type_table_entry(); | |
| 913 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); | |
| 899 | 914 | entry->type_ref = LLVMInt32Type(); |
| 900 | 915 | buf_init_from_str(&entry->name, "i32"); |
| 901 | 916 | entry->size_in_bits = 32; |
| 902 | 917 | entry->align_in_bits = 32; |
| 903 | entry->is_signed_int = true; | |
| 918 | entry->data.integral.is_signed = true; | |
| 904 | 919 | entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), |
| 905 | 920 | entry->size_in_bits, entry->align_in_bits, |
| 906 | 921 | LLVMZigEncoding_DW_ATE_signed()); |
| ... | ... | @@ -908,12 +923,11 @@ static void define_primitive_types(CodeGen *g) { |
| 908 | 923 | g->builtin_types.entry_i32 = entry; |
| 909 | 924 | } |
| 910 | 925 | { |
| 911 | TypeTableEntry *entry = new_type_table_entry(); | |
| 926 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat); | |
| 912 | 927 | entry->type_ref = LLVMFloatType(); |
| 913 | 928 | buf_init_from_str(&entry->name, "f32"); |
| 914 | 929 | entry->size_in_bits = 32; |
| 915 | 930 | entry->align_in_bits = 32; |
| 916 | entry->is_float = true; | |
| 917 | 931 | entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), |
| 918 | 932 | entry->size_in_bits, entry->align_in_bits, |
| 919 | 933 | LLVMZigEncoding_DW_ATE_float()); |
| ... | ... | @@ -921,7 +935,7 @@ static void define_primitive_types(CodeGen *g) { |
| 921 | 935 | g->builtin_types.entry_f32 = entry; |
| 922 | 936 | } |
| 923 | 937 | { |
| 924 | TypeTableEntry *entry = new_type_table_entry(); | |
| 938 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdVoid); | |
| 925 | 939 | entry->type_ref = LLVMVoidType(); |
| 926 | 940 | buf_init_from_str(&entry->name, "void"); |
| 927 | 941 | entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), |
| ... | ... | @@ -931,7 +945,7 @@ static void define_primitive_types(CodeGen *g) { |
| 931 | 945 | g->builtin_types.entry_void = entry; |
| 932 | 946 | } |
| 933 | 947 | { |
| 934 | TypeTableEntry *entry = new_type_table_entry(); | |
| 948 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdUnreachable); | |
| 935 | 949 | entry->type_ref = LLVMVoidType(); |
| 936 | 950 | buf_init_from_str(&entry->name, "unreachable"); |
| 937 | 951 | entry->di_type = g->builtin_types.entry_void->di_type; |
src/parser.cpp+39-19| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | |
| 8 | 8 | #include "parser.hpp" |
| 9 | 9 | #include "errmsg.hpp" |
| 10 | #include "semantic_info.hpp" | |
| 10 | #include "analyze.hpp" | |
| 11 | 11 | |
| 12 | 12 | #include <stdarg.h> |
| 13 | 13 | #include <stdio.h> |
| ... | ... | @@ -70,6 +70,8 @@ const char *node_type_str(NodeType node_type) { |
| 70 | 70 | return "BinOpExpr"; |
| 71 | 71 | case NodeTypeFnCallExpr: |
| 72 | 72 | return "FnCallExpr"; |
| 73 | case NodeTypeArrayAccessExpr: | |
| 74 | return "ArrayAccessExpr"; | |
| 73 | 75 | case NodeTypeExternBlock: |
| 74 | 76 | return "ExternBlock"; |
| 75 | 77 | case NodeTypeDirective: |
| ... | ... | @@ -231,6 +233,11 @@ void ast_print(AstNode *node, int indent) { |
| 231 | 233 | ast_print(child, indent + 2); |
| 232 | 234 | } |
| 233 | 235 | break; |
| 236 | case NodeTypeArrayAccessExpr: | |
| 237 | fprintf(stderr, "%s\n", node_type_str(node->type)); | |
| 238 | ast_print(node->data.array_access_expr.array_ref_expr, indent + 2); | |
| 239 | ast_print(node->data.array_access_expr.subscript, indent + 2); | |
| 240 | break; | |
| 234 | 241 | case NodeTypeDirective: |
| 235 | 242 | fprintf(stderr, "%s\n", node_type_str(node->type)); |
| 236 | 243 | break; |
| ... | ... | @@ -566,10 +573,6 @@ static void ast_parse_param_decl_list(ParseContext *pc, int token_index, int *ne |
| 566 | 573 | static void ast_parse_fn_call_param_list(ParseContext *pc, int token_index, int *new_token_index, |
| 567 | 574 | ZigList<AstNode*> *params) |
| 568 | 575 | { |
| 569 | Token *l_paren = &pc->tokens->at(token_index); | |
| 570 | token_index += 1; | |
| 571 | ast_expect_token(pc, l_paren, TokenIdLParen); | |
| 572 | ||
| 573 | 576 | Token *token = &pc->tokens->at(token_index); |
| 574 | 577 | if (token->id == TokenIdRParen) { |
| 575 | 578 | token_index += 1; |
| ... | ... | @@ -680,22 +683,39 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool |
| 680 | 683 | } |
| 681 | 684 | |
| 682 | 685 | /* |
| 683 | FnCallExpression : PrimaryExpression token(LParen) list(Expression, token(Comma)) token(RParen) | PrimaryExpression | |
| 686 | SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression) | |
| 687 | FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen) | |
| 688 | ArrayAccessExpression : token(LBracket) Expression token(RBracket) | |
| 684 | 689 | */ |
| 685 | static AstNode *ast_parse_fn_call_expr(ParseContext *pc, int *token_index, bool mandatory) { | |
| 690 | static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, bool mandatory) { | |
| 686 | 691 | AstNode *primary_expr = ast_parse_primary_expr(pc, token_index, mandatory); |
| 687 | if (!primary_expr) | |
| 692 | if (!primary_expr) { | |
| 688 | 693 | return nullptr; |
| 694 | } | |
| 689 | 695 | |
| 690 | Token *l_paren = &pc->tokens->at(*token_index); | |
| 691 | if (l_paren->id != TokenIdLParen) | |
| 692 | return primary_expr; | |
| 696 | Token *token = &pc->tokens->at(*token_index); | |
| 697 | if (token->id == TokenIdLParen) { | |
| 698 | *token_index += 1; | |
| 693 | 699 | |
| 694 | AstNode *node = ast_create_node_with_node(pc, NodeTypeFnCallExpr, primary_expr); | |
| 695 | node->data.fn_call_expr.fn_ref_expr = primary_expr; | |
| 696 | ast_parse_fn_call_param_list(pc, *token_index, token_index, &node->data.fn_call_expr.params); | |
| 700 | AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, token); | |
| 701 | node->data.fn_call_expr.fn_ref_expr = primary_expr; | |
| 702 | ast_parse_fn_call_param_list(pc, *token_index, token_index, &node->data.fn_call_expr.params); | |
| 703 | return node; | |
| 704 | } else if (token->id == TokenIdLBracket) { | |
| 705 | *token_index += 1; | |
| 697 | 706 | |
| 698 | return node; | |
| 707 | AstNode *node = ast_create_node(pc, NodeTypeArrayAccessExpr, token); | |
| 708 | node->data.array_access_expr.array_ref_expr = primary_expr; | |
| 709 | node->data.array_access_expr.subscript = ast_parse_expression(pc, token_index, true); | |
| 710 | ||
| 711 | Token *r_bracket = &pc->tokens->at(*token_index); | |
| 712 | *token_index += 1; | |
| 713 | ast_expect_token(pc, r_bracket, TokenIdRBracket); | |
| 714 | ||
| 715 | return node; | |
| 716 | } else { | |
| 717 | return primary_expr; | |
| 718 | } | |
| 699 | 719 | } |
| 700 | 720 | |
| 701 | 721 | static PrefixOp tok_to_prefix_op(Token *token) { |
| ... | ... | @@ -725,17 +745,17 @@ static PrefixOp ast_parse_prefix_op(ParseContext *pc, int *token_index, bool man |
| 725 | 745 | } |
| 726 | 746 | |
| 727 | 747 | /* |
| 728 | PrefixOpExpression : PrefixOp FnCallExpression | FnCallExpression | |
| 748 | PrefixOpExpression : PrefixOp SuffixOpExpression | SuffixOpExpression | |
| 729 | 749 | */ |
| 730 | 750 | static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, bool mandatory) { |
| 731 | 751 | Token *token = &pc->tokens->at(*token_index); |
| 732 | 752 | PrefixOp prefix_op = ast_parse_prefix_op(pc, token_index, false); |
| 733 | 753 | if (prefix_op == PrefixOpInvalid) |
| 734 | return ast_parse_fn_call_expr(pc, token_index, mandatory); | |
| 754 | return ast_parse_suffix_op_expr(pc, token_index, mandatory); | |
| 735 | 755 | |
| 736 | AstNode *primary_expr = ast_parse_fn_call_expr(pc, token_index, true); | |
| 756 | AstNode *prefix_op_expr = ast_parse_suffix_op_expr(pc, token_index, true); | |
| 737 | 757 | AstNode *node = ast_create_node(pc, NodeTypePrefixOpExpr, token); |
| 738 | node->data.prefix_op_expr.primary_expr = primary_expr; | |
| 758 | node->data.prefix_op_expr.primary_expr = prefix_op_expr; | |
| 739 | 759 | node->data.prefix_op_expr.prefix_op = prefix_op; |
| 740 | 760 | |
| 741 | 761 | return node; |
src/parser.hpp+7| ... | ... | @@ -38,6 +38,7 @@ enum NodeType { |
| 38 | 38 | NodeTypeSymbol, |
| 39 | 39 | NodeTypePrefixOpExpr, |
| 40 | 40 | NodeTypeFnCallExpr, |
| 41 | NodeTypeArrayAccessExpr, | |
| 41 | 42 | NodeTypeUse, |
| 42 | 43 | NodeTypeVoid, |
| 43 | 44 | NodeTypeBoolLiteral, |
| ... | ... | @@ -143,6 +144,11 @@ struct AstNodeFnCallExpr { |
| 143 | 144 | ZigList<AstNode *> params; |
| 144 | 145 | }; |
| 145 | 146 | |
| 147 | struct AstNodeArrayAccessExpr { | |
| 148 | AstNode *array_ref_expr; | |
| 149 | AstNode *subscript; | |
| 150 | }; | |
| 151 | ||
| 146 | 152 | struct AstNodeExternBlock { |
| 147 | 153 | ZigList<AstNode *> *directives; |
| 148 | 154 | ZigList<AstNode *> fn_decls; |
| ... | ... | @@ -219,6 +225,7 @@ struct AstNode { |
| 219 | 225 | AstNodeCastExpr cast_expr; |
| 220 | 226 | AstNodePrefixOpExpr prefix_op_expr; |
| 221 | 227 | AstNodeFnCallExpr fn_call_expr; |
| 228 | AstNodeArrayAccessExpr array_access_expr; | |
| 222 | 229 | AstNodeUse use; |
| 223 | 230 | AstNodeIfExpr if_expr; |
| 224 | 231 | AstNodeLabel label; |
src/semantic_info.hpp deleted-194| ... | ... | @@ -1,194 +0,0 @@ |
| 1 | /* | |
| 2 | * Copyright (c) 2015 Andrew Kelley | |
| 3 | * | |
| 4 | * This file is part of zig, which is MIT licensed. | |
| 5 | * See http://opensource.org/licenses/MIT | |
| 6 | */ | |
| 7 | ||
| 8 | #ifndef ZIG_SEMANTIC_INFO_HPP | |
| 9 | #define ZIG_SEMANTIC_INFO_HPP | |
| 10 | ||
| 11 | #include "codegen.hpp" | |
| 12 | #include "hash_map.hpp" | |
| 13 | #include "zig_llvm.hpp" | |
| 14 | #include "errmsg.hpp" | |
| 15 | ||
| 16 | struct FnTableEntry; | |
| 17 | struct BlockContext; | |
| 18 | ||
| 19 | struct TypeTableEntry { | |
| 20 | LLVMTypeRef type_ref; | |
| 21 | LLVMZigDIType *di_type; | |
| 22 | uint64_t size_in_bits; | |
| 23 | uint64_t align_in_bits; | |
| 24 | bool is_signed_int; | |
| 25 | bool is_float; | |
| 26 | ||
| 27 | TypeTableEntry *pointer_child; | |
| 28 | bool pointer_is_const; | |
| 29 | int user_defined_id; | |
| 30 | Buf name; | |
| 31 | ||
| 32 | // use these fields to make sure we don't duplicate type table entries for the same type | |
| 33 | TypeTableEntry *pointer_const_parent; | |
| 34 | TypeTableEntry *pointer_mut_parent; | |
| 35 | HashMap<int, TypeTableEntry *, int_hash, int_eq> arrays_by_size; | |
| 36 | }; | |
| 37 | ||
| 38 | struct ImportTableEntry { | |
| 39 | AstNode *root; | |
| 40 | Buf *path; // relative to root_source_dir | |
| 41 | LLVMZigDIFile *di_file; | |
| 42 | Buf *source_code; | |
| 43 | ZigList<int> *line_offsets; | |
| 44 | ||
| 45 | // reminder: hash tables must be initialized before use | |
| 46 | HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table; | |
| 47 | }; | |
| 48 | ||
| 49 | struct LabelTableEntry { | |
| 50 | AstNode *label_node; | |
| 51 | LLVMBasicBlockRef basic_block; | |
| 52 | bool used; | |
| 53 | bool entered_from_fallthrough; | |
| 54 | }; | |
| 55 | ||
| 56 | struct FnTableEntry { | |
| 57 | LLVMValueRef fn_value; | |
| 58 | AstNode *proto_node; | |
| 59 | AstNode *fn_def_node; | |
| 60 | bool is_extern; | |
| 61 | bool internal_linkage; | |
| 62 | unsigned calling_convention; | |
| 63 | ImportTableEntry *import_entry; | |
| 64 | ||
| 65 | // reminder: hash tables must be initialized before use | |
| 66 | HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table; | |
| 67 | }; | |
| 68 | ||
| 69 | struct CodeGen { | |
| 70 | LLVMModuleRef module; | |
| 71 | ZigList<ErrorMsg*> errors; | |
| 72 | LLVMBuilderRef builder; | |
| 73 | LLVMZigDIBuilder *dbuilder; | |
| 74 | LLVMZigDICompileUnit *compile_unit; | |
| 75 | ||
| 76 | // reminder: hash tables must be initialized before use | |
| 77 | HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table; | |
| 78 | HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table; | |
| 79 | HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table; | |
| 80 | HashMap<Buf *, bool, buf_hash, buf_eql_buf> link_table; | |
| 81 | HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table; | |
| 82 | ||
| 83 | struct { | |
| 84 | TypeTableEntry *entry_bool; | |
| 85 | TypeTableEntry *entry_u8; | |
| 86 | TypeTableEntry *entry_i32; | |
| 87 | TypeTableEntry *entry_f32; | |
| 88 | TypeTableEntry *entry_string_literal; | |
| 89 | TypeTableEntry *entry_void; | |
| 90 | TypeTableEntry *entry_unreachable; | |
| 91 | TypeTableEntry *entry_invalid; | |
| 92 | } builtin_types; | |
| 93 | ||
| 94 | LLVMTargetDataRef target_data_ref; | |
| 95 | unsigned pointer_size_bytes; | |
| 96 | bool is_static; | |
| 97 | bool strip_debug_symbols; | |
| 98 | CodeGenBuildType build_type; | |
| 99 | LLVMTargetMachineRef target_machine; | |
| 100 | bool is_native_target; | |
| 101 | Buf *root_source_dir; | |
| 102 | Buf *root_out_name; | |
| 103 | ||
| 104 | // The function definitions this module includes. There must be a corresponding | |
| 105 | // fn_protos entry. | |
| 106 | ZigList<FnTableEntry *> fn_defs; | |
| 107 | // The function prototypes this module includes. In the case of external declarations, | |
| 108 | // there will not be a corresponding fn_defs entry. | |
| 109 | ZigList<FnTableEntry *> fn_protos; | |
| 110 | ||
| 111 | OutType out_type; | |
| 112 | FnTableEntry *cur_fn; | |
| 113 | LLVMBasicBlockRef cur_basic_block; | |
| 114 | BlockContext *cur_block_context; | |
| 115 | bool c_stdint_used; | |
| 116 | AstNode *root_export_decl; | |
| 117 | int version_major; | |
| 118 | int version_minor; | |
| 119 | int version_patch; | |
| 120 | bool verbose; | |
| 121 | ErrColor err_color; | |
| 122 | ImportTableEntry *root_import; | |
| 123 | }; | |
| 124 | ||
| 125 | struct LocalVariableTableEntry { | |
| 126 | Buf name; | |
| 127 | TypeTableEntry *type; | |
| 128 | LLVMValueRef value_ref; | |
| 129 | bool is_const; | |
| 130 | bool is_ptr; // if true, value_ref is a pointer | |
| 131 | AstNode *decl_node; | |
| 132 | LLVMZigDILocalVariable *di_loc_var; | |
| 133 | int arg_index; | |
| 134 | }; | |
| 135 | ||
| 136 | struct BlockContext { | |
| 137 | AstNode *node; // either NodeTypeFnDef or NodeTypeBlock | |
| 138 | BlockContext *root; // always points to the BlockContext with the NodeTypeFnDef | |
| 139 | BlockContext *parent; // nullptr when this is the root | |
| 140 | HashMap<Buf *, LocalVariableTableEntry *, buf_hash, buf_eql_buf> variable_table; | |
| 141 | LLVMZigDIScope *di_scope; | |
| 142 | }; | |
| 143 | ||
| 144 | struct TypeNode { | |
| 145 | TypeTableEntry *entry; | |
| 146 | }; | |
| 147 | ||
| 148 | struct FnProtoNode { | |
| 149 | FnTableEntry *fn_table_entry; | |
| 150 | }; | |
| 151 | ||
| 152 | struct FnDefNode { | |
| 153 | TypeTableEntry *implicit_return_type; | |
| 154 | BlockContext *block_context; | |
| 155 | bool skip; | |
| 156 | // Required to be a pre-order traversal of the AST. (parents must come before children) | |
| 157 | ZigList<BlockContext *> all_block_contexts; | |
| 158 | }; | |
| 159 | ||
| 160 | struct ExprNode { | |
| 161 | TypeTableEntry *type_entry; | |
| 162 | // the context in which this expression is evaluated. | |
| 163 | // for blocks, this points to the containing scope, not the block's own scope for its children. | |
| 164 | BlockContext *block_context; | |
| 165 | }; | |
| 166 | ||
| 167 | struct AssignNode { | |
| 168 | LocalVariableTableEntry *var_entry; | |
| 169 | }; | |
| 170 | ||
| 171 | struct BlockNode { | |
| 172 | BlockContext *block_context; | |
| 173 | }; | |
| 174 | ||
| 175 | struct CodeGenNode { | |
| 176 | union { | |
| 177 | TypeNode type_node; // for NodeTypeType | |
| 178 | FnDefNode fn_def_node; // for NodeTypeFnDef | |
| 179 | FnProtoNode fn_proto_node; // for NodeTypeFnProto | |
| 180 | LabelTableEntry *label_entry; // for NodeTypeGoto and NodeTypeLabel | |
| 181 | AssignNode assign_node; // for NodeTypeBinOpExpr where op is BinOpTypeAssign | |
| 182 | BlockNode block_node; // for NodeTypeBlock | |
| 183 | } data; | |
| 184 | ExprNode expr_node; // for all the expression nodes | |
| 185 | }; | |
| 186 | ||
| 187 | static inline Buf *hack_get_fn_call_name(CodeGen *g, AstNode *node) { | |
| 188 | // Assume that the expression evaluates to a simple name and return the buf | |
| 189 | // TODO after type checking works we should be able to remove this hack | |
| 190 | assert(node->type == NodeTypeSymbol); | |
| 191 | return &node->data.symbol; | |
| 192 | } | |
| 193 | ||
| 194 | #endif |
test/run_tests.cpp+1-1| ... | ... | @@ -392,7 +392,7 @@ fn a() { |
| 392 | 392 | b(1); |
| 393 | 393 | } |
| 394 | 394 | fn b(a: i32, b: i32, c: i32) { } |
| 395 | )SOURCE", 1, ".tmp_source.zig:3:5: error: wrong number of arguments. Expected 3, got 1."); | |
| 395 | )SOURCE", 1, ".tmp_source.zig:3:6: error: wrong number of arguments. Expected 3, got 1."); | |
| 396 | 396 | |
| 397 | 397 | add_compile_fail_case("invalid type", R"SOURCE( |
| 398 | 398 | fn a() -> bogus {} |