Commit 6acc354957

Andrew Kelley <superjoe30@gmail.com>
2016-04-20 20:58:01
for loop: add ability to get pointer to elem var
see #51
1 parent a25307c
doc/langref.md
@@ -81,7 +81,7 @@ SwitchItem = Expression | (Expression "..." Expression)
 
 WhileExpression = "while" "(" Expression option(";" Expression) ")" Expression
 
-ForExpression = "for" "(" Expression ")" option("|" "Symbol" option("," "Symbol") "|") Expression
+ForExpression = "for" "(" Expression ")" option("|" option("*") "Symbol" option("," "Symbol") "|") Expression
 
 BoolOrExpression = BoolAndExpression "||" BoolOrExpression | BoolAndExpression
 
src/all_types.hpp
@@ -508,6 +508,7 @@ struct AstNodeForExpr {
     Expr resolved_expr;
     VariableTableEntry *elem_var;
     VariableTableEntry *index_var;
+    bool elem_is_ptr;
 };
 
 struct AstNodeSwitchExpr {
src/analyze.cpp
@@ -3567,6 +3567,13 @@ static TypeTableEntry *analyze_for_expr(CodeGen *g, ImportTableEntry *import, Bl
         child_type = g->builtin_types.entry_invalid;
     }
 
+    TypeTableEntry *var_type;
+    if (node->data.for_expr.elem_is_ptr) {
+        var_type = get_pointer_to_type(g, child_type, false);
+    } else {
+        var_type = child_type;
+    }
+
     BlockContext *child_context = new_block_context(node, context);
     child_context->parent_loop_node = node;
 
@@ -3574,7 +3581,7 @@ static TypeTableEntry *analyze_for_expr(CodeGen *g, ImportTableEntry *import, Bl
     elem_var_node->block_context = child_context;
     Buf *elem_var_name = &elem_var_node->data.symbol_expr.symbol;
     node->data.for_expr.elem_var = add_local_var(g, elem_var_node, import, child_context, elem_var_name,
-            child_type, true, nullptr);
+            var_type, true, nullptr);
 
     AstNode *index_var_node = node->data.for_expr.index_node;
     if (index_var_node) {
src/codegen.cpp
@@ -2427,9 +2427,14 @@ static LLVMValueRef gen_for_expr(CodeGen *g, AstNode *node) {
 
     LLVMPositionBuilderAtEnd(g->builder, body_block);
     LLVMValueRef elem_ptr = gen_array_elem_ptr(g, node, array_val, array_type, index_val);
-    LLVMValueRef elem_val = handle_is_ptr(child_type) ? elem_ptr : LLVMBuildLoad(g->builder, elem_ptr, "");
-    gen_assign_raw(g, node, BinOpTypeAssign, elem_var->value_ref, elem_val,
-            elem_var->type, child_type);
+
+    LLVMValueRef elem_val;
+    if (node->data.for_expr.elem_is_ptr) {
+        elem_val = elem_ptr;
+    } else {
+        elem_val = handle_is_ptr(child_type) ? elem_ptr : LLVMBuildLoad(g->builder, elem_ptr, "");
+    }
+    gen_assign_raw(g, node, BinOpTypeAssign, elem_var->value_ref, elem_val, elem_var->type, child_type);
     gen_var_debug_decl(g, elem_var);
     g->break_block_stack.append(end_block);
     g->continue_block_stack.append(continue_block);
src/eval.cpp
@@ -812,6 +812,10 @@ static bool eval_for_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) {
     assert(elem_node->type == NodeTypeSymbol);
     Buf *elem_var_name = &elem_node->data.symbol_expr.symbol;
 
+    if (node->data.for_expr.elem_is_ptr) {
+        zig_panic("TODO");
+    }
+
     Buf *index_var_name = nullptr;
     if (index_node) {
         assert(index_node->type == NodeTypeSymbol);
src/parser.cpp
@@ -1932,7 +1932,7 @@ static AstNode *ast_parse_symbol(ParseContext *pc, int *token_index) {
 }
 
 /*
-ForExpression = "for" "(" Expression ")" option("|" "Symbol" option("," "Symbol") "|") Expression
+ForExpression = "for" "(" Expression ")" option("|" option("*") "Symbol" option("," "Symbol") "|") Expression
 */
 static AstNode *ast_parse_for_expr(ParseContext *pc, int *token_index, bool mandatory) {
     Token *token = &pc->tokens->at(*token_index);
@@ -1955,6 +1955,13 @@ static AstNode *ast_parse_for_expr(ParseContext *pc, int *token_index, bool mand
     Token *maybe_bar = &pc->tokens->at(*token_index);
     if (maybe_bar->id == TokenIdBinOr) {
         *token_index += 1;
+
+        Token *maybe_star = &pc->tokens->at(*token_index);
+        if (maybe_star->id == TokenIdStar) {
+            *token_index += 1;
+            node->data.for_expr.elem_is_ptr = true;
+        }
+
         node->data.for_expr.elem_node = ast_parse_symbol(pc, token_index);
 
         Token *maybe_comma = &pc->tokens->at(*token_index);
test/self_hosted.zig
@@ -1269,3 +1269,19 @@ fn while_with_continue_expr() {
     }}
     assert(sum == 40);
 }
+
+
+#attribute("test")
+fn for_loop_with_pointer_elem_var() {
+    const source = "abcdefg";
+    var target: [source.len]u8 = undefined;
+    @memcpy(&target[0], &source[0], source.len);
+    mangle_string(target);
+    assert(str.eql(target, "bcdefgh"));
+}
+#static_eval_enable(false)
+fn mangle_string(s: []u8) {
+    for (s) |*c| {
+        *c += 1;
+    }
+}