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.
6464 * main function with command line arguments
6565 * void pointer constant
6666 * sizeof
67 * address of operator
68 * global variables
6769 * static initializers
6870 * assert
6971 * function pointers
......@@ -202,9 +204,13 @@ MultiplyOperator : token(Star) | token(Slash) | token(Percent)
202204
203205CastExpression : PrefixOpExpression token(as) Type | PrefixOpExpression
204206
205PrefixOpExpression : PrefixOp FnCallExpression | FnCallExpression
207PrefixOpExpression : PrefixOp SuffixOpExpression | SuffixOpExpression
206208
207FnCallExpression : PrimaryExpression token(LParen) list(Expression, token(Comma)) token(RParen) | PrimaryExpression
209SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression)
210
211FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
212
213ArrayAccessExpression : token(LBracket) Expression token(RBracket)
208214
209215PrefixOp : token(Not) | token(Dash) | token(Tilde)
210216
......@@ -220,7 +226,7 @@ KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False)
220226## Operator Precedence
221227
222228```
223x()
229x() x[]
224230!x -x ~x
225231as
226232* / %
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 @@
66 */
77
88#include "analyze.hpp"
9#include "semantic_info.hpp"
109#include "error.hpp"
1110#include "zig_llvm.hpp"
1211#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
1448void add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
1549 ErrorMsg *err = allocate<ErrorMsg>(1);
1650 err->line_start = node->line;
......@@ -48,9 +82,10 @@ static void set_root_export_version(CodeGen *g, Buf *version_buf, AstNode *node)
4882 }
4983}
5084
51TypeTableEntry *new_type_table_entry() {
85TypeTableEntry *new_type_table_entry(TypeTableEntryId id) {
5286 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
5387 entry->arrays_by_size.init(2);
88 entry->id = id;
5489 return entry;
5590}
5691
......@@ -61,7 +96,7 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool
6196 if (*parent_pointer) {
6297 return *parent_pointer;
6398 } else {
64 TypeTableEntry *entry = new_type_table_entry();
99 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPointer);
65100 entry->type_ref = LLVMPointerType(child_type->type_ref, 0);
66101 buf_resize(&entry->name, 0);
67102 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
80115 if (existing_entry) {
81116 return existing_entry->value;
82117 } else {
83 TypeTableEntry *entry = new_type_table_entry();
118 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArray);
84119 entry->type_ref = LLVMArrayType(child_type->type_ref, array_size);
85120 buf_resize(&entry->name, 0);
86121 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,
357392 case NodeTypeBlock:
358393 case NodeTypeBinOpExpr:
359394 case NodeTypeFnCallExpr:
395 case NodeTypeArrayAccessExpr:
360396 case NodeTypeNumberLiteral:
361397 case NodeTypeStringLiteral:
362398 case NodeTypeUnreachable:
......@@ -466,7 +502,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
466502 // ignore void statements once we enter unreachable land.
467503 continue;
468504 }
469 add_node_error(g, child, buf_sprintf("unreachable code"));
505 add_node_error(g, first_executing_node(child), buf_sprintf("unreachable code"));
470506 break;
471507 }
472508 return_type = analyze_expression(g, import, child_context, nullptr, child);
......@@ -641,14 +677,21 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
641677
642678 case NodeTypeFnCallExpr:
643679 {
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
646689 auto entry = import->fn_table.maybe_get(name);
647690 if (!entry)
648691 entry = g->fn_table.maybe_get(name);
649692
650693 if (!entry) {
651 add_node_error(g, node,
694 add_node_error(g, fn_ref_expr,
652695 buf_sprintf("undefined function: '%s'", buf_ptr(name)));
653696 // still analyze the parameters, even though we don't know what to expect
654697 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,
691734 break;
692735 }
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 }
694750 case NodeTypeNumberLiteral:
695751 // TODO: generic literal int type
696752 return_type = g->builtin_types.entry_i32;
......@@ -897,6 +953,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
897953 case NodeTypeBlock:
898954 case NodeTypeBinOpExpr:
899955 case NodeTypeFnCallExpr:
956 case NodeTypeArrayAccessExpr:
900957 case NodeTypeNumberLiteral:
901958 case NodeTypeStringLiteral:
902959 case NodeTypeUnreachable:
src/analyze.hpp+205-6
......@@ -8,17 +8,216 @@
88#ifndef ZIG_ANALYZE_HPP
99#define ZIG_ANALYZE_HPP
1010
11struct CodeGen;
12struct AstNode;
13struct Buf;
11#include "codegen.hpp"
12#include "hash_map.hpp"
13#include "zig_llvm.hpp"
14#include "errmsg.hpp"
1415
15struct TypeTableEntry;
16struct LocalVariableTableEntry;
16struct FnTableEntry;
1717struct 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
19218void semantic_analyze(CodeGen *g);
20219void add_node_error(CodeGen *g, AstNode *node, Buf *msg);
21TypeTableEntry *new_type_table_entry();
220TypeTableEntry *new_type_table_entry(TypeTableEntryId id);
22221TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
23222LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name);
24223
src/codegen.cpp+38-24
......@@ -11,7 +11,6 @@
1111#include "os.hpp"
1212#include "config.h"
1313#include "error.hpp"
14#include "semantic_info.hpp"
1514#include "analyze.hpp"
1615#include "errmsg.hpp"
1716
......@@ -168,6 +167,12 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
168167 }
169168}
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
171176static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
172177 assert(node->type == NodeTypePrefixOpExpr);
173178 assert(node->data.prefix_op_expr.primary_expr);
......@@ -229,49 +234,55 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {
229234 return LLVMBuildShl(g->builder, val1, val2, "");
230235 case BinOpTypeBitShiftRight:
231236 add_debug_source_node(g, node);
232 if (op1_type->is_signed_int) {
237 if (op1_type->id == TypeTableEntryIdInt) {
233238 return LLVMBuildAShr(g->builder, val1, val2, "");
234239 } else {
235240 return LLVMBuildLShr(g->builder, val1, val2, "");
236241 }
237242 case BinOpTypeAdd:
238243 add_debug_source_node(g, node);
239 if (op1_type->is_float) {
244 if (op1_type->id == TypeTableEntryIdFloat) {
240245 return LLVMBuildFAdd(g->builder, val1, val2, "");
241246 } else {
242247 return LLVMBuildNSWAdd(g->builder, val1, val2, "");
243248 }
244249 case BinOpTypeSub:
245250 add_debug_source_node(g, node);
246 if (op1_type->is_float) {
251 if (op1_type->id == TypeTableEntryIdFloat) {
247252 return LLVMBuildFSub(g->builder, val1, val2, "");
248253 } else {
249254 return LLVMBuildNSWSub(g->builder, val1, val2, "");
250255 }
251256 case BinOpTypeMult:
252257 add_debug_source_node(g, node);
253 if (op1_type->is_float) {
258 if (op1_type->id == TypeTableEntryIdFloat) {
254259 return LLVMBuildFMul(g->builder, val1, val2, "");
255260 } else {
256261 return LLVMBuildNSWMul(g->builder, val1, val2, "");
257262 }
258263 case BinOpTypeDiv:
259264 add_debug_source_node(g, node);
260 if (op1_type->is_float) {
265 if (op1_type->id == TypeTableEntryIdFloat) {
261266 return LLVMBuildFDiv(g->builder, val1, val2, "");
262 } else if (op1_type->is_signed_int) {
263 return LLVMBuildSDiv(g->builder, val1, val2, "");
264267 } 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 }
266274 }
267275 case BinOpTypeMod:
268276 add_debug_source_node(g, node);
269 if (op1_type->is_float) {
277 if (op1_type->id == TypeTableEntryIdFloat) {
270278 return LLVMBuildFRem(g->builder, val1, val2, "");
271 } else if (op1_type->is_signed_int) {
272 return LLVMBuildSRem(g->builder, val1, val2, "");
273279 } 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 }
275286 }
276287 case BinOpTypeBoolOr:
277288 case BinOpTypeBoolAnd:
......@@ -337,11 +348,13 @@ static LLVMValueRef gen_cmp_expr(CodeGen *g, AstNode *node) {
337348 assert(op1_type == op2_type);
338349
339350 add_debug_source_node(g, node);
340 if (op1_type->is_float) {
351 if (op1_type->id == TypeTableEntryIdFloat) {
341352 LLVMRealPredicate pred = cmp_op_to_real_predicate(node->data.bin_op_expr.bin_op);
342353 return LLVMBuildFCmp(g->builder, pred, val1, val2, "");
343354 } 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);
345358 return LLVMBuildICmp(g->builder, pred, val1, val2, "");
346359 }
347360}
......@@ -596,6 +609,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
596609 return gen_prefix_op_expr(g, node);
597610 case NodeTypeFnCallExpr:
598611 return gen_fn_call_expr(g, node);
612 case NodeTypeArrayAccessExpr:
613 return gen_array_access_expr(g, node);
599614 case NodeTypeUnreachable:
600615 add_debug_source_node(g, node);
601616 return LLVMBuildUnreachable(g->builder);
......@@ -865,12 +880,12 @@ static void do_code_gen(CodeGen *g) {
865880static void define_primitive_types(CodeGen *g) {
866881 {
867882 // 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);
869884 buf_init_from_str(&entry->name, "(invalid)");
870885 g->builtin_types.entry_invalid = entry;
871886 }
872887 {
873 TypeTableEntry *entry = new_type_table_entry();
888 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdBool);
874889 entry->type_ref = LLVMInt1Type();
875890 buf_init_from_str(&entry->name, "bool");
876891 entry->size_in_bits = 1;
......@@ -882,7 +897,7 @@ static void define_primitive_types(CodeGen *g) {
882897 g->builtin_types.entry_bool = entry;
883898 }
884899 {
885 TypeTableEntry *entry = new_type_table_entry();
900 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
886901 entry->type_ref = LLVMInt8Type();
887902 buf_init_from_str(&entry->name, "u8");
888903 entry->size_in_bits = 8;
......@@ -895,12 +910,12 @@ static void define_primitive_types(CodeGen *g) {
895910 }
896911 g->builtin_types.entry_string_literal = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
897912 {
898 TypeTableEntry *entry = new_type_table_entry();
913 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
899914 entry->type_ref = LLVMInt32Type();
900915 buf_init_from_str(&entry->name, "i32");
901916 entry->size_in_bits = 32;
902917 entry->align_in_bits = 32;
903 entry->is_signed_int = true;
918 entry->data.integral.is_signed = true;
904919 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
905920 entry->size_in_bits, entry->align_in_bits,
906921 LLVMZigEncoding_DW_ATE_signed());
......@@ -908,12 +923,11 @@ static void define_primitive_types(CodeGen *g) {
908923 g->builtin_types.entry_i32 = entry;
909924 }
910925 {
911 TypeTableEntry *entry = new_type_table_entry();
926 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
912927 entry->type_ref = LLVMFloatType();
913928 buf_init_from_str(&entry->name, "f32");
914929 entry->size_in_bits = 32;
915930 entry->align_in_bits = 32;
916 entry->is_float = true;
917931 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
918932 entry->size_in_bits, entry->align_in_bits,
919933 LLVMZigEncoding_DW_ATE_float());
......@@ -921,7 +935,7 @@ static void define_primitive_types(CodeGen *g) {
921935 g->builtin_types.entry_f32 = entry;
922936 }
923937 {
924 TypeTableEntry *entry = new_type_table_entry();
938 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdVoid);
925939 entry->type_ref = LLVMVoidType();
926940 buf_init_from_str(&entry->name, "void");
927941 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
......@@ -931,7 +945,7 @@ static void define_primitive_types(CodeGen *g) {
931945 g->builtin_types.entry_void = entry;
932946 }
933947 {
934 TypeTableEntry *entry = new_type_table_entry();
948 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdUnreachable);
935949 entry->type_ref = LLVMVoidType();
936950 buf_init_from_str(&entry->name, "unreachable");
937951 entry->di_type = g->builtin_types.entry_void->di_type;
src/parser.cpp+39-19
......@@ -7,7 +7,7 @@
77
88#include "parser.hpp"
99#include "errmsg.hpp"
10#include "semantic_info.hpp"
10#include "analyze.hpp"
1111
1212#include <stdarg.h>
1313#include <stdio.h>
......@@ -70,6 +70,8 @@ const char *node_type_str(NodeType node_type) {
7070 return "BinOpExpr";
7171 case NodeTypeFnCallExpr:
7272 return "FnCallExpr";
73 case NodeTypeArrayAccessExpr:
74 return "ArrayAccessExpr";
7375 case NodeTypeExternBlock:
7476 return "ExternBlock";
7577 case NodeTypeDirective:
......@@ -231,6 +233,11 @@ void ast_print(AstNode *node, int indent) {
231233 ast_print(child, indent + 2);
232234 }
233235 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;
234241 case NodeTypeDirective:
235242 fprintf(stderr, "%s\n", node_type_str(node->type));
236243 break;
......@@ -566,10 +573,6 @@ static void ast_parse_param_decl_list(ParseContext *pc, int token_index, int *ne
566573static void ast_parse_fn_call_param_list(ParseContext *pc, int token_index, int *new_token_index,
567574 ZigList<AstNode*> *params)
568575{
569 Token *l_paren = &pc->tokens->at(token_index);
570 token_index += 1;
571 ast_expect_token(pc, l_paren, TokenIdLParen);
572
573576 Token *token = &pc->tokens->at(token_index);
574577 if (token->id == TokenIdRParen) {
575578 token_index += 1;
......@@ -680,22 +683,39 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
680683}
681684
682685/*
683FnCallExpression : PrimaryExpression token(LParen) list(Expression, token(Comma)) token(RParen) | PrimaryExpression
686SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression)
687FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
688ArrayAccessExpression : token(LBracket) Expression token(RBracket)
684689*/
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) {
686691 AstNode *primary_expr = ast_parse_primary_expr(pc, token_index, mandatory);
687 if (!primary_expr)
692 if (!primary_expr) {
688693 return nullptr;
694 }
689695
690 Token *l_paren = &pc->tokens->at(*token_index);
691 if (l_paren->id != TokenIdLParen)
692 return primary_expr;
696 Token *token = &pc->tokens->at(*token_index);
697 if (token->id == TokenIdLParen) {
698 *token_index += 1;
693699
694 AstNode *node = ast_create_node_with_node(pc, NodeTypeFnCallExpr, primary_expr);
695 node->data.fn_call_expr.fn_ref_expr = primary_expr;
696 ast_parse_fn_call_param_list(pc, *token_index, token_index, &node->data.fn_call_expr.params);
700 AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, token);
701 node->data.fn_call_expr.fn_ref_expr = primary_expr;
702 ast_parse_fn_call_param_list(pc, *token_index, token_index, &node->data.fn_call_expr.params);
703 return node;
704 } else if (token->id == TokenIdLBracket) {
705 *token_index += 1;
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 }
699719}
700720
701721static PrefixOp tok_to_prefix_op(Token *token) {
......@@ -725,17 +745,17 @@ static PrefixOp ast_parse_prefix_op(ParseContext *pc, int *token_index, bool man
725745}
726746
727747/*
728PrefixOpExpression : PrefixOp FnCallExpression | FnCallExpression
748PrefixOpExpression : PrefixOp SuffixOpExpression | SuffixOpExpression
729749*/
730750static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, bool mandatory) {
731751 Token *token = &pc->tokens->at(*token_index);
732752 PrefixOp prefix_op = ast_parse_prefix_op(pc, token_index, false);
733753 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);
737757 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;
739759 node->data.prefix_op_expr.prefix_op = prefix_op;
740760
741761 return node;
src/parser.hpp+7
......@@ -38,6 +38,7 @@ enum NodeType {
3838 NodeTypeSymbol,
3939 NodeTypePrefixOpExpr,
4040 NodeTypeFnCallExpr,
41 NodeTypeArrayAccessExpr,
4142 NodeTypeUse,
4243 NodeTypeVoid,
4344 NodeTypeBoolLiteral,
......@@ -143,6 +144,11 @@ struct AstNodeFnCallExpr {
143144 ZigList<AstNode *> params;
144145};
145146
147struct AstNodeArrayAccessExpr {
148 AstNode *array_ref_expr;
149 AstNode *subscript;
150};
151
146152struct AstNodeExternBlock {
147153 ZigList<AstNode *> *directives;
148154 ZigList<AstNode *> fn_decls;
......@@ -219,6 +225,7 @@ struct AstNode {
219225 AstNodeCastExpr cast_expr;
220226 AstNodePrefixOpExpr prefix_op_expr;
221227 AstNodeFnCallExpr fn_call_expr;
228 AstNodeArrayAccessExpr array_access_expr;
222229 AstNodeUse use;
223230 AstNodeIfExpr if_expr;
224231 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() {
392392 b(1);
393393}
394394fn 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
397397 add_compile_fail_case("invalid type", R"SOURCE(
398398fn a() -> bogus {}