authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-18 07:00:45-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-18 07:00:45-07:00
logfbbef140130e8da13f1d58b884ec3a0225965531
treedc54b1f5a9e3bc793986067b67de336320a2ee29
parentf0a43cfda9bcfcbefb24cac3ef01c5c745022c58

add for loop which can iterate over arrays

See #51

9 files changed, 344 insertions(+), 105 deletions(-)

doc/langref.md+3-1
......@@ -90,10 +90,12 @@ AssignmentExpression : UnwrapMaybeExpression AssignmentOperator UnwrapMaybeExpre
9090
9191AssignmentOperator : token(Eq) | token(TimesEq) | token(DivEq) | token(ModEq) | token(PlusEq) | token(MinusEq) | token(BitShiftLeftEq) | token(BitShiftRightEq) | token(BitAndEq) | token(BitXorEq) | token(BitOrEq) | token(BoolAndEq) | token(BoolOrEq)
9292
93BlockExpression : IfExpression | Block | WhileExpression
93BlockExpression : IfExpression | Block | WhileExpression | ForExpression
9494
9595WhileExpression : token(While) token(LParen) Expression token(RParen) Expression
9696
97ForExpression : token(For) token(LParen) Symbol token(Comma) Expression option(token(Comma) token(Symbol)) token(RParen) Expression
98
9799BoolOrExpression : BoolAndExpression token(BoolOr) BoolOrExpression | BoolAndExpression
98100
99101ReturnExpression : token(Return) option(Expression)
src/all_types.hpp+20-2
......@@ -138,6 +138,7 @@ enum NodeType {
138138 NodeTypeIfBoolExpr,
139139 NodeTypeIfVarExpr,
140140 NodeTypeWhileExpr,
141 NodeTypeForExpr,
141142 NodeTypeLabel,
142143 NodeTypeGoto,
143144 NodeTypeBreak,
......@@ -393,6 +394,21 @@ struct AstNodeWhileExpr {
393394 bool condition_always_true;
394395 bool contains_break;
395396 Expr resolved_expr;
397 BlockContext *block_context;
398};
399
400struct AstNodeForExpr {
401 AstNode *elem_node; // always a symbol
402 AstNode *array_expr;
403 AstNode *index_node; // always a symbol, might be null
404 AstNode *body;
405
406 // populated by semantic analyzer
407 bool contains_break;
408 Expr resolved_expr;
409 BlockContext *block_context;
410 VariableTableEntry *elem_var;
411 VariableTableEntry *index_var;
396412};
397413
398414struct AstNodeLabel {
......@@ -605,6 +621,7 @@ struct AstNode {
605621 AstNodeIfBoolExpr if_bool_expr;
606622 AstNodeIfVarExpr if_var_expr;
607623 AstNodeWhileExpr while_expr;
624 AstNodeForExpr for_expr;
608625 AstNodeLabel label;
609626 AstNodeGoto goto_expr;
610627 AstNodeAsmExpr asm_expr;
......@@ -916,7 +933,8 @@ struct VariableTableEntry {
916933 bool is_ptr; // if true, value_ref is a pointer
917934 AstNode *decl_node;
918935 LLVMZigDILocalVariable *di_loc_var;
919 int arg_index;
936 int src_arg_index;
937 int gen_arg_index;
920938};
921939
922940struct BlockContext {
......@@ -927,8 +945,8 @@ struct BlockContext {
927945 HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table;
928946 ZigList<Cast *> cast_expr_alloca_list;
929947 ZigList<StructValExprCodeGen *> struct_val_expr_alloca_list;
948 ZigList<VariableTableEntry *> variable_list;
930949 AstNode *parent_loop_node;
931 AstNode *next_child_parent_loop_node;
932950 LLVMZigDIScope *di_scope;
933951};
934952
src/analyze.cpp+124-56
......@@ -60,6 +60,7 @@ static AstNode *first_executing_node(AstNode *node) {
6060 case NodeTypeStructField:
6161 case NodeTypeStructValueField:
6262 case NodeTypeWhileExpr:
63 case NodeTypeForExpr:
6364 case NodeTypeContainerInitExpr:
6465 case NodeTypeArrayType:
6566 return node;
......@@ -867,6 +868,7 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
867868 case NodeTypeIfBoolExpr:
868869 case NodeTypeIfVarExpr:
869870 case NodeTypeWhileExpr:
871 case NodeTypeForExpr:
870872 case NodeTypeLabel:
871873 case NodeTypeGoto:
872874 case NodeTypeBreak:
......@@ -1175,12 +1177,7 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) {
11751177 context->type_table.init(8);
11761178
11771179 if (parent) {
1178 if (parent->next_child_parent_loop_node) {
1179 context->parent_loop_node = parent->next_child_parent_loop_node;
1180 parent->next_child_parent_loop_node = nullptr;
1181 } else {
1182 context->parent_loop_node = parent->parent_loop_node;
1183 }
1180 context->parent_loop_node = parent->parent_loop_node;
11841181 }
11851182
11861183 if (node && node->type == NodeTypeFnDef) {
......@@ -1986,6 +1983,36 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
19861983 zig_unreachable();
19871984}
19881985
1986// Set name to nullptr to make the variable anonymous (not visible to programmer).
1987static VariableTableEntry *add_local_var(CodeGen *g, AstNode *source_node, BlockContext *context,
1988 Buf *name, TypeTableEntry *type_entry, bool is_const)
1989{
1990 VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1);
1991 variable_entry->type = type_entry;
1992
1993 if (name) {
1994 buf_init_from_buf(&variable_entry->name, name);
1995 VariableTableEntry *existing_var = find_local_variable(context, name);
1996
1997 if (existing_var) {
1998 add_node_error(g, source_node, buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
1999 variable_entry->type = g->builtin_types.entry_invalid;
2000 }
2001
2002 context->variable_table.put(&variable_entry->name, variable_entry);
2003 context->variable_list.append(variable_entry);
2004 } else {
2005 buf_init_from_str(&variable_entry->name, "_anon");
2006 context->variable_list.append(variable_entry);
2007 }
2008
2009 variable_entry->is_const = is_const;
2010 variable_entry->is_ptr = true;
2011 variable_entry->decl_node = source_node;
2012
2013 return variable_entry;
2014}
2015
19892016static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import,
19902017 BlockContext *context, AstNode *source_node,
19912018 AstNodeVariableDeclaration *variable_declaration,
......@@ -2037,38 +2064,26 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa
20372064 TypeTableEntry *type = explicit_type != nullptr ? explicit_type : implicit_type;
20382065 assert(type != nullptr); // should have been caught by the parser
20392066
2040 VariableTableEntry *existing_variable = find_local_variable(context, &variable_declaration->symbol);
2041 if (existing_variable) {
2042 add_node_error(g, source_node,
2043 buf_sprintf("redeclaration of variable '%s'", buf_ptr(&variable_declaration->symbol)));
2044 } else {
2045 VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1);
2046 buf_init_from_buf(&variable_entry->name, &variable_declaration->symbol);
2047 variable_entry->type = type;
2048 variable_entry->is_const = variable_declaration->is_const;
2049 variable_entry->is_ptr = true;
2050 variable_entry->decl_node = source_node;
2051 context->variable_table.put(&variable_entry->name, variable_entry);
2067 VariableTableEntry *var = add_local_var(g, source_node, context,
2068 &variable_declaration->symbol, type, variable_declaration->is_const);
20522069
2053 bool is_pub = (variable_declaration->visib_mod != VisibModPrivate);
2054 if (is_pub) {
2055 for (int i = 0; i < import->importers.length; i += 1) {
2056 ImporterInfo importer = import->importers.at(i);
2057 auto table_entry = importer.import->block_context->variable_table.maybe_get(&variable_entry->name);
2058 if (table_entry) {
2059 add_node_error(g, importer.source_node,
2060 buf_sprintf("import of variable '%s' overrides existing definition",
2061 buf_ptr(&variable_entry->name)));
2062 } else {
2063 importer.import->block_context->variable_table.put(&variable_entry->name, variable_entry);
2064 }
2070
2071 bool is_pub = (variable_declaration->visib_mod != VisibModPrivate);
2072 if (is_pub) {
2073 for (int i = 0; i < import->importers.length; i += 1) {
2074 ImporterInfo importer = import->importers.at(i);
2075 auto table_entry = importer.import->block_context->variable_table.maybe_get(&var->name);
2076 if (table_entry) {
2077 add_node_error(g, importer.source_node,
2078 buf_sprintf("import of variable '%s' overrides existing definition",
2079 buf_ptr(&var->name)));
2080 } else {
2081 importer.import->block_context->variable_table.put(&var->name, var);
20652082 }
20662083 }
2067
2068
2069 return variable_entry;
20702084 }
2071 return nullptr;
2085
2086 return var;
20722087}
20732088
20742089static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import,
......@@ -2172,11 +2187,15 @@ static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import,
21722187
21732188 AstNode *condition_node = node->data.while_expr.condition;
21742189 AstNode *while_body_node = node->data.while_expr.body;
2190
21752191 TypeTableEntry *condition_type = analyze_expression(g, import, context,
21762192 g->builtin_types.entry_bool, condition_node);
21772193
2178 context->next_child_parent_loop_node = node;
2179 analyze_expression(g, import, context, g->builtin_types.entry_void, while_body_node);
2194 BlockContext *child_context = new_block_context(node, context);
2195 child_context->parent_loop_node = node;
2196 node->data.while_expr.block_context = child_context;
2197
2198 analyze_expression(g, import, child_context, g->builtin_types.entry_void, while_body_node);
21802199
21812200
21822201 TypeTableEntry *expr_return_type = g->builtin_types.entry_void;
......@@ -2200,6 +2219,54 @@ static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import,
22002219 return expr_return_type;
22012220}
22022221
2222static TypeTableEntry *analyze_for_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
2223 TypeTableEntry *expected_type, AstNode *node)
2224{
2225 assert(node->type == NodeTypeForExpr);
2226
2227 AstNode *array_node = node->data.for_expr.array_expr;
2228 TypeTableEntry *array_type = analyze_expression(g, import, context, nullptr, array_node);
2229 TypeTableEntry *child_type;
2230 if (array_type->id == TypeTableEntryIdInvalid) {
2231 child_type = array_type;
2232 } else if (array_type->id == TypeTableEntryIdArray) {
2233 child_type = array_type->data.array.child_type;
2234 } else if (array_type->id == TypeTableEntryIdStruct &&
2235 array_type->data.structure.is_unknown_size_array)
2236 {
2237 TypeTableEntry *pointer_type = array_type->data.structure.fields[0].type_entry;
2238 assert(pointer_type->id == TypeTableEntryIdPointer);
2239 child_type = pointer_type->data.pointer.child_type;
2240 } else {
2241 add_node_error(g, node,
2242 buf_sprintf("iteration over non array type '%s'", buf_ptr(&array_type->name)));
2243 child_type = g->builtin_types.entry_invalid;
2244 }
2245
2246 BlockContext *child_context = new_block_context(node, context);
2247 node->data.for_expr.block_context = child_context;
2248
2249 AstNode *elem_var_node = node->data.for_expr.elem_node;
2250 Buf *elem_var_name = &elem_var_node->data.symbol_expr.symbol;
2251 node->data.for_expr.elem_var = add_local_var(g, elem_var_node, child_context, elem_var_name, child_type, true);
2252
2253 AstNode *index_var_node = node->data.for_expr.index_node;
2254 if (index_var_node) {
2255 Buf *index_var_name = &index_var_node->data.symbol_expr.symbol;
2256 node->data.for_expr.index_var = add_local_var(g, index_var_node, child_context, index_var_name,
2257 g->builtin_types.entry_usize, true);
2258 } else {
2259 node->data.for_expr.index_var = add_local_var(g, node, child_context, nullptr,
2260 g->builtin_types.entry_usize, true);
2261 }
2262
2263 AstNode *for_body_node = node->data.for_expr.body;
2264 analyze_expression(g, import, child_context, g->builtin_types.entry_void, for_body_node);
2265
2266
2267 return g->builtin_types.entry_void;
2268}
2269
22032270static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
22042271 TypeTableEntry *expected_type, AstNode *node)
22052272{
......@@ -3018,6 +3085,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
30183085 case NodeTypeWhileExpr:
30193086 return_type = analyze_while_expr(g, import, context, expected_type, node);
30203087 break;
3088 case NodeTypeForExpr:
3089 return_type = analyze_for_expr(g, import, context, expected_type, node);
3090 break;
30213091 case NodeTypeArrayType:
30223092 return_type = analyze_array_type(g, import, context, expected_type, node);
30233093 break;
......@@ -3081,6 +3151,7 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo
30813151
30823152 AstNodeFnProto *fn_proto = &fn_proto_node->data.fn_proto;
30833153 bool is_exported = (fn_proto->visib_mod == VisibModExport);
3154 int gen_arg_index = 0;
30843155 for (int i = 0; i < fn_proto->params.length; i += 1) {
30853156 AstNode *param_decl_node = fn_proto->params.at(i);
30863157 assert(param_decl_node->type == NodeTypeParamDecl);
......@@ -3099,28 +3170,15 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo
30993170 buf_sprintf("byvalue struct parameters not yet supported on exported functions"));
31003171 }
31013172
3102 VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1);
3103 buf_init_from_buf(&variable_entry->name, &param_decl->name);
3104 variable_entry->type = type;
3105 variable_entry->is_const = true;
3106 variable_entry->decl_node = param_decl_node;
3107 variable_entry->arg_index = i;
3173 VariableTableEntry *var = add_local_var(g, param_decl_node, context, &param_decl->name, type, true);
3174 var->src_arg_index = i;
3175 param_decl_node->data.param_decl.variable = var;
31083176
3109 param_decl_node->data.param_decl.variable = variable_entry;
3110
3111 VariableTableEntry *existing_entry = find_local_variable(context, &variable_entry->name);
3112 if (!existing_entry) {
3113 // unique definition
3114 context->variable_table.put(&variable_entry->name, variable_entry);
3177 if (type->size_in_bits > 0) {
3178 var->gen_arg_index = gen_arg_index;
3179 gen_arg_index += 1;
31153180 } else {
3116 add_node_error(g, node,
3117 buf_sprintf("redeclaration of parameter '%s'.", buf_ptr(&existing_entry->name)));
3118 if (existing_entry->type == variable_entry->type) {
3119 // types agree, so the type is probably good enough for the rest of analysis
3120 } else {
3121 // types disagree. don't trust either one of them.
3122 existing_entry->type = g->builtin_types.entry_invalid;;
3123 }
3181 var->gen_arg_index = -1;
31243182 }
31253183 }
31263184
......@@ -3187,6 +3245,7 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
31873245 case NodeTypeIfBoolExpr:
31883246 case NodeTypeIfVarExpr:
31893247 case NodeTypeWhileExpr:
3248 case NodeTypeForExpr:
31903249 case NodeTypeLabel:
31913250 case NodeTypeGoto:
31923251 case NodeTypeBreak:
......@@ -3281,6 +3340,10 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
32813340 collect_expr_decl_deps(g, import, node->data.while_expr.condition, decl_node);
32823341 collect_expr_decl_deps(g, import, node->data.while_expr.body, decl_node);
32833342 break;
3343 case NodeTypeForExpr:
3344 collect_expr_decl_deps(g, import, node->data.for_expr.array_expr, decl_node);
3345 collect_expr_decl_deps(g, import, node->data.for_expr.body, decl_node);
3346 break;
32843347 case NodeTypeBlock:
32853348 for (int i = 0; i < node->data.block.statements.length; i += 1) {
32863349 AstNode *stmt = node->data.block.statements.at(i);
......@@ -3505,6 +3568,7 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
35053568 case NodeTypeIfBoolExpr:
35063569 case NodeTypeIfVarExpr:
35073570 case NodeTypeWhileExpr:
3571 case NodeTypeForExpr:
35083572 case NodeTypeLabel:
35093573 case NodeTypeGoto:
35103574 case NodeTypeBreak:
......@@ -3681,6 +3745,8 @@ Expr *get_resolved_expr(AstNode *node) {
36813745 return &node->data.if_var_expr.resolved_expr;
36823746 case NodeTypeWhileExpr:
36833747 return &node->data.while_expr.resolved_expr;
3748 case NodeTypeForExpr:
3749 return &node->data.for_expr.resolved_expr;
36843750 case NodeTypeAsmExpr:
36853751 return &node->data.asm_expr.resolved_expr;
36863752 case NodeTypeContainerInitExpr:
......@@ -3743,6 +3809,7 @@ NumLitCodeGen *get_resolved_num_lit(AstNode *node) {
37433809 case NodeTypeIfBoolExpr:
37443810 case NodeTypeIfVarExpr:
37453811 case NodeTypeWhileExpr:
3812 case NodeTypeForExpr:
37463813 case NodeTypeAsmExpr:
37473814 case NodeTypeContainerInitExpr:
37483815 case NodeTypeRoot:
......@@ -3793,6 +3860,7 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) {
37933860 case NodeTypeIfBoolExpr:
37943861 case NodeTypeIfVarExpr:
37953862 case NodeTypeWhileExpr:
3863 case NodeTypeForExpr:
37963864 case NodeTypeAsmExpr:
37973865 case NodeTypeContainerInitExpr:
37983866 case NodeTypeRoot:
src/codegen.cpp+108-40
......@@ -526,41 +526,35 @@ static LLVMValueRef gen_array_base_ptr(CodeGen *g, AstNode *node) {
526526 return array_ptr;
527527}
528528
529static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {
530 assert(node->type == NodeTypeArrayAccessExpr);
531
532 AstNode *array_expr_node = node->data.array_access_expr.array_ref_expr;
533 TypeTableEntry *type_entry = get_expr_type(array_expr_node);
534
535 LLVMValueRef array_ptr = gen_array_base_ptr(g, array_expr_node);
536
537 LLVMValueRef subscript_value = gen_expr(g, node->data.array_access_expr.subscript);
529static LLVMValueRef gen_array_elem_ptr(CodeGen *g, AstNode *source_node, LLVMValueRef array_ptr,
530 TypeTableEntry *array_type, LLVMValueRef subscript_value)
531{
538532 assert(subscript_value);
539533
540 if (type_entry->size_in_bits == 0) {
534 if (array_type->size_in_bits == 0) {
541535 return nullptr;
542536 }
543537
544 if (type_entry->id == TypeTableEntryIdArray) {
538 if (array_type->id == TypeTableEntryIdArray) {
545539 LLVMValueRef indices[] = {
546540 LLVMConstNull(g->builtin_types.entry_usize->type_ref),
547541 subscript_value
548542 };
549 add_debug_source_node(g, node);
543 add_debug_source_node(g, source_node);
550544 return LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, "");
551 } else if (type_entry->id == TypeTableEntryIdPointer) {
545 } else if (array_type->id == TypeTableEntryIdPointer) {
552546 assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);
553547 LLVMValueRef indices[] = {
554548 subscript_value
555549 };
556 add_debug_source_node(g, node);
550 add_debug_source_node(g, source_node);
557551 return LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 1, "");
558 } else if (type_entry->id == TypeTableEntryIdStruct) {
559 assert(type_entry->data.structure.is_unknown_size_array);
552 } else if (array_type->id == TypeTableEntryIdStruct) {
553 assert(array_type->data.structure.is_unknown_size_array);
560554 assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);
561555 assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind);
562556
563 add_debug_source_node(g, node);
557 add_debug_source_node(g, source_node);
564558 LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, 0, "");
565559 LLVMValueRef ptr = LLVMBuildLoad(g->builder, ptr_ptr, "");
566560 return LLVMBuildInBoundsGEP(g->builder, ptr, &subscript_value, 1, "");
......@@ -569,6 +563,19 @@ static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {
569563 }
570564}
571565
566static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {
567 assert(node->type == NodeTypeArrayAccessExpr);
568
569 AstNode *array_expr_node = node->data.array_access_expr.array_ref_expr;
570 TypeTableEntry *array_type = get_expr_type(array_expr_node);
571
572 LLVMValueRef array_ptr = gen_array_base_ptr(g, array_expr_node);
573
574 LLVMValueRef subscript_value = gen_expr(g, node->data.array_access_expr.subscript);
575
576 return gen_array_elem_ptr(g, node, array_ptr, array_type, subscript_value);
577}
578
572579static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **out_type_entry) {
573580 assert(node->type == NodeTypeFieldAccessExpr);
574581
......@@ -1695,10 +1702,13 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
16951702 assert(node->data.while_expr.condition);
16961703 assert(node->data.while_expr.body);
16971704
1705 BlockContext *old_block_context = g->cur_block_context;
1706
16981707 bool condition_always_true = node->data.while_expr.condition_always_true;
16991708 bool contains_break = node->data.while_expr.contains_break;
17001709 if (condition_always_true) {
17011710 // generate a forever loop
1711 g->cur_block_context = node->data.while_expr.block_context;
17021712
17031713 LLVMBasicBlockRef body_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileBody");
17041714 LLVMBasicBlockRef end_block = nullptr;
......@@ -1735,6 +1745,7 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
17351745 LLVMBuildBr(g->builder, cond_block);
17361746
17371747 LLVMPositionBuilderAtEnd(g->builder, cond_block);
1748 g->cur_block_context = old_block_context;
17381749 LLVMValueRef cond_val = gen_expr(g, node->data.while_expr.condition);
17391750 add_debug_source_node(g, node->data.while_expr.condition);
17401751 LLVMBuildCondBr(g->builder, cond_val, body_block, end_block);
......@@ -1742,6 +1753,7 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
17421753 LLVMPositionBuilderAtEnd(g->builder, body_block);
17431754 g->break_block_stack.append(end_block);
17441755 g->continue_block_stack.append(cond_block);
1756 g->cur_block_context = node->data.while_expr.block_context;
17451757 gen_expr(g, node->data.while_expr.body);
17461758 g->break_block_stack.pop();
17471759 g->continue_block_stack.pop();
......@@ -1753,6 +1765,77 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
17531765 LLVMPositionBuilderAtEnd(g->builder, end_block);
17541766 }
17551767
1768 g->cur_block_context = old_block_context;
1769 return nullptr;
1770}
1771
1772static LLVMValueRef gen_for_expr(CodeGen *g, AstNode *node) {
1773 assert(node->type == NodeTypeForExpr);
1774 assert(node->data.for_expr.array_expr);
1775 assert(node->data.for_expr.body);
1776
1777 VariableTableEntry *elem_var = node->data.for_expr.elem_var;
1778 assert(elem_var);
1779
1780 TypeTableEntry *array_type = get_expr_type(node->data.for_expr.array_expr);
1781
1782 VariableTableEntry *index_var = node->data.for_expr.index_var;
1783 assert(index_var);
1784 LLVMValueRef index_ptr = index_var->value_ref;
1785 LLVMValueRef one_const = LLVMConstInt(g->builtin_types.entry_usize->type_ref, 1, false);
1786
1787 BlockContext *old_block_context = g->cur_block_context;
1788
1789 LLVMBasicBlockRef cond_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForCond");
1790 LLVMBasicBlockRef body_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForBody");
1791 LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForEnd");
1792
1793 LLVMValueRef array_val = gen_expr(g, node->data.for_expr.array_expr);
1794 add_debug_source_node(g, node);
1795 LLVMBuildStore(g->builder, LLVMConstNull(index_var->type->type_ref), index_ptr);
1796 LLVMValueRef len_val;
1797 TypeTableEntry *child_type;
1798 if (array_type->id == TypeTableEntryIdArray) {
1799 len_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
1800 array_type->data.array.len, false);
1801 child_type = array_type->data.array.child_type;
1802 } else if (array_type->id == TypeTableEntryIdStruct) {
1803 assert(array_type->data.structure.is_unknown_size_array);
1804 TypeTableEntry *child_ptr_type = array_type->data.structure.fields[0].type_entry;
1805 assert(child_ptr_type->id == TypeTableEntryIdPointer);
1806 child_type = child_ptr_type->data.pointer.child_type;
1807 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, array_val, 1, "");
1808 len_val = LLVMBuildLoad(g->builder, len_field_ptr, "");
1809 } else {
1810 zig_unreachable();
1811 }
1812 LLVMBuildBr(g->builder, cond_block);
1813
1814 LLVMPositionBuilderAtEnd(g->builder, cond_block);
1815 LLVMValueRef index_val = LLVMBuildLoad(g->builder, index_ptr, "");
1816 LLVMValueRef cond = LLVMBuildICmp(g->builder, LLVMIntSLT, index_val, len_val, "");
1817 LLVMBuildCondBr(g->builder, cond, body_block, end_block);
1818
1819 LLVMPositionBuilderAtEnd(g->builder, body_block);
1820 LLVMValueRef elem_ptr = gen_array_elem_ptr(g, node, array_val, array_type, index_val);
1821 LLVMValueRef elem_val = handle_is_ptr(child_type) ? elem_ptr : LLVMBuildLoad(g->builder, elem_ptr, "");
1822 gen_assign_raw(g, node, BinOpTypeAssign, elem_var->value_ref, elem_val,
1823 elem_var->type, child_type);
1824 g->break_block_stack.append(end_block);
1825 g->continue_block_stack.append(cond_block);
1826 g->cur_block_context = node->data.for_expr.block_context;
1827 gen_expr(g, node->data.for_expr.body);
1828 g->break_block_stack.pop();
1829 g->continue_block_stack.pop();
1830 if (get_expr_type(node->data.for_expr.body)->id != TypeTableEntryIdUnreachable) {
1831 add_debug_source_node(g, node);
1832 LLVMValueRef new_index_val = LLVMBuildAdd(g->builder, index_val, one_const, "");
1833 LLVMBuildStore(g->builder, new_index_val, index_ptr);
1834 LLVMBuildBr(g->builder, cond_block);
1835 }
1836
1837 LLVMPositionBuilderAtEnd(g->builder, end_block);
1838 g->cur_block_context = old_block_context;
17561839 return nullptr;
17571840}
17581841
......@@ -1935,6 +2018,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
19352018 return gen_if_var_expr(g, node);
19362019 case NodeTypeWhileExpr:
19372020 return gen_while_expr(g, node);
2021 case NodeTypeForExpr:
2022 return gen_for_expr(g, node);
19382023 case NodeTypeAsmExpr:
19392024 return gen_asm_expr(g, node);
19402025 case NodeTypeNumberLiteral:
......@@ -2177,22 +2262,6 @@ static void do_code_gen(CodeGen *g) {
21772262
21782263 fn_def_node->data.fn_def.block_context->di_scope = LLVMZigSubprogramToScope(subprogram);
21792264
2180 int non_void_param_count = count_non_void_params(g, &fn_proto->params);
2181 assert(non_void_param_count == (int)LLVMCountParams(fn));
2182 LLVMValueRef *params = allocate<LLVMValueRef>(non_void_param_count);
2183 LLVMGetParams(fn, params);
2184
2185 int non_void_index = 0;
2186 for (int param_i = 0; param_i < fn_proto->params.length; param_i += 1) {
2187 AstNode *param_decl = fn_proto->params.at(param_i);
2188 assert(param_decl->type == NodeTypeParamDecl);
2189 if (is_param_decl_type_void(g, param_decl))
2190 continue;
2191 VariableTableEntry *parameter_variable = fn_def_node->data.fn_def.block_context->variable_table.get(&param_decl->data.param_decl.name);
2192 parameter_variable->value_ref = params[non_void_index];
2193 non_void_index += 1;
2194 }
2195
21962265 AstNode *body_node = fn_def_node->data.fn_def.body;
21972266 build_label_blocks(g, body_node);
21982267
......@@ -2212,13 +2281,9 @@ static void do_code_gen(CodeGen *g) {
22122281
22132282 g->cur_block_context = block_context;
22142283
2215 auto it = block_context->variable_table.entry_iterator();
2216 for (;;) {
2217 auto *entry = it.next();
2218 if (!entry)
2219 break;
2284 for (int var_i = 0; var_i < block_context->variable_list.length; var_i += 1) {
2285 VariableTableEntry *var = block_context->variable_list.at(var_i);
22202286
2221 VariableTableEntry *var = entry->value;
22222287 if (var->type->size_in_bits == 0) {
22232288 continue;
22242289 }
......@@ -2227,7 +2292,10 @@ static void do_code_gen(CodeGen *g) {
22272292 unsigned arg_no;
22282293 if (block_context->node->type == NodeTypeFnDef) {
22292294 tag = LLVMZigTag_DW_arg_variable();
2230 arg_no = var->arg_index + 1;
2295 arg_no = var->gen_arg_index + 1;
2296
2297 var->is_ptr = false;
2298 var->value_ref = LLVMGetParam(fn, var->gen_arg_index);
22312299 } else {
22322300 tag = LLVMZigTag_DW_auto_variable();
22332301 arg_no = 0;
src/parser.cpp+57-1
......@@ -121,6 +121,8 @@ const char *node_type_str(NodeType node_type) {
121121 return "IfVarExpr";
122122 case NodeTypeWhileExpr:
123123 return "WhileExpr";
124 case NodeTypeForExpr:
125 return "ForExpr";
124126 case NodeTypeLabel:
125127 return "Label";
126128 case NodeTypeGoto:
......@@ -331,6 +333,15 @@ void ast_print(AstNode *node, int indent) {
331333 ast_print(node->data.while_expr.condition, indent + 2);
332334 ast_print(node->data.while_expr.body, indent + 2);
333335 break;
336 case NodeTypeForExpr:
337 fprintf(stderr, "%s\n", node_type_str(node->type));
338 ast_print(node->data.for_expr.elem_node, indent + 2);
339 ast_print(node->data.for_expr.array_expr, indent + 2);
340 if (node->data.for_expr.index_node) {
341 ast_print(node->data.for_expr.index_node, indent + 2);
342 }
343 ast_print(node->data.for_expr.body, indent + 2);
344 break;
334345 case NodeTypeLabel:
335346 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.label.name));
336347 break;
......@@ -2114,8 +2125,49 @@ static AstNode *ast_parse_while_expr(ParseContext *pc, int *token_index, bool ma
21142125 return node;
21152126}
21162127
2128static AstNode *ast_parse_symbol(ParseContext *pc, int *token_index) {
2129 Token *token = ast_eat_token(pc, token_index, TokenIdSymbol);
2130 AstNode *node = ast_create_node(pc, NodeTypeSymbol, token);
2131 ast_buf_from_token(pc, token, &node->data.symbol_expr.symbol);
2132 return node;
2133}
2134
21172135/*
2118BlockExpression : IfExpression | Block | WhileExpression
2136ForExpression : token(For) token(LParen) Symbol token(Comma) Expression option(token(Comma) token(Symbol)) token(RParen) Expression
2137*/
2138static AstNode *ast_parse_for_expr(ParseContext *pc, int *token_index, bool mandatory) {
2139 Token *token = &pc->tokens->at(*token_index);
2140
2141 if (token->id != TokenIdKeywordFor) {
2142 if (mandatory) {
2143 ast_invalid_token_error(pc, token);
2144 } else {
2145 return nullptr;
2146 }
2147 }
2148 *token_index += 1;
2149
2150 AstNode *node = ast_create_node(pc, NodeTypeForExpr, token);
2151
2152 ast_eat_token(pc, token_index, TokenIdLParen);
2153 node->data.for_expr.elem_node = ast_parse_symbol(pc, token_index);
2154 ast_eat_token(pc, token_index, TokenIdComma);
2155 node->data.for_expr.array_expr = ast_parse_expression(pc, token_index, true);
2156
2157 Token *comma = &pc->tokens->at(*token_index);
2158 if (comma->id == TokenIdComma) {
2159 *token_index += 1;
2160 node->data.for_expr.index_node = ast_parse_symbol(pc, token_index);
2161 }
2162
2163 ast_eat_token(pc, token_index, TokenIdRParen);
2164
2165 node->data.for_expr.body = ast_parse_expression(pc, token_index, true);
2166 return node;
2167}
2168
2169/*
2170BlockExpression : IfExpression | Block | WhileExpression | ForExpression
21192171*/
21202172static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool mandatory) {
21212173 Token *token = &pc->tokens->at(*token_index);
......@@ -2132,6 +2184,10 @@ static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool ma
21322184 if (while_expr)
21332185 return while_expr;
21342186
2187 AstNode *for_expr = ast_parse_for_expr(pc, token_index, false);
2188 if (for_expr)
2189 return for_expr;
2190
21352191 if (mandatory)
21362192 ast_invalid_token_error(pc, token);
21372193
src/tokenizer.cpp+3
......@@ -231,6 +231,8 @@ static void end_token(Tokenize *t) {
231231 t->cur_tok->id = TokenIdKeywordStruct;
232232 } else if (mem_eql_str(token_mem, token_len, "enum")) {
233233 t->cur_tok->id = TokenIdKeywordEnum;
234 } else if (mem_eql_str(token_mem, token_len, "for")) {
235 t->cur_tok->id = TokenIdKeywordFor;
234236 } else if (mem_eql_str(token_mem, token_len, "while")) {
235237 t->cur_tok->id = TokenIdKeywordWhile;
236238 } else if (mem_eql_str(token_mem, token_len, "continue")) {
......@@ -1028,6 +1030,7 @@ const char * token_name(TokenId id) {
10281030 case TokenIdKeywordStruct: return "struct";
10291031 case TokenIdKeywordEnum: return "enum";
10301032 case TokenIdKeywordWhile: return "while";
1033 case TokenIdKeywordFor: return "for";
10311034 case TokenIdKeywordContinue: return "continue";
10321035 case TokenIdKeywordBreak: return "break";
10331036 case TokenIdKeywordNull: return "null";
src/tokenizer.hpp+1
......@@ -31,6 +31,7 @@ enum TokenId {
3131 TokenIdKeywordStruct,
3232 TokenIdKeywordEnum,
3333 TokenIdKeywordWhile,
34 TokenIdKeywordFor,
3435 TokenIdKeywordContinue,
3536 TokenIdKeywordBreak,
3637 TokenIdKeywordNull,
std/bootstrap.zig+1-4
......@@ -25,12 +25,9 @@ fn strlen(ptr: &u8) usize => {
2525
2626fn call_main() unreachable => {
2727 var args: [argc][]u8;
28 var i : @typeof(argc) = 0;
29 // TODO for in loop over the array
30 while (i < argc) {
28 for (arg, args, i) {
3129 const ptr = argv[i];
3230 args[i] = ptr[0...strlen(ptr)];
33 i += 1;
3431 }
3532 exit(main(args))
3633}
test/run_tests.cpp+27-1
......@@ -1136,6 +1136,32 @@ pub fn main(args: [][]u8) i32 => {
11361136 return 0;
11371137}
11381138 )SOURCE", "hello\nthis\nis\nmy\nthing\n");
1139
1140 add_simple_case("for loops", R"SOURCE(
1141import "std.zig";
1142
1143pub fn main(args: [][]u8) i32 => {
1144 const array = []u8 {9, 8, 7, 6};
1145 for (item, array) {
1146 print_u64(item);
1147 print_str("\n");
1148 }
1149 for (item, array, index) {
1150 print_u64(index);
1151 print_str("\n");
1152 }
1153 const unknown_size: []u8 = array;
1154 for (item, unknown_size) {
1155 print_u64(item);
1156 print_str("\n");
1157 }
1158 for (item, unknown_size, index) {
1159 print_u64(index);
1160 print_str("\n");
1161 }
1162 return 0;
1163}
1164 )SOURCE", "9\n8\n7\n6\n0\n1\n2\n3\n9\n8\n7\n6\n0\n1\n2\n3\n");
11391165}
11401166
11411167
......@@ -1226,7 +1252,7 @@ fn b() => {}
12261252 add_compile_fail_case("parameter redeclaration", R"SOURCE(
12271253fn f(a : i32, a : i32) => {
12281254}
1229 )SOURCE", 1, ".tmp_source.zig:2:1: error: redeclaration of parameter 'a'");
1255 )SOURCE", 1, ".tmp_source.zig:2:15: error: redeclaration of variable 'a'");
12301256
12311257 add_compile_fail_case("local variable redeclaration", R"SOURCE(
12321258fn f() => {