authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-08 14:15:34-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-08 14:15:34-07:00
log75efc313299af89c69c5f2b4a7c2758753ed36c3
tree6bee1174842149ad36378a8c241b760af4db77df
parent2f0e4e9cb26df7a6f6251d0e865d0d964680831e

add array access syntax


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 arguments64 * main function with command line arguments
65 * void pointer constant65 * void pointer constant
66 * sizeof66 * sizeof
67 * address of operator
68 * global variables
67 * static initializers69 * static initializers
68 * assert70 * assert
69 * function pointers71 * function pointers
...@@ -202,9 +204,13 @@ MultiplyOperator : token(Star) | token(Slash) | token(Percent)...@@ -202,9 +204,13 @@ MultiplyOperator : token(Star) | token(Slash) | token(Percent)
202204
203CastExpression : PrefixOpExpression token(as) Type | PrefixOpExpression205CastExpression : PrefixOpExpression token(as) Type | PrefixOpExpression
204206
205PrefixOpExpression : PrefixOp FnCallExpression | FnCallExpression207PrefixOpExpression : PrefixOp SuffixOpExpression | SuffixOpExpression
206208
207FnCallExpression : PrimaryExpression token(LParen) list(Expression, token(Comma)) token(RParen) | PrimaryExpression209SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression)
210
211FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
212
213ArrayAccessExpression : token(LBracket) Expression token(RBracket)
208214
209PrefixOp : token(Not) | token(Dash) | token(Tilde)215PrefixOp : token(Not) | token(Dash) | token(Tilde)
210216
...@@ -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 Precedence226## Operator Precedence
221227
222```228```
223x()229x() x[]
224!x -x ~x230!x -x ~x
225as231as
226* / %232* / %
example/arrays/arrays.zig created+16
...@@ -0,0 +1,16 @@
1export executable "arrays";
2
3#link("c")
4extern {
5 fn puts(s: *const u8) -> i32;
6 fn exit(code: i32) -> unreachable;
7}
8
9export 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 */
77
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"
1312
13static 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
14void add_node_error(CodeGen *g, AstNode *node, Buf *msg) {48void 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}
5084
51TypeTableEntry *new_type_table_entry() {85TypeTableEntry *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}
5691
...@@ -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,
641677
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;
645688
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);
649692
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 expect696 // 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 }
693736
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 type751 // 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_HPP8#ifndef ZIG_ANALYZE_HPP
9#define ZIG_ANALYZE_HPP9#define ZIG_ANALYZE_HPP
1010
11struct CodeGen;11#include "codegen.hpp"
12struct AstNode;12#include "hash_map.hpp"
13struct Buf;13#include "zig_llvm.hpp"
14#include "errmsg.hpp"
1415
15struct TypeTableEntry;16struct FnTableEntry;
16struct LocalVariableTableEntry;
17struct BlockContext;17struct BlockContext;
18struct TypeTableEntry;
19
20struct TypeTableEntryPointer {
21 TypeTableEntry *pointer_child;
22 bool pointer_is_const;
23};
24
25struct TypeTableEntryInt {
26 bool is_signed;
27};
28
29enum TypeTableEntryId {
30 TypeTableEntryIdInvalid,
31 TypeTableEntryIdVoid,
32 TypeTableEntryIdBool,
33 TypeTableEntryIdUnreachable,
34 TypeTableEntryIdInt,
35 TypeTableEntryIdFloat,
36 TypeTableEntryIdPointer,
37 TypeTableEntryIdArray,
38};
39
40struct 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
62struct 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
73struct LabelTableEntry {
74 AstNode *label_node;
75 LLVMBasicBlockRef basic_block;
76 bool used;
77 bool entered_from_fallthrough;
78};
79
80struct 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
93struct 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
149struct 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
160struct 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
168struct TypeNode {
169 TypeTableEntry *entry;
170};
171
172struct FnProtoNode {
173 FnTableEntry *fn_table_entry;
174};
175
176struct 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
184struct 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
191struct AssignNode {
192 LocalVariableTableEntry *var_entry;
193};
194
195struct BlockNode {
196 BlockContext *block_context;
197};
198
199struct 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
211static 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}
18217
19void semantic_analyze(CodeGen *g);218void semantic_analyze(CodeGen *g);
20void add_node_error(CodeGen *g, AstNode *node, Buf *msg);219void add_node_error(CodeGen *g, AstNode *node, Buf *msg);
21TypeTableEntry *new_type_table_entry();220TypeTableEntry *new_type_table_entry(TypeTableEntryId id);
22TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);221TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
23LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name);222LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name);
24223
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"
1716
...@@ -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}
170169
170static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node) {
171 assert(node->type == NodeTypeArrayAccessExpr);
172
173 zig_panic("TODO gen arary access");
174}
175
171static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {176static 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);
338349
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) {
865static void define_primitive_types(CodeGen *g) {880static 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 @@
77
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"
1111
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
566static void ast_parse_fn_call_param_list(ParseContext *pc, int token_index, int *new_token_index,573static 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}
681684
682/*685/*
683FnCallExpression : PrimaryExpression token(LParen) list(Expression, token(Comma)) token(RParen) | PrimaryExpression686SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression)
687FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
688ArrayAccessExpression : token(LBracket) Expression token(RBracket)
684*/689*/
685static AstNode *ast_parse_fn_call_expr(ParseContext *pc, int *token_index, bool mandatory) {690static 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 }
689695
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;
693699
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;
697706
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}
700720
701static PrefixOp tok_to_prefix_op(Token *token) {721static 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}
726746
727/*747/*
728PrefixOpExpression : PrefixOp FnCallExpression | FnCallExpression748PrefixOpExpression : PrefixOp SuffixOpExpression | SuffixOpExpression
729*/749*/
730static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, bool mandatory) {750static 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);
735755
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;
740760
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};
145146
147struct AstNodeArrayAccessExpr {
148 AstNode *array_ref_expr;
149 AstNode *subscript;
150};
151
146struct AstNodeExternBlock {152struct 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
16struct FnTableEntry;
17struct BlockContext;
18
19struct 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
38struct 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
49struct LabelTableEntry {
50 AstNode *label_node;
51 LLVMBasicBlockRef basic_block;
52 bool used;
53 bool entered_from_fallthrough;
54};
55
56struct 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
69struct 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
125struct 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
136struct 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
144struct TypeNode {
145 TypeTableEntry *entry;
146};
147
148struct FnProtoNode {
149 FnTableEntry *fn_table_entry;
150};
151
152struct 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
160struct 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
167struct AssignNode {
168 LocalVariableTableEntry *var_entry;
169};
170
171struct BlockNode {
172 BlockContext *block_context;
173};
174
175struct 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
187static 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}
394fn b(a: i32, b: i32, c: i32) { }394fn 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.");
396396
397 add_compile_fail_case("invalid type", R"SOURCE(397 add_compile_fail_case("invalid type", R"SOURCE(
398fn a() -> bogus {}398fn a() -> bogus {}