| 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,6 +64,8 @@ compromises backward compatibility. |
| 64 | * main function with command line arguments | 64 | * main function with command line arguments |
| 65 | * void pointer constant | 65 | * void pointer constant |
| 66 | * sizeof | 66 | * sizeof |
| 67 | * address of operator | ||
| 68 | * global variables | ||
| 67 | * static initializers | 69 | * static initializers |
| 68 | * assert | 70 | * assert |
| 69 | * function pointers | 71 | * function pointers |
| ... | @@ -202,9 +204,13 @@ MultiplyOperator : token(Star) | token(Slash) | token(Percent) | ... | @@ -202,9 +204,13 @@ MultiplyOperator : token(Star) | token(Slash) | token(Percent) |
| 202 | 204 | ||
| 203 | CastExpression : PrefixOpExpression token(as) Type | PrefixOpExpression | 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 | PrefixOp : token(Not) | token(Dash) | token(Tilde) | 215 | PrefixOp : token(Not) | token(Dash) | token(Tilde) |
| 210 | 216 | ||
| ... | @@ -220,7 +226,7 @@ KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False) | ... | @@ -220,7 +226,7 @@ KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False) |
| 220 | ## Operator Precedence | 226 | ## Operator Precedence |
| 221 | 227 | ||
| 222 | ``` | 228 | ``` |
| 223 | x() | 229 | x() x[] |
| 224 | !x -x ~x | 230 | !x -x ~x |
| 225 | as | 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,11 +6,45 @@ |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include "analyze.hpp" | 8 | #include "analyze.hpp" |
| 9 | #include "semantic_info.hpp" | ||
| 10 | #include "error.hpp" | 9 | #include "error.hpp" |
| 11 | #include "zig_llvm.hpp" | 10 | #include "zig_llvm.hpp" |
| 12 | #include "os.hpp" | 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 | void add_node_error(CodeGen *g, AstNode *node, Buf *msg) { | 48 | void add_node_error(CodeGen *g, AstNode *node, Buf *msg) { |
| 15 | ErrorMsg *err = allocate<ErrorMsg>(1); | 49 | ErrorMsg *err = allocate<ErrorMsg>(1); |
| 16 | err->line_start = node->line; | 50 | err->line_start = node->line; |
| ... | @@ -48,9 +82,10 @@ static void set_root_export_version(CodeGen *g, Buf *version_buf, AstNode *node) | ... | @@ -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 | TypeTableEntry *entry = allocate<TypeTableEntry>(1); | 86 | TypeTableEntry *entry = allocate<TypeTableEntry>(1); |
| 53 | entry->arrays_by_size.init(2); | 87 | entry->arrays_by_size.init(2); |
| 88 | entry->id = id; | ||
| 54 | return entry; | 89 | return entry; |
| 55 | } | 90 | } |
| 56 | 91 | ||
| ... | @@ -61,7 +96,7 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool | ... | @@ -61,7 +96,7 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool |
| 61 | if (*parent_pointer) { | 96 | if (*parent_pointer) { |
| 62 | return *parent_pointer; | 97 | return *parent_pointer; |
| 63 | } else { | 98 | } else { |
| 64 | TypeTableEntry *entry = new_type_table_entry(); | 99 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPointer); |
| 65 | entry->type_ref = LLVMPointerType(child_type->type_ref, 0); | 100 | entry->type_ref = LLVMPointerType(child_type->type_ref, 0); |
| 66 | buf_resize(&entry->name, 0); | 101 | buf_resize(&entry->name, 0); |
| 67 | buf_appendf(&entry->name, "*%s %s", is_const ? "const" : "mut", buf_ptr(&child_type->name)); | 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,7 +115,7 @@ static TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, in |
| 80 | if (existing_entry) { | 115 | if (existing_entry) { |
| 81 | return existing_entry->value; | 116 | return existing_entry->value; |
| 82 | } else { | 117 | } else { |
| 83 | TypeTableEntry *entry = new_type_table_entry(); | 118 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArray); |
| 84 | entry->type_ref = LLVMArrayType(child_type->type_ref, array_size); | 119 | entry->type_ref = LLVMArrayType(child_type->type_ref, array_size); |
| 85 | buf_resize(&entry->name, 0); | 120 | buf_resize(&entry->name, 0); |
| 86 | buf_appendf(&entry->name, "[%s; %d]", buf_ptr(&child_type->name), array_size); | 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,6 +392,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, |
| 357 | case NodeTypeBlock: | 392 | case NodeTypeBlock: |
| 358 | case NodeTypeBinOpExpr: | 393 | case NodeTypeBinOpExpr: |
| 359 | case NodeTypeFnCallExpr: | 394 | case NodeTypeFnCallExpr: |
| 395 | case NodeTypeArrayAccessExpr: | ||
| 360 | case NodeTypeNumberLiteral: | 396 | case NodeTypeNumberLiteral: |
| 361 | case NodeTypeStringLiteral: | 397 | case NodeTypeStringLiteral: |
| 362 | case NodeTypeUnreachable: | 398 | case NodeTypeUnreachable: |
| ... | @@ -466,7 +502,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -466,7 +502,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 466 | // ignore void statements once we enter unreachable land. | 502 | // ignore void statements once we enter unreachable land. |
| 467 | continue; | 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 | break; | 506 | break; |
| 471 | } | 507 | } |
| 472 | return_type = analyze_expression(g, import, child_context, nullptr, child); | 508 | return_type = analyze_expression(g, import, child_context, nullptr, child); |
| ... | @@ -641,14 +677,21 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -641,14 +677,21 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 641 | 677 | ||
| 642 | case NodeTypeFnCallExpr: | 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 | auto entry = import->fn_table.maybe_get(name); | 689 | auto entry = import->fn_table.maybe_get(name); |
| 647 | if (!entry) | 690 | if (!entry) |
| 648 | entry = g->fn_table.maybe_get(name); | 691 | entry = g->fn_table.maybe_get(name); |
| 649 | 692 | ||
| 650 | if (!entry) { | 693 | if (!entry) { |
| 651 | add_node_error(g, node, | 694 | add_node_error(g, fn_ref_expr, |
| 652 | buf_sprintf("undefined function: '%s'", buf_ptr(name))); | 695 | buf_sprintf("undefined function: '%s'", buf_ptr(name))); |
| 653 | // still analyze the parameters, even though we don't know what to expect | 696 | // still analyze the parameters, even though we don't know what to expect |
| 654 | for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { | 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,6 +734,19 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 691 | break; | 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 | case NodeTypeNumberLiteral: | 750 | case NodeTypeNumberLiteral: |
| 695 | // TODO: generic literal int type | 751 | // TODO: generic literal int type |
| 696 | return_type = g->builtin_types.entry_i32; | 752 | return_type = g->builtin_types.entry_i32; |
| ... | @@ -897,6 +953,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, | ... | @@ -897,6 +953,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, |
| 897 | case NodeTypeBlock: | 953 | case NodeTypeBlock: |
| 898 | case NodeTypeBinOpExpr: | 954 | case NodeTypeBinOpExpr: |
| 899 | case NodeTypeFnCallExpr: | 955 | case NodeTypeFnCallExpr: |
| 956 | case NodeTypeArrayAccessExpr: | ||
| 900 | case NodeTypeNumberLiteral: | 957 | case NodeTypeNumberLiteral: |
| 901 | case NodeTypeStringLiteral: | 958 | case NodeTypeStringLiteral: |
| 902 | case NodeTypeUnreachable: | 959 | case NodeTypeUnreachable: |
src/analyze.hpp+205-6| ... | @@ -8,17 +8,216 @@ | ... | @@ -8,17 +8,216 @@ |
| 8 | #ifndef ZIG_ANALYZE_HPP | 8 | #ifndef ZIG_ANALYZE_HPP |
| 9 | #define ZIG_ANALYZE_HPP | 9 | #define ZIG_ANALYZE_HPP |
| 10 | 10 | ||
| 11 | struct CodeGen; | 11 | #include "codegen.hpp" |
| 12 | struct AstNode; | 12 | #include "hash_map.hpp" |
| 13 | struct Buf; | 13 | #include "zig_llvm.hpp" |
| 14 | #include "errmsg.hpp" | ||
| 14 | 15 | ||
| 15 | struct TypeTableEntry; | 16 | struct FnTableEntry; |
| 16 | struct LocalVariableTableEntry; | ||
| 17 | struct BlockContext; | 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 | void semantic_analyze(CodeGen *g); | 218 | void semantic_analyze(CodeGen *g); |
| 20 | void add_node_error(CodeGen *g, AstNode *node, Buf *msg); | 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 | TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const); | 221 | TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const); |
| 23 | LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name); | 222 | LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name); |
| 24 | 223 |
src/codegen.cpp+38-24| ... | @@ -11,7 +11,6 @@ | ... | @@ -11,7 +11,6 @@ |
| 11 | #include "os.hpp" | 11 | #include "os.hpp" |
| 12 | #include "config.h" | 12 | #include "config.h" |
| 13 | #include "error.hpp" | 13 | #include "error.hpp" |
| 14 | #include "semantic_info.hpp" | ||
| 15 | #include "analyze.hpp" | 14 | #include "analyze.hpp" |
| 16 | #include "errmsg.hpp" | 15 | #include "errmsg.hpp" |
| 17 | 16 | ||
| ... | @@ -168,6 +167,12 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { | ... | @@ -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 | static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) { | 176 | static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) { |
| 172 | assert(node->type == NodeTypePrefixOpExpr); | 177 | assert(node->type == NodeTypePrefixOpExpr); |
| 173 | assert(node->data.prefix_op_expr.primary_expr); | 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,49 +234,55 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) { |
| 229 | return LLVMBuildShl(g->builder, val1, val2, ""); | 234 | return LLVMBuildShl(g->builder, val1, val2, ""); |
| 230 | case BinOpTypeBitShiftRight: | 235 | case BinOpTypeBitShiftRight: |
| 231 | add_debug_source_node(g, node); | 236 | add_debug_source_node(g, node); |
| 232 | if (op1_type->is_signed_int) { | 237 | if (op1_type->id == TypeTableEntryIdInt) { |
| 233 | return LLVMBuildAShr(g->builder, val1, val2, ""); | 238 | return LLVMBuildAShr(g->builder, val1, val2, ""); |
| 234 | } else { | 239 | } else { |
| 235 | return LLVMBuildLShr(g->builder, val1, val2, ""); | 240 | return LLVMBuildLShr(g->builder, val1, val2, ""); |
| 236 | } | 241 | } |
| 237 | case BinOpTypeAdd: | 242 | case BinOpTypeAdd: |
| 238 | add_debug_source_node(g, node); | 243 | add_debug_source_node(g, node); |
| 239 | if (op1_type->is_float) { | 244 | if (op1_type->id == TypeTableEntryIdFloat) { |
| 240 | return LLVMBuildFAdd(g->builder, val1, val2, ""); | 245 | return LLVMBuildFAdd(g->builder, val1, val2, ""); |
| 241 | } else { | 246 | } else { |
| 242 | return LLVMBuildNSWAdd(g->builder, val1, val2, ""); | 247 | return LLVMBuildNSWAdd(g->builder, val1, val2, ""); |
| 243 | } | 248 | } |
| 244 | case BinOpTypeSub: | 249 | case BinOpTypeSub: |
| 245 | add_debug_source_node(g, node); | 250 | add_debug_source_node(g, node); |
| 246 | if (op1_type->is_float) { | 251 | if (op1_type->id == TypeTableEntryIdFloat) { |
| 247 | return LLVMBuildFSub(g->builder, val1, val2, ""); | 252 | return LLVMBuildFSub(g->builder, val1, val2, ""); |
| 248 | } else { | 253 | } else { |
| 249 | return LLVMBuildNSWSub(g->builder, val1, val2, ""); | 254 | return LLVMBuildNSWSub(g->builder, val1, val2, ""); |
| 250 | } | 255 | } |
| 251 | case BinOpTypeMult: | 256 | case BinOpTypeMult: |
| 252 | add_debug_source_node(g, node); | 257 | add_debug_source_node(g, node); |
| 253 | if (op1_type->is_float) { | 258 | if (op1_type->id == TypeTableEntryIdFloat) { |
| 254 | return LLVMBuildFMul(g->builder, val1, val2, ""); | 259 | return LLVMBuildFMul(g->builder, val1, val2, ""); |
| 255 | } else { | 260 | } else { |
| 256 | return LLVMBuildNSWMul(g->builder, val1, val2, ""); | 261 | return LLVMBuildNSWMul(g->builder, val1, val2, ""); |
| 257 | } | 262 | } |
| 258 | case BinOpTypeDiv: | 263 | case BinOpTypeDiv: |
| 259 | add_debug_source_node(g, node); | 264 | add_debug_source_node(g, node); |
| 260 | if (op1_type->is_float) { | 265 | if (op1_type->id == TypeTableEntryIdFloat) { |
| 261 | return LLVMBuildFDiv(g->builder, val1, val2, ""); | 266 | return LLVMBuildFDiv(g->builder, val1, val2, ""); |
| 262 | } else if (op1_type->is_signed_int) { | ||
| 263 | return LLVMBuildSDiv(g->builder, val1, val2, ""); | ||
| 264 | } else { | 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 | case BinOpTypeMod: | 275 | case BinOpTypeMod: |
| 268 | add_debug_source_node(g, node); | 276 | add_debug_source_node(g, node); |
| 269 | if (op1_type->is_float) { | 277 | if (op1_type->id == TypeTableEntryIdFloat) { |
| 270 | return LLVMBuildFRem(g->builder, val1, val2, ""); | 278 | return LLVMBuildFRem(g->builder, val1, val2, ""); |
| 271 | } else if (op1_type->is_signed_int) { | ||
| 272 | return LLVMBuildSRem(g->builder, val1, val2, ""); | ||
| 273 | } else { | 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 | case BinOpTypeBoolOr: | 287 | case BinOpTypeBoolOr: |
| 277 | case BinOpTypeBoolAnd: | 288 | case BinOpTypeBoolAnd: |
| ... | @@ -337,11 +348,13 @@ static LLVMValueRef gen_cmp_expr(CodeGen *g, AstNode *node) { | ... | @@ -337,11 +348,13 @@ static LLVMValueRef gen_cmp_expr(CodeGen *g, AstNode *node) { |
| 337 | assert(op1_type == op2_type); | 348 | assert(op1_type == op2_type); |
| 338 | 349 | ||
| 339 | add_debug_source_node(g, node); | 350 | add_debug_source_node(g, node); |
| 340 | if (op1_type->is_float) { | 351 | if (op1_type->id == TypeTableEntryIdFloat) { |
| 341 | LLVMRealPredicate pred = cmp_op_to_real_predicate(node->data.bin_op_expr.bin_op); | 352 | LLVMRealPredicate pred = cmp_op_to_real_predicate(node->data.bin_op_expr.bin_op); |
| 342 | return LLVMBuildFCmp(g->builder, pred, val1, val2, ""); | 353 | return LLVMBuildFCmp(g->builder, pred, val1, val2, ""); |
| 343 | } else { | 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 | return LLVMBuildICmp(g->builder, pred, val1, val2, ""); | 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,6 +609,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { |
| 596 | return gen_prefix_op_expr(g, node); | 609 | return gen_prefix_op_expr(g, node); |
| 597 | case NodeTypeFnCallExpr: | 610 | case NodeTypeFnCallExpr: |
| 598 | return gen_fn_call_expr(g, node); | 611 | return gen_fn_call_expr(g, node); |
| 612 | case NodeTypeArrayAccessExpr: | ||
| 613 | return gen_array_access_expr(g, node); | ||
| 599 | case NodeTypeUnreachable: | 614 | case NodeTypeUnreachable: |
| 600 | add_debug_source_node(g, node); | 615 | add_debug_source_node(g, node); |
| 601 | return LLVMBuildUnreachable(g->builder); | 616 | return LLVMBuildUnreachable(g->builder); |
| ... | @@ -865,12 +880,12 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -865,12 +880,12 @@ static void do_code_gen(CodeGen *g) { |
| 865 | static void define_primitive_types(CodeGen *g) { | 880 | static void define_primitive_types(CodeGen *g) { |
| 866 | { | 881 | { |
| 867 | // if this type is anywhere in the AST, we should never hit codegen. | 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 | buf_init_from_str(&entry->name, "(invalid)"); | 884 | buf_init_from_str(&entry->name, "(invalid)"); |
| 870 | g->builtin_types.entry_invalid = entry; | 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 | entry->type_ref = LLVMInt1Type(); | 889 | entry->type_ref = LLVMInt1Type(); |
| 875 | buf_init_from_str(&entry->name, "bool"); | 890 | buf_init_from_str(&entry->name, "bool"); |
| 876 | entry->size_in_bits = 1; | 891 | entry->size_in_bits = 1; |
| ... | @@ -882,7 +897,7 @@ static void define_primitive_types(CodeGen *g) { | ... | @@ -882,7 +897,7 @@ static void define_primitive_types(CodeGen *g) { |
| 882 | g->builtin_types.entry_bool = entry; | 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 | entry->type_ref = LLVMInt8Type(); | 901 | entry->type_ref = LLVMInt8Type(); |
| 887 | buf_init_from_str(&entry->name, "u8"); | 902 | buf_init_from_str(&entry->name, "u8"); |
| 888 | entry->size_in_bits = 8; | 903 | entry->size_in_bits = 8; |
| ... | @@ -895,12 +910,12 @@ static void define_primitive_types(CodeGen *g) { | ... | @@ -895,12 +910,12 @@ static void define_primitive_types(CodeGen *g) { |
| 895 | } | 910 | } |
| 896 | g->builtin_types.entry_string_literal = get_pointer_to_type(g, g->builtin_types.entry_u8, true); | 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 | entry->type_ref = LLVMInt32Type(); | 914 | entry->type_ref = LLVMInt32Type(); |
| 900 | buf_init_from_str(&entry->name, "i32"); | 915 | buf_init_from_str(&entry->name, "i32"); |
| 901 | entry->size_in_bits = 32; | 916 | entry->size_in_bits = 32; |
| 902 | entry->align_in_bits = 32; | 917 | entry->align_in_bits = 32; |
| 903 | entry->is_signed_int = true; | 918 | entry->data.integral.is_signed = true; |
| 904 | entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), | 919 | entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), |
| 905 | entry->size_in_bits, entry->align_in_bits, | 920 | entry->size_in_bits, entry->align_in_bits, |
| 906 | LLVMZigEncoding_DW_ATE_signed()); | 921 | LLVMZigEncoding_DW_ATE_signed()); |
| ... | @@ -908,12 +923,11 @@ static void define_primitive_types(CodeGen *g) { | ... | @@ -908,12 +923,11 @@ static void define_primitive_types(CodeGen *g) { |
| 908 | g->builtin_types.entry_i32 = entry; | 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 | entry->type_ref = LLVMFloatType(); | 927 | entry->type_ref = LLVMFloatType(); |
| 913 | buf_init_from_str(&entry->name, "f32"); | 928 | buf_init_from_str(&entry->name, "f32"); |
| 914 | entry->size_in_bits = 32; | 929 | entry->size_in_bits = 32; |
| 915 | entry->align_in_bits = 32; | 930 | entry->align_in_bits = 32; |
| 916 | entry->is_float = true; | ||
| 917 | entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), | 931 | entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), |
| 918 | entry->size_in_bits, entry->align_in_bits, | 932 | entry->size_in_bits, entry->align_in_bits, |
| 919 | LLVMZigEncoding_DW_ATE_float()); | 933 | LLVMZigEncoding_DW_ATE_float()); |
| ... | @@ -921,7 +935,7 @@ static void define_primitive_types(CodeGen *g) { | ... | @@ -921,7 +935,7 @@ static void define_primitive_types(CodeGen *g) { |
| 921 | g->builtin_types.entry_f32 = entry; | 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 | entry->type_ref = LLVMVoidType(); | 939 | entry->type_ref = LLVMVoidType(); |
| 926 | buf_init_from_str(&entry->name, "void"); | 940 | buf_init_from_str(&entry->name, "void"); |
| 927 | entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), | 941 | entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), |
| ... | @@ -931,7 +945,7 @@ static void define_primitive_types(CodeGen *g) { | ... | @@ -931,7 +945,7 @@ static void define_primitive_types(CodeGen *g) { |
| 931 | g->builtin_types.entry_void = entry; | 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 | entry->type_ref = LLVMVoidType(); | 949 | entry->type_ref = LLVMVoidType(); |
| 936 | buf_init_from_str(&entry->name, "unreachable"); | 950 | buf_init_from_str(&entry->name, "unreachable"); |
| 937 | entry->di_type = g->builtin_types.entry_void->di_type; | 951 | entry->di_type = g->builtin_types.entry_void->di_type; |
src/parser.cpp+39-19| ... | @@ -7,7 +7,7 @@ | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | ||
| 8 | #include "parser.hpp" | 8 | #include "parser.hpp" |
| 9 | #include "errmsg.hpp" | 9 | #include "errmsg.hpp" |
| 10 | #include "semantic_info.hpp" | 10 | #include "analyze.hpp" |
| 11 | 11 | ||
| 12 | #include <stdarg.h> | 12 | #include <stdarg.h> |
| 13 | #include <stdio.h> | 13 | #include <stdio.h> |
| ... | @@ -70,6 +70,8 @@ const char *node_type_str(NodeType node_type) { | ... | @@ -70,6 +70,8 @@ const char *node_type_str(NodeType node_type) { |
| 70 | return "BinOpExpr"; | 70 | return "BinOpExpr"; |
| 71 | case NodeTypeFnCallExpr: | 71 | case NodeTypeFnCallExpr: |
| 72 | return "FnCallExpr"; | 72 | return "FnCallExpr"; |
| 73 | case NodeTypeArrayAccessExpr: | ||
| 74 | return "ArrayAccessExpr"; | ||
| 73 | case NodeTypeExternBlock: | 75 | case NodeTypeExternBlock: |
| 74 | return "ExternBlock"; | 76 | return "ExternBlock"; |
| 75 | case NodeTypeDirective: | 77 | case NodeTypeDirective: |
| ... | @@ -231,6 +233,11 @@ void ast_print(AstNode *node, int indent) { | ... | @@ -231,6 +233,11 @@ void ast_print(AstNode *node, int indent) { |
| 231 | ast_print(child, indent + 2); | 233 | ast_print(child, indent + 2); |
| 232 | } | 234 | } |
| 233 | break; | 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 | case NodeTypeDirective: | 241 | case NodeTypeDirective: |
| 235 | fprintf(stderr, "%s\n", node_type_str(node->type)); | 242 | fprintf(stderr, "%s\n", node_type_str(node->type)); |
| 236 | break; | 243 | break; |
| ... | @@ -566,10 +573,6 @@ static void ast_parse_param_decl_list(ParseContext *pc, int token_index, int *ne | ... | @@ -566,10 +573,6 @@ static void ast_parse_param_decl_list(ParseContext *pc, int token_index, int *ne |
| 566 | static void ast_parse_fn_call_param_list(ParseContext *pc, int token_index, int *new_token_index, | 573 | static void ast_parse_fn_call_param_list(ParseContext *pc, int token_index, int *new_token_index, |
| 567 | ZigList<AstNode*> *params) | 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 | Token *token = &pc->tokens->at(token_index); | 576 | Token *token = &pc->tokens->at(token_index); |
| 574 | if (token->id == TokenIdRParen) { | 577 | if (token->id == TokenIdRParen) { |
| 575 | token_index += 1; | 578 | token_index += 1; |
| ... | @@ -680,22 +683,39 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool | ... | @@ -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 | AstNode *primary_expr = ast_parse_primary_expr(pc, token_index, mandatory); | 691 | AstNode *primary_expr = ast_parse_primary_expr(pc, token_index, mandatory); |
| 687 | if (!primary_expr) | 692 | if (!primary_expr) { |
| 688 | return nullptr; | 693 | return nullptr; |
| 694 | } | ||
| 689 | 695 | ||
| 690 | Token *l_paren = &pc->tokens->at(*token_index); | 696 | Token *token = &pc->tokens->at(*token_index); |
| 691 | if (l_paren->id != TokenIdLParen) | 697 | if (token->id == TokenIdLParen) { |
| 692 | return primary_expr; | 698 | *token_index += 1; |
| 693 | 699 | ||
| 694 | AstNode *node = ast_create_node_with_node(pc, NodeTypeFnCallExpr, primary_expr); | 700 | AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, token); |
| 695 | node->data.fn_call_expr.fn_ref_expr = primary_expr; | 701 | 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); | 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 | static PrefixOp tok_to_prefix_op(Token *token) { | 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,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 | static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, bool mandatory) { | 750 | static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, bool mandatory) { |
| 731 | Token *token = &pc->tokens->at(*token_index); | 751 | Token *token = &pc->tokens->at(*token_index); |
| 732 | PrefixOp prefix_op = ast_parse_prefix_op(pc, token_index, false); | 752 | PrefixOp prefix_op = ast_parse_prefix_op(pc, token_index, false); |
| 733 | if (prefix_op == PrefixOpInvalid) | 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 | AstNode *node = ast_create_node(pc, NodeTypePrefixOpExpr, token); | 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 | node->data.prefix_op_expr.prefix_op = prefix_op; | 759 | node->data.prefix_op_expr.prefix_op = prefix_op; |
| 740 | 760 | ||
| 741 | return node; | 761 | return node; |
src/parser.hpp+7| ... | @@ -38,6 +38,7 @@ enum NodeType { | ... | @@ -38,6 +38,7 @@ enum NodeType { |
| 38 | NodeTypeSymbol, | 38 | NodeTypeSymbol, |
| 39 | NodeTypePrefixOpExpr, | 39 | NodeTypePrefixOpExpr, |
| 40 | NodeTypeFnCallExpr, | 40 | NodeTypeFnCallExpr, |
| 41 | NodeTypeArrayAccessExpr, | ||
| 41 | NodeTypeUse, | 42 | NodeTypeUse, |
| 42 | NodeTypeVoid, | 43 | NodeTypeVoid, |
| 43 | NodeTypeBoolLiteral, | 44 | NodeTypeBoolLiteral, |
| ... | @@ -143,6 +144,11 @@ struct AstNodeFnCallExpr { | ... | @@ -143,6 +144,11 @@ struct AstNodeFnCallExpr { |
| 143 | ZigList<AstNode *> params; | 144 | ZigList<AstNode *> params; |
| 144 | }; | 145 | }; |
| 145 | 146 | ||
| 147 | struct AstNodeArrayAccessExpr { | ||
| 148 | AstNode *array_ref_expr; | ||
| 149 | AstNode *subscript; | ||
| 150 | }; | ||
| 151 | |||
| 146 | struct AstNodeExternBlock { | 152 | struct AstNodeExternBlock { |
| 147 | ZigList<AstNode *> *directives; | 153 | ZigList<AstNode *> *directives; |
| 148 | ZigList<AstNode *> fn_decls; | 154 | ZigList<AstNode *> fn_decls; |
| ... | @@ -219,6 +225,7 @@ struct AstNode { | ... | @@ -219,6 +225,7 @@ struct AstNode { |
| 219 | AstNodeCastExpr cast_expr; | 225 | AstNodeCastExpr cast_expr; |
| 220 | AstNodePrefixOpExpr prefix_op_expr; | 226 | AstNodePrefixOpExpr prefix_op_expr; |
| 221 | AstNodeFnCallExpr fn_call_expr; | 227 | AstNodeFnCallExpr fn_call_expr; |
| 228 | AstNodeArrayAccessExpr array_access_expr; | ||
| 222 | AstNodeUse use; | 229 | AstNodeUse use; |
| 223 | AstNodeIfExpr if_expr; | 230 | AstNodeIfExpr if_expr; |
| 224 | AstNodeLabel label; | 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,7 +392,7 @@ fn a() { |
| 392 | b(1); | 392 | b(1); |
| 393 | } | 393 | } |
| 394 | fn b(a: i32, b: i32, c: i32) { } | 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 | add_compile_fail_case("invalid type", R"SOURCE( | 397 | add_compile_fail_case("invalid type", R"SOURCE( |
| 398 | fn a() -> bogus {} | 398 | fn a() -> bogus {} |