| author | |
| committer | |
| log | 6acc354957752e2cfa8d67bdd0e4c3b42f9be3c3 |
| tree | df6c6511e3ded50d1be9d59940d093a3470b93b4 |
| parent | a25307c0a1b45d0c7b83158349fbc57626baf656 |
see #517 files changed, 46 insertions(+), 6 deletions(-)
doc/langref.md+1-1| ... | ... | @@ -81,7 +81,7 @@ SwitchItem = Expression | (Expression "..." Expression) |
| 81 | 81 | |
| 82 | 82 | WhileExpression = "while" "(" Expression option(";" Expression) ")" Expression |
| 83 | 83 | |
| 84 | ForExpression = "for" "(" Expression ")" option("|" "Symbol" option("," "Symbol") "|") Expression | |
| 84 | ForExpression = "for" "(" Expression ")" option("|" option("*") "Symbol" option("," "Symbol") "|") Expression | |
| 85 | 85 | |
| 86 | 86 | BoolOrExpression = BoolAndExpression "||" BoolOrExpression | BoolAndExpression |
| 87 | 87 |
src/all_types.hpp+1| ... | ... | @@ -508,6 +508,7 @@ struct AstNodeForExpr { |
| 508 | 508 | Expr resolved_expr; |
| 509 | 509 | VariableTableEntry *elem_var; |
| 510 | 510 | VariableTableEntry *index_var; |
| 511 | bool elem_is_ptr; | |
| 511 | 512 | }; |
| 512 | 513 | |
| 513 | 514 | struct AstNodeSwitchExpr { |
src/analyze.cpp+8-1| ... | ... | @@ -3567,6 +3567,13 @@ static TypeTableEntry *analyze_for_expr(CodeGen *g, ImportTableEntry *import, Bl |
| 3567 | 3567 | child_type = g->builtin_types.entry_invalid; |
| 3568 | 3568 | } |
| 3569 | 3569 | |
| 3570 | TypeTableEntry *var_type; | |
| 3571 | if (node->data.for_expr.elem_is_ptr) { | |
| 3572 | var_type = get_pointer_to_type(g, child_type, false); | |
| 3573 | } else { | |
| 3574 | var_type = child_type; | |
| 3575 | } | |
| 3576 | ||
| 3570 | 3577 | BlockContext *child_context = new_block_context(node, context); |
| 3571 | 3578 | child_context->parent_loop_node = node; |
| 3572 | 3579 | |
| ... | ... | @@ -3574,7 +3581,7 @@ static TypeTableEntry *analyze_for_expr(CodeGen *g, ImportTableEntry *import, Bl |
| 3574 | 3581 | elem_var_node->block_context = child_context; |
| 3575 | 3582 | Buf *elem_var_name = &elem_var_node->data.symbol_expr.symbol; |
| 3576 | 3583 | node->data.for_expr.elem_var = add_local_var(g, elem_var_node, import, child_context, elem_var_name, |
| 3577 | child_type, true, nullptr); | |
| 3584 | var_type, true, nullptr); | |
| 3578 | 3585 | |
| 3579 | 3586 | AstNode *index_var_node = node->data.for_expr.index_node; |
| 3580 | 3587 | if (index_var_node) { |
src/codegen.cpp+8-3| ... | ... | @@ -2427,9 +2427,14 @@ static LLVMValueRef gen_for_expr(CodeGen *g, AstNode *node) { |
| 2427 | 2427 | |
| 2428 | 2428 | LLVMPositionBuilderAtEnd(g->builder, body_block); |
| 2429 | 2429 | LLVMValueRef elem_ptr = gen_array_elem_ptr(g, node, array_val, array_type, index_val); |
| 2430 | LLVMValueRef elem_val = handle_is_ptr(child_type) ? elem_ptr : LLVMBuildLoad(g->builder, elem_ptr, ""); | |
| 2431 | gen_assign_raw(g, node, BinOpTypeAssign, elem_var->value_ref, elem_val, | |
| 2432 | elem_var->type, child_type); | |
| 2430 | ||
| 2431 | LLVMValueRef elem_val; | |
| 2432 | if (node->data.for_expr.elem_is_ptr) { | |
| 2433 | elem_val = elem_ptr; | |
| 2434 | } else { | |
| 2435 | elem_val = handle_is_ptr(child_type) ? elem_ptr : LLVMBuildLoad(g->builder, elem_ptr, ""); | |
| 2436 | } | |
| 2437 | gen_assign_raw(g, node, BinOpTypeAssign, elem_var->value_ref, elem_val, elem_var->type, child_type); | |
| 2433 | 2438 | gen_var_debug_decl(g, elem_var); |
| 2434 | 2439 | g->break_block_stack.append(end_block); |
| 2435 | 2440 | g->continue_block_stack.append(continue_block); |
src/eval.cpp+4| ... | ... | @@ -812,6 +812,10 @@ static bool eval_for_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { |
| 812 | 812 | assert(elem_node->type == NodeTypeSymbol); |
| 813 | 813 | Buf *elem_var_name = &elem_node->data.symbol_expr.symbol; |
| 814 | 814 | |
| 815 | if (node->data.for_expr.elem_is_ptr) { | |
| 816 | zig_panic("TODO"); | |
| 817 | } | |
| 818 | ||
| 815 | 819 | Buf *index_var_name = nullptr; |
| 816 | 820 | if (index_node) { |
| 817 | 821 | assert(index_node->type == NodeTypeSymbol); |
src/parser.cpp+8-1| ... | ... | @@ -1932,7 +1932,7 @@ static AstNode *ast_parse_symbol(ParseContext *pc, int *token_index) { |
| 1932 | 1932 | } |
| 1933 | 1933 | |
| 1934 | 1934 | /* |
| 1935 | ForExpression = "for" "(" Expression ")" option("|" "Symbol" option("," "Symbol") "|") Expression | |
| 1935 | ForExpression = "for" "(" Expression ")" option("|" option("*") "Symbol" option("," "Symbol") "|") Expression | |
| 1936 | 1936 | */ |
| 1937 | 1937 | static AstNode *ast_parse_for_expr(ParseContext *pc, int *token_index, bool mandatory) { |
| 1938 | 1938 | Token *token = &pc->tokens->at(*token_index); |
| ... | ... | @@ -1955,6 +1955,13 @@ static AstNode *ast_parse_for_expr(ParseContext *pc, int *token_index, bool mand |
| 1955 | 1955 | Token *maybe_bar = &pc->tokens->at(*token_index); |
| 1956 | 1956 | if (maybe_bar->id == TokenIdBinOr) { |
| 1957 | 1957 | *token_index += 1; |
| 1958 | ||
| 1959 | Token *maybe_star = &pc->tokens->at(*token_index); | |
| 1960 | if (maybe_star->id == TokenIdStar) { | |
| 1961 | *token_index += 1; | |
| 1962 | node->data.for_expr.elem_is_ptr = true; | |
| 1963 | } | |
| 1964 | ||
| 1958 | 1965 | node->data.for_expr.elem_node = ast_parse_symbol(pc, token_index); |
| 1959 | 1966 | |
| 1960 | 1967 | Token *maybe_comma = &pc->tokens->at(*token_index); |
test/self_hosted.zig+16| ... | ... | @@ -1269,3 +1269,19 @@ fn while_with_continue_expr() { |
| 1269 | 1269 | }} |
| 1270 | 1270 | assert(sum == 40); |
| 1271 | 1271 | } |
| 1272 | ||
| 1273 | ||
| 1274 | #attribute("test") | |
| 1275 | fn for_loop_with_pointer_elem_var() { | |
| 1276 | const source = "abcdefg"; | |
| 1277 | var target: [source.len]u8 = undefined; | |
| 1278 | @memcpy(&target[0], &source[0], source.len); | |
| 1279 | mangle_string(target); | |
| 1280 | assert(str.eql(target, "bcdefgh")); | |
| 1281 | } | |
| 1282 | #static_eval_enable(false) | |
| 1283 | fn mangle_string(s: []u8) { | |
| 1284 | for (s) |*c| { | |
| 1285 | *c += 1; | |
| 1286 | } | |
| 1287 | } |