for loop: add ability to get pointer to elem var

see #51
This commit is contained in:
Andrew Kelley 2016-04-20 11:58:01 -07:00
parent a25307c0a1
commit 6acc354957
7 changed files with 46 additions and 6 deletions

View File

@ -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

View File

@ -508,6 +508,7 @@ struct AstNodeForExpr {
Expr resolved_expr;
VariableTableEntry *elem_var;
VariableTableEntry *index_var;
bool elem_is_ptr;
};
struct AstNodeSwitchExpr {

View File

@ -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) {

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;
}
}