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...@@ -90,10 +90,12 @@ AssignmentExpression : UnwrapMaybeExpression AssignmentOperator UnwrapMaybeExpre
9090
91AssignmentOperator : 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) 91AssignmentOperator : 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 | WhileExpression93BlockExpression : IfExpression | Block | WhileExpression | ForExpression
9494
95WhileExpression : token(While) token(LParen) Expression token(RParen) Expression95WhileExpression : 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
97BoolOrExpression : BoolAndExpression token(BoolOr) BoolOrExpression | BoolAndExpression99BoolOrExpression : BoolAndExpression token(BoolOr) BoolOrExpression | BoolAndExpression
98100
99ReturnExpression : token(Return) option(Expression)101ReturnExpression : token(Return) option(Expression)
src/all_types.hpp+20-2
...@@ -138,6 +138,7 @@ enum NodeType {...@@ -138,6 +138,7 @@ enum NodeType {
138 NodeTypeIfBoolExpr,138 NodeTypeIfBoolExpr,
139 NodeTypeIfVarExpr,139 NodeTypeIfVarExpr,
140 NodeTypeWhileExpr,140 NodeTypeWhileExpr,
141 NodeTypeForExpr,
141 NodeTypeLabel,142 NodeTypeLabel,
142 NodeTypeGoto,143 NodeTypeGoto,
143 NodeTypeBreak,144 NodeTypeBreak,
...@@ -393,6 +394,21 @@ struct AstNodeWhileExpr {...@@ -393,6 +394,21 @@ struct AstNodeWhileExpr {
393 bool condition_always_true;394 bool condition_always_true;
394 bool contains_break;395 bool contains_break;
395 Expr resolved_expr;396 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;
396};412};
397413
398struct AstNodeLabel {414struct AstNodeLabel {
...@@ -605,6 +621,7 @@ struct AstNode {...@@ -605,6 +621,7 @@ struct AstNode {
605 AstNodeIfBoolExpr if_bool_expr;621 AstNodeIfBoolExpr if_bool_expr;
606 AstNodeIfVarExpr if_var_expr;622 AstNodeIfVarExpr if_var_expr;
607 AstNodeWhileExpr while_expr;623 AstNodeWhileExpr while_expr;
624 AstNodeForExpr for_expr;
608 AstNodeLabel label;625 AstNodeLabel label;
609 AstNodeGoto goto_expr;626 AstNodeGoto goto_expr;
610 AstNodeAsmExpr asm_expr;627 AstNodeAsmExpr asm_expr;
...@@ -916,7 +933,8 @@ struct VariableTableEntry {...@@ -916,7 +933,8 @@ struct VariableTableEntry {
916 bool is_ptr; // if true, value_ref is a pointer933 bool is_ptr; // if true, value_ref is a pointer
917 AstNode *decl_node;934 AstNode *decl_node;
918 LLVMZigDILocalVariable *di_loc_var;935 LLVMZigDILocalVariable *di_loc_var;
919 int arg_index;936 int src_arg_index;
937 int gen_arg_index;
920};938};
921939
922struct BlockContext {940struct BlockContext {
...@@ -927,8 +945,8 @@ struct BlockContext {...@@ -927,8 +945,8 @@ struct BlockContext {
927 HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table;945 HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table;
928 ZigList<Cast *> cast_expr_alloca_list;946 ZigList<Cast *> cast_expr_alloca_list;
929 ZigList<StructValExprCodeGen *> struct_val_expr_alloca_list;947 ZigList<StructValExprCodeGen *> struct_val_expr_alloca_list;
948 ZigList<VariableTableEntry *> variable_list;
930 AstNode *parent_loop_node;949 AstNode *parent_loop_node;
931 AstNode *next_child_parent_loop_node;
932 LLVMZigDIScope *di_scope;950 LLVMZigDIScope *di_scope;
933};951};
934952
src/analyze.cpp+124-56
...@@ -60,6 +60,7 @@ static AstNode *first_executing_node(AstNode *node) {...@@ -60,6 +60,7 @@ static AstNode *first_executing_node(AstNode *node) {
60 case NodeTypeStructField:60 case NodeTypeStructField:
61 case NodeTypeStructValueField:61 case NodeTypeStructValueField:
62 case NodeTypeWhileExpr:62 case NodeTypeWhileExpr:
63 case NodeTypeForExpr:
63 case NodeTypeContainerInitExpr:64 case NodeTypeContainerInitExpr:
64 case NodeTypeArrayType:65 case NodeTypeArrayType:
65 return node;66 return node;
...@@ -867,6 +868,7 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode...@@ -867,6 +868,7 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
867 case NodeTypeIfBoolExpr:868 case NodeTypeIfBoolExpr:
868 case NodeTypeIfVarExpr:869 case NodeTypeIfVarExpr:
869 case NodeTypeWhileExpr:870 case NodeTypeWhileExpr:
871 case NodeTypeForExpr:
870 case NodeTypeLabel:872 case NodeTypeLabel:
871 case NodeTypeGoto:873 case NodeTypeGoto:
872 case NodeTypeBreak:874 case NodeTypeBreak:
...@@ -1175,12 +1177,7 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) {...@@ -1175,12 +1177,7 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) {
1175 context->type_table.init(8);1177 context->type_table.init(8);
11761178
1177 if (parent) {1179 if (parent) {
1178 if (parent->next_child_parent_loop_node) {1180 context->parent_loop_node = parent->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 }
1184 }1181 }
11851182
1186 if (node && node->type == NodeTypeFnDef) {1183 if (node && node->type == NodeTypeFnDef) {
...@@ -1986,6 +1983,36 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,...@@ -1986,6 +1983,36 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
1986 zig_unreachable();1983 zig_unreachable();
1987}1984}
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
1989static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import,2016static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import,
1990 BlockContext *context, AstNode *source_node,2017 BlockContext *context, AstNode *source_node,
1991 AstNodeVariableDeclaration *variable_declaration,2018 AstNodeVariableDeclaration *variable_declaration,
...@@ -2037,38 +2064,26 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa...@@ -2037,38 +2064,26 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa
2037 TypeTableEntry *type = explicit_type != nullptr ? explicit_type : implicit_type;2064 TypeTableEntry *type = explicit_type != nullptr ? explicit_type : implicit_type;
2038 assert(type != nullptr); // should have been caught by the parser2065 assert(type != nullptr); // should have been caught by the parser
20392066
2040 VariableTableEntry *existing_variable = find_local_variable(context, &variable_declaration->symbol);2067 VariableTableEntry *var = add_local_var(g, source_node, context,
2041 if (existing_variable) {2068 &variable_declaration->symbol, type, variable_declaration->is_const);
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);
20522069
2053 bool is_pub = (variable_declaration->visib_mod != VisibModPrivate);2070
2054 if (is_pub) {2071 bool is_pub = (variable_declaration->visib_mod != VisibModPrivate);
2055 for (int i = 0; i < import->importers.length; i += 1) {2072 if (is_pub) {
2056 ImporterInfo importer = import->importers.at(i);2073 for (int i = 0; i < import->importers.length; i += 1) {
2057 auto table_entry = importer.import->block_context->variable_table.maybe_get(&variable_entry->name);2074 ImporterInfo importer = import->importers.at(i);
2058 if (table_entry) {2075 auto table_entry = importer.import->block_context->variable_table.maybe_get(&var->name);
2059 add_node_error(g, importer.source_node,2076 if (table_entry) {
2060 buf_sprintf("import of variable '%s' overrides existing definition",2077 add_node_error(g, importer.source_node,
2061 buf_ptr(&variable_entry->name)));2078 buf_sprintf("import of variable '%s' overrides existing definition",
2062 } else {2079 buf_ptr(&var->name)));
2063 importer.import->block_context->variable_table.put(&variable_entry->name, variable_entry);2080 } else {
2064 }2081 importer.import->block_context->variable_table.put(&var->name, var);
2065 }2082 }
2066 }2083 }
2067
2068
2069 return variable_entry;
2070 }2084 }
2071 return nullptr;2085
2086 return var;
2072}2087}
20732088
2074static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import,2089static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import,
...@@ -2172,11 +2187,15 @@ static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import,...@@ -2172,11 +2187,15 @@ static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import,
21722187
2173 AstNode *condition_node = node->data.while_expr.condition;2188 AstNode *condition_node = node->data.while_expr.condition;
2174 AstNode *while_body_node = node->data.while_expr.body;2189 AstNode *while_body_node = node->data.while_expr.body;
2190
2175 TypeTableEntry *condition_type = analyze_expression(g, import, context,2191 TypeTableEntry *condition_type = analyze_expression(g, import, context,
2176 g->builtin_types.entry_bool, condition_node);2192 g->builtin_types.entry_bool, condition_node);
21772193
2178 context->next_child_parent_loop_node = node;2194 BlockContext *child_context = new_block_context(node, context);
2179 analyze_expression(g, import, context, g->builtin_types.entry_void, while_body_node);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
2182 TypeTableEntry *expr_return_type = g->builtin_types.entry_void;2201 TypeTableEntry *expr_return_type = g->builtin_types.entry_void;
...@@ -2200,6 +2219,54 @@ static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import,...@@ -2200,6 +2219,54 @@ static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import,
2200 return expr_return_type;2219 return expr_return_type;
2201}2220}
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
2203static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,2270static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
2204 TypeTableEntry *expected_type, AstNode *node)2271 TypeTableEntry *expected_type, AstNode *node)
2205{2272{
...@@ -3018,6 +3085,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -3018,6 +3085,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
3018 case NodeTypeWhileExpr:3085 case NodeTypeWhileExpr:
3019 return_type = analyze_while_expr(g, import, context, expected_type, node);3086 return_type = analyze_while_expr(g, import, context, expected_type, node);
3020 break;3087 break;
3088 case NodeTypeForExpr:
3089 return_type = analyze_for_expr(g, import, context, expected_type, node);
3090 break;
3021 case NodeTypeArrayType:3091 case NodeTypeArrayType:
3022 return_type = analyze_array_type(g, import, context, expected_type, node);3092 return_type = analyze_array_type(g, import, context, expected_type, node);
3023 break;3093 break;
...@@ -3081,6 +3151,7 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo...@@ -3081,6 +3151,7 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo
30813151
3082 AstNodeFnProto *fn_proto = &fn_proto_node->data.fn_proto;3152 AstNodeFnProto *fn_proto = &fn_proto_node->data.fn_proto;
3083 bool is_exported = (fn_proto->visib_mod == VisibModExport);3153 bool is_exported = (fn_proto->visib_mod == VisibModExport);
3154 int gen_arg_index = 0;
3084 for (int i = 0; i < fn_proto->params.length; i += 1) {3155 for (int i = 0; i < fn_proto->params.length; i += 1) {
3085 AstNode *param_decl_node = fn_proto->params.at(i);3156 AstNode *param_decl_node = fn_proto->params.at(i);
3086 assert(param_decl_node->type == NodeTypeParamDecl);3157 assert(param_decl_node->type == NodeTypeParamDecl);
...@@ -3099,28 +3170,15 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo...@@ -3099,28 +3170,15 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo
3099 buf_sprintf("byvalue struct parameters not yet supported on exported functions"));3170 buf_sprintf("byvalue struct parameters not yet supported on exported functions"));
3100 }3171 }
31013172
3102 VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1);3173 VariableTableEntry *var = add_local_var(g, param_decl_node, context, &param_decl->name, type, true);
3103 buf_init_from_buf(&variable_entry->name, &param_decl->name);3174 var->src_arg_index = i;
3104 variable_entry->type = type;3175 param_decl_node->data.param_decl.variable = var;
3105 variable_entry->is_const = true;
3106 variable_entry->decl_node = param_decl_node;
3107 variable_entry->arg_index = i;
31083176
3109 param_decl_node->data.param_decl.variable = variable_entry;3177 if (type->size_in_bits > 0) {
31103178 var->gen_arg_index = gen_arg_index;
3111 VariableTableEntry *existing_entry = find_local_variable(context, &variable_entry->name);3179 gen_arg_index += 1;
3112 if (!existing_entry) {
3113 // unique definition
3114 context->variable_table.put(&variable_entry->name, variable_entry);
3115 } else {3180 } else {
3116 add_node_error(g, node,3181 var->gen_arg_index = -1;
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 }
3124 }3182 }
3125 }3183 }
31263184
...@@ -3187,6 +3245,7 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode...@@ -3187,6 +3245,7 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
3187 case NodeTypeIfBoolExpr:3245 case NodeTypeIfBoolExpr:
3188 case NodeTypeIfVarExpr:3246 case NodeTypeIfVarExpr:
3189 case NodeTypeWhileExpr:3247 case NodeTypeWhileExpr:
3248 case NodeTypeForExpr:
3190 case NodeTypeLabel:3249 case NodeTypeLabel:
3191 case NodeTypeGoto:3250 case NodeTypeGoto:
3192 case NodeTypeBreak:3251 case NodeTypeBreak:
...@@ -3281,6 +3340,10 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode...@@ -3281,6 +3340,10 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
3281 collect_expr_decl_deps(g, import, node->data.while_expr.condition, decl_node);3340 collect_expr_decl_deps(g, import, node->data.while_expr.condition, decl_node);
3282 collect_expr_decl_deps(g, import, node->data.while_expr.body, decl_node);3341 collect_expr_decl_deps(g, import, node->data.while_expr.body, decl_node);
3283 break;3342 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;
3284 case NodeTypeBlock:3347 case NodeTypeBlock:
3285 for (int i = 0; i < node->data.block.statements.length; i += 1) {3348 for (int i = 0; i < node->data.block.statements.length; i += 1) {
3286 AstNode *stmt = node->data.block.statements.at(i);3349 AstNode *stmt = node->data.block.statements.at(i);
...@@ -3505,6 +3568,7 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast...@@ -3505,6 +3568,7 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
3505 case NodeTypeIfBoolExpr:3568 case NodeTypeIfBoolExpr:
3506 case NodeTypeIfVarExpr:3569 case NodeTypeIfVarExpr:
3507 case NodeTypeWhileExpr:3570 case NodeTypeWhileExpr:
3571 case NodeTypeForExpr:
3508 case NodeTypeLabel:3572 case NodeTypeLabel:
3509 case NodeTypeGoto:3573 case NodeTypeGoto:
3510 case NodeTypeBreak:3574 case NodeTypeBreak:
...@@ -3681,6 +3745,8 @@ Expr *get_resolved_expr(AstNode *node) {...@@ -3681,6 +3745,8 @@ Expr *get_resolved_expr(AstNode *node) {
3681 return &node->data.if_var_expr.resolved_expr;3745 return &node->data.if_var_expr.resolved_expr;
3682 case NodeTypeWhileExpr:3746 case NodeTypeWhileExpr:
3683 return &node->data.while_expr.resolved_expr;3747 return &node->data.while_expr.resolved_expr;
3748 case NodeTypeForExpr:
3749 return &node->data.for_expr.resolved_expr;
3684 case NodeTypeAsmExpr:3750 case NodeTypeAsmExpr:
3685 return &node->data.asm_expr.resolved_expr;3751 return &node->data.asm_expr.resolved_expr;
3686 case NodeTypeContainerInitExpr:3752 case NodeTypeContainerInitExpr:
...@@ -3743,6 +3809,7 @@ NumLitCodeGen *get_resolved_num_lit(AstNode *node) {...@@ -3743,6 +3809,7 @@ NumLitCodeGen *get_resolved_num_lit(AstNode *node) {
3743 case NodeTypeIfBoolExpr:3809 case NodeTypeIfBoolExpr:
3744 case NodeTypeIfVarExpr:3810 case NodeTypeIfVarExpr:
3745 case NodeTypeWhileExpr:3811 case NodeTypeWhileExpr:
3812 case NodeTypeForExpr:
3746 case NodeTypeAsmExpr:3813 case NodeTypeAsmExpr:
3747 case NodeTypeContainerInitExpr:3814 case NodeTypeContainerInitExpr:
3748 case NodeTypeRoot:3815 case NodeTypeRoot:
...@@ -3793,6 +3860,7 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) {...@@ -3793,6 +3860,7 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) {
3793 case NodeTypeIfBoolExpr:3860 case NodeTypeIfBoolExpr:
3794 case NodeTypeIfVarExpr:3861 case NodeTypeIfVarExpr:
3795 case NodeTypeWhileExpr:3862 case NodeTypeWhileExpr:
3863 case NodeTypeForExpr:
3796 case NodeTypeAsmExpr:3864 case NodeTypeAsmExpr:
3797 case NodeTypeContainerInitExpr:3865 case NodeTypeContainerInitExpr:
3798 case NodeTypeRoot:3866 case NodeTypeRoot:
src/codegen.cpp+108-40
...@@ -526,41 +526,35 @@ static LLVMValueRef gen_array_base_ptr(CodeGen *g, AstNode *node) {...@@ -526,41 +526,35 @@ static LLVMValueRef gen_array_base_ptr(CodeGen *g, AstNode *node) {
526 return array_ptr;526 return array_ptr;
527}527}
528528
529static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {529static LLVMValueRef gen_array_elem_ptr(CodeGen *g, AstNode *source_node, LLVMValueRef array_ptr,
530 assert(node->type == NodeTypeArrayAccessExpr);530 TypeTableEntry *array_type, LLVMValueRef subscript_value)
531531{
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);
538 assert(subscript_value);532 assert(subscript_value);
539533
540 if (type_entry->size_in_bits == 0) {534 if (array_type->size_in_bits == 0) {
541 return nullptr;535 return nullptr;
542 }536 }
543537
544 if (type_entry->id == TypeTableEntryIdArray) {538 if (array_type->id == TypeTableEntryIdArray) {
545 LLVMValueRef indices[] = {539 LLVMValueRef indices[] = {
546 LLVMConstNull(g->builtin_types.entry_usize->type_ref),540 LLVMConstNull(g->builtin_types.entry_usize->type_ref),
547 subscript_value541 subscript_value
548 };542 };
549 add_debug_source_node(g, node);543 add_debug_source_node(g, source_node);
550 return LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, "");544 return LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, "");
551 } else if (type_entry->id == TypeTableEntryIdPointer) {545 } else if (array_type->id == TypeTableEntryIdPointer) {
552 assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);546 assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);
553 LLVMValueRef indices[] = {547 LLVMValueRef indices[] = {
554 subscript_value548 subscript_value
555 };549 };
556 add_debug_source_node(g, node);550 add_debug_source_node(g, source_node);
557 return LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 1, "");551 return LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 1, "");
558 } else if (type_entry->id == TypeTableEntryIdStruct) {552 } else if (array_type->id == TypeTableEntryIdStruct) {
559 assert(type_entry->data.structure.is_unknown_size_array);553 assert(array_type->data.structure.is_unknown_size_array);
560 assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);554 assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);
561 assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind);555 assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind);
562556
563 add_debug_source_node(g, node);557 add_debug_source_node(g, source_node);
564 LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, 0, "");558 LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, 0, "");
565 LLVMValueRef ptr = LLVMBuildLoad(g->builder, ptr_ptr, "");559 LLVMValueRef ptr = LLVMBuildLoad(g->builder, ptr_ptr, "");
566 return LLVMBuildInBoundsGEP(g->builder, ptr, &subscript_value, 1, "");560 return LLVMBuildInBoundsGEP(g->builder, ptr, &subscript_value, 1, "");
...@@ -569,6 +563,19 @@ static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {...@@ -569,6 +563,19 @@ static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {
569 }563 }
570}564}
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
572static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **out_type_entry) {579static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **out_type_entry) {
573 assert(node->type == NodeTypeFieldAccessExpr);580 assert(node->type == NodeTypeFieldAccessExpr);
574581
...@@ -1695,10 +1702,13 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {...@@ -1695,10 +1702,13 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
1695 assert(node->data.while_expr.condition);1702 assert(node->data.while_expr.condition);
1696 assert(node->data.while_expr.body);1703 assert(node->data.while_expr.body);
16971704
1705 BlockContext *old_block_context = g->cur_block_context;
1706
1698 bool condition_always_true = node->data.while_expr.condition_always_true;1707 bool condition_always_true = node->data.while_expr.condition_always_true;
1699 bool contains_break = node->data.while_expr.contains_break;1708 bool contains_break = node->data.while_expr.contains_break;
1700 if (condition_always_true) {1709 if (condition_always_true) {
1701 // generate a forever loop1710 // generate a forever loop
1711 g->cur_block_context = node->data.while_expr.block_context;
17021712
1703 LLVMBasicBlockRef body_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileBody");1713 LLVMBasicBlockRef body_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileBody");
1704 LLVMBasicBlockRef end_block = nullptr;1714 LLVMBasicBlockRef end_block = nullptr;
...@@ -1735,6 +1745,7 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {...@@ -1735,6 +1745,7 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
1735 LLVMBuildBr(g->builder, cond_block);1745 LLVMBuildBr(g->builder, cond_block);
17361746
1737 LLVMPositionBuilderAtEnd(g->builder, cond_block);1747 LLVMPositionBuilderAtEnd(g->builder, cond_block);
1748 g->cur_block_context = old_block_context;
1738 LLVMValueRef cond_val = gen_expr(g, node->data.while_expr.condition);1749 LLVMValueRef cond_val = gen_expr(g, node->data.while_expr.condition);
1739 add_debug_source_node(g, node->data.while_expr.condition);1750 add_debug_source_node(g, node->data.while_expr.condition);
1740 LLVMBuildCondBr(g->builder, cond_val, body_block, end_block);1751 LLVMBuildCondBr(g->builder, cond_val, body_block, end_block);
...@@ -1742,6 +1753,7 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {...@@ -1742,6 +1753,7 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
1742 LLVMPositionBuilderAtEnd(g->builder, body_block);1753 LLVMPositionBuilderAtEnd(g->builder, body_block);
1743 g->break_block_stack.append(end_block);1754 g->break_block_stack.append(end_block);
1744 g->continue_block_stack.append(cond_block);1755 g->continue_block_stack.append(cond_block);
1756 g->cur_block_context = node->data.while_expr.block_context;
1745 gen_expr(g, node->data.while_expr.body);1757 gen_expr(g, node->data.while_expr.body);
1746 g->break_block_stack.pop();1758 g->break_block_stack.pop();
1747 g->continue_block_stack.pop();1759 g->continue_block_stack.pop();
...@@ -1753,6 +1765,77 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {...@@ -1753,6 +1765,77 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
1753 LLVMPositionBuilderAtEnd(g->builder, end_block);1765 LLVMPositionBuilderAtEnd(g->builder, end_block);
1754 }1766 }
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;
1756 return nullptr;1839 return nullptr;
1757}1840}
17581841
...@@ -1935,6 +2018,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {...@@ -1935,6 +2018,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
1935 return gen_if_var_expr(g, node);2018 return gen_if_var_expr(g, node);
1936 case NodeTypeWhileExpr:2019 case NodeTypeWhileExpr:
1937 return gen_while_expr(g, node);2020 return gen_while_expr(g, node);
2021 case NodeTypeForExpr:
2022 return gen_for_expr(g, node);
1938 case NodeTypeAsmExpr:2023 case NodeTypeAsmExpr:
1939 return gen_asm_expr(g, node);2024 return gen_asm_expr(g, node);
1940 case NodeTypeNumberLiteral:2025 case NodeTypeNumberLiteral:
...@@ -2177,22 +2262,6 @@ static void do_code_gen(CodeGen *g) {...@@ -2177,22 +2262,6 @@ static void do_code_gen(CodeGen *g) {
21772262
2178 fn_def_node->data.fn_def.block_context->di_scope = LLVMZigSubprogramToScope(subprogram);2263 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
2196 AstNode *body_node = fn_def_node->data.fn_def.body;2265 AstNode *body_node = fn_def_node->data.fn_def.body;
2197 build_label_blocks(g, body_node);2266 build_label_blocks(g, body_node);
21982267
...@@ -2212,13 +2281,9 @@ static void do_code_gen(CodeGen *g) {...@@ -2212,13 +2281,9 @@ static void do_code_gen(CodeGen *g) {
22122281
2213 g->cur_block_context = block_context;2282 g->cur_block_context = block_context;
22142283
2215 auto it = block_context->variable_table.entry_iterator();2284 for (int var_i = 0; var_i < block_context->variable_list.length; var_i += 1) {
2216 for (;;) {2285 VariableTableEntry *var = block_context->variable_list.at(var_i);
2217 auto *entry = it.next();
2218 if (!entry)
2219 break;
22202286
2221 VariableTableEntry *var = entry->value;
2222 if (var->type->size_in_bits == 0) {2287 if (var->type->size_in_bits == 0) {
2223 continue;2288 continue;
2224 }2289 }
...@@ -2227,7 +2292,10 @@ static void do_code_gen(CodeGen *g) {...@@ -2227,7 +2292,10 @@ static void do_code_gen(CodeGen *g) {
2227 unsigned arg_no;2292 unsigned arg_no;
2228 if (block_context->node->type == NodeTypeFnDef) {2293 if (block_context->node->type == NodeTypeFnDef) {
2229 tag = LLVMZigTag_DW_arg_variable();2294 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);
2231 } else {2299 } else {
2232 tag = LLVMZigTag_DW_auto_variable();2300 tag = LLVMZigTag_DW_auto_variable();
2233 arg_no = 0;2301 arg_no = 0;
src/parser.cpp+57-1
...@@ -121,6 +121,8 @@ const char *node_type_str(NodeType node_type) {...@@ -121,6 +121,8 @@ const char *node_type_str(NodeType node_type) {
121 return "IfVarExpr";121 return "IfVarExpr";
122 case NodeTypeWhileExpr:122 case NodeTypeWhileExpr:
123 return "WhileExpr";123 return "WhileExpr";
124 case NodeTypeForExpr:
125 return "ForExpr";
124 case NodeTypeLabel:126 case NodeTypeLabel:
125 return "Label";127 return "Label";
126 case NodeTypeGoto:128 case NodeTypeGoto:
...@@ -331,6 +333,15 @@ void ast_print(AstNode *node, int indent) {...@@ -331,6 +333,15 @@ void ast_print(AstNode *node, int indent) {
331 ast_print(node->data.while_expr.condition, indent + 2);333 ast_print(node->data.while_expr.condition, indent + 2);
332 ast_print(node->data.while_expr.body, indent + 2);334 ast_print(node->data.while_expr.body, indent + 2);
333 break;335 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;
334 case NodeTypeLabel:345 case NodeTypeLabel:
335 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.label.name));346 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.label.name));
336 break;347 break;
...@@ -2114,8 +2125,49 @@ static AstNode *ast_parse_while_expr(ParseContext *pc, int *token_index, bool ma...@@ -2114,8 +2125,49 @@ static AstNode *ast_parse_while_expr(ParseContext *pc, int *token_index, bool ma
2114 return node;2125 return node;
2115}2126}
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
2117/*2135/*
2118BlockExpression : IfExpression | Block | WhileExpression2136ForExpression : 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
2119*/2171*/
2120static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool mandatory) {2172static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool mandatory) {
2121 Token *token = &pc->tokens->at(*token_index);2173 Token *token = &pc->tokens->at(*token_index);
...@@ -2132,6 +2184,10 @@ static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool ma...@@ -2132,6 +2184,10 @@ static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool ma
2132 if (while_expr)2184 if (while_expr)
2133 return while_expr;2185 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
2135 if (mandatory)2191 if (mandatory)
2136 ast_invalid_token_error(pc, token);2192 ast_invalid_token_error(pc, token);
21372193
src/tokenizer.cpp+3
...@@ -231,6 +231,8 @@ static void end_token(Tokenize *t) {...@@ -231,6 +231,8 @@ static void end_token(Tokenize *t) {
231 t->cur_tok->id = TokenIdKeywordStruct;231 t->cur_tok->id = TokenIdKeywordStruct;
232 } else if (mem_eql_str(token_mem, token_len, "enum")) {232 } else if (mem_eql_str(token_mem, token_len, "enum")) {
233 t->cur_tok->id = TokenIdKeywordEnum;233 t->cur_tok->id = TokenIdKeywordEnum;
234 } else if (mem_eql_str(token_mem, token_len, "for")) {
235 t->cur_tok->id = TokenIdKeywordFor;
234 } else if (mem_eql_str(token_mem, token_len, "while")) {236 } else if (mem_eql_str(token_mem, token_len, "while")) {
235 t->cur_tok->id = TokenIdKeywordWhile;237 t->cur_tok->id = TokenIdKeywordWhile;
236 } else if (mem_eql_str(token_mem, token_len, "continue")) {238 } else if (mem_eql_str(token_mem, token_len, "continue")) {
...@@ -1028,6 +1030,7 @@ const char * token_name(TokenId id) {...@@ -1028,6 +1030,7 @@ const char * token_name(TokenId id) {
1028 case TokenIdKeywordStruct: return "struct";1030 case TokenIdKeywordStruct: return "struct";
1029 case TokenIdKeywordEnum: return "enum";1031 case TokenIdKeywordEnum: return "enum";
1030 case TokenIdKeywordWhile: return "while";1032 case TokenIdKeywordWhile: return "while";
1033 case TokenIdKeywordFor: return "for";
1031 case TokenIdKeywordContinue: return "continue";1034 case TokenIdKeywordContinue: return "continue";
1032 case TokenIdKeywordBreak: return "break";1035 case TokenIdKeywordBreak: return "break";
1033 case TokenIdKeywordNull: return "null";1036 case TokenIdKeywordNull: return "null";
src/tokenizer.hpp+1
...@@ -31,6 +31,7 @@ enum TokenId {...@@ -31,6 +31,7 @@ enum TokenId {
31 TokenIdKeywordStruct,31 TokenIdKeywordStruct,
32 TokenIdKeywordEnum,32 TokenIdKeywordEnum,
33 TokenIdKeywordWhile,33 TokenIdKeywordWhile,
34 TokenIdKeywordFor,
34 TokenIdKeywordContinue,35 TokenIdKeywordContinue,
35 TokenIdKeywordBreak,36 TokenIdKeywordBreak,
36 TokenIdKeywordNull,37 TokenIdKeywordNull,
std/bootstrap.zig+1-4
...@@ -25,12 +25,9 @@ fn strlen(ptr: &u8) usize => {...@@ -25,12 +25,9 @@ fn strlen(ptr: &u8) usize => {
2525
26fn call_main() unreachable => {26fn call_main() unreachable => {
27 var args: [argc][]u8;27 var args: [argc][]u8;
28 var i : @typeof(argc) = 0;28 for (arg, args, i) {
29 // TODO for in loop over the array
30 while (i < argc) {
31 const ptr = argv[i];29 const ptr = argv[i];
32 args[i] = ptr[0...strlen(ptr)];30 args[i] = ptr[0...strlen(ptr)];
33 i += 1;
34 }31 }
35 exit(main(args))32 exit(main(args))
36}33}
test/run_tests.cpp+27-1
...@@ -1136,6 +1136,32 @@ pub fn main(args: [][]u8) i32 => {...@@ -1136,6 +1136,32 @@ pub fn main(args: [][]u8) i32 => {
1136 return 0;1136 return 0;
1137}1137}
1138 )SOURCE", "hello\nthis\nis\nmy\nthing\n");1138 )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");
1139}1165}
11401166
11411167
...@@ -1226,7 +1252,7 @@ fn b() => {}...@@ -1226,7 +1252,7 @@ fn b() => {}
1226 add_compile_fail_case("parameter redeclaration", R"SOURCE(1252 add_compile_fail_case("parameter redeclaration", R"SOURCE(
1227fn f(a : i32, a : i32) => {1253fn f(a : i32, a : i32) => {
1228}1254}
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
1231 add_compile_fail_case("local variable redeclaration", R"SOURCE(1257 add_compile_fail_case("local variable redeclaration", R"SOURCE(
1232fn f() => {1258fn f() => {