support assigning to arrays

This commit is contained in:
Andrew Kelley 2015-12-08 15:31:43 -07:00
parent 6e0c3dc173
commit e8550814c5
4 changed files with 85 additions and 38 deletions

View File

@ -9,9 +9,7 @@ extern {
export fn _start() -> unreachable {
let mut array : [i32; 10];
exit(array[1]);
//array[4] = array[1] + 5;
array[4] = array[1] + 5;
exit(0);
}

View File

@ -10,6 +10,9 @@
#include "zig_llvm.hpp"
#include "os.hpp"
static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node);
static AstNode *first_executing_node(AstNode *node) {
switch (node->type) {
case NodeTypeFnCallExpr:
@ -476,6 +479,35 @@ LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name) {
}
}
static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
AstNode *node)
{
TypeTableEntry *array_type = analyze_expression(g, import, context, nullptr,
node->data.array_access_expr.array_ref_expr);
TypeTableEntry *return_type;
if (array_type->id == TypeTableEntryIdArray) {
return_type = array_type->data.array.child_type;
} else {
if (array_type->id != TypeTableEntryIdInvalid) {
add_node_error(g, node, buf_sprintf("array access of non-array"));
}
return_type = g->builtin_types.entry_invalid;
}
TypeTableEntry *subscript_type = analyze_expression(g, import, context, nullptr,
node->data.array_access_expr.subscript);
if (subscript_type->id != TypeTableEntryIdInt &&
subscript_type->id != TypeTableEntryIdInvalid)
{
add_node_error(g, node,
buf_sprintf("array subscripts must be integers"));
}
return return_type;
}
static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node)
{
@ -593,6 +625,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
case BinOpTypeAssign:
{
AstNode *lhs_node = node->data.bin_op_expr.op1;
TypeTableEntry *expected_rhs_type = nullptr;
if (lhs_node->type == NodeTypeSymbol) {
Buf *name = &lhs_node->data.symbol;
LocalVariableTableEntry *var = find_local_variable(context, name);
@ -601,18 +634,19 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
add_node_error(g, lhs_node,
buf_sprintf("cannot assign to constant variable"));
} else {
analyze_expression(g, import, context, var->type,
node->data.bin_op_expr.op2);
expected_rhs_type = var->type;
}
} else {
add_node_error(g, lhs_node,
buf_sprintf("use of undeclared identifier '%s'", buf_ptr(name)));
}
} else if (lhs_node->type == NodeTypeArrayAccessExpr) {
expected_rhs_type = analyze_array_access_expr(g, import, context, lhs_node);
} else {
add_node_error(g, lhs_node,
buf_sprintf("expected a bare identifier"));
}
analyze_expression(g, import, context, expected_rhs_type, node->data.bin_op_expr.op2);
return_type = g->builtin_types.entry_void;
break;
}
@ -736,25 +770,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
}
case NodeTypeArrayAccessExpr:
{
// here we are always reading the array
TypeTableEntry *array_type = analyze_expression(g, import, context, nullptr,
node->data.array_access_expr.array_ref_expr);
if (array_type->id == TypeTableEntryIdArray) {
TypeTableEntry *subscript_type = analyze_expression(g, import, context,
nullptr, node->data.array_access_expr.subscript);
if (subscript_type->id != TypeTableEntryIdInt) {
add_node_error(g, node,
buf_sprintf("array subscripts must be integers"));
}
return_type = array_type->data.array.child_type;
} else {
add_node_error(g, node, buf_sprintf("array access of non-array"));
return_type = g->builtin_types.entry_invalid;
}
break;
}
// for reading array access; assignment handled elsewhere
return_type = analyze_array_access_expr(g, import, context, node);
break;
case NodeTypeNumberLiteral:
// TODO: generic literal int type
return_type = g->builtin_types.entry_i32;

View File

@ -167,7 +167,7 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
}
}
static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node) {
static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeArrayAccessExpr);
LLVMValueRef array_ref_value = gen_expr(g, node->data.array_access_expr.array_ref_expr);
@ -180,8 +180,14 @@ static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node) {
LLVMConstInt(LLVMInt32Type(), 0, false),
subscript_value
};
LLVMValueRef result_ptr = LLVMBuildInBoundsGEP(g->builder, array_ref_value, indices, 2, "");
return LLVMBuildLoad(g->builder, result_ptr, "");
return LLVMBuildInBoundsGEP(g->builder, array_ref_value, indices, 2, "");
}
static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeArrayAccessExpr);
LLVMValueRef ptr = gen_array_ptr(g, node);
return LLVMBuildLoad(g->builder, ptr, "");
}
static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
@ -437,22 +443,32 @@ static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) {
return phi;
}
static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeBinOpExpr);
AstNode *symbol_node = node->data.bin_op_expr.op1;
assert(symbol_node->type == NodeTypeSymbol);
AstNode *lhs_node = node->data.bin_op_expr.op1;
LocalVariableTableEntry *var = find_local_variable(node->codegen_node->expr_node.block_context,
&symbol_node->data.symbol);
if (lhs_node->type == NodeTypeSymbol) {
LocalVariableTableEntry *var = find_local_variable(node->codegen_node->expr_node.block_context,
&lhs_node->data.symbol);
// semantic checking ensures no variables are constant
assert(!var->is_const);
// semantic checking ensures no variables are constant
assert(!var->is_const);
LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2);
LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2);
add_debug_source_node(g, node);
return LLVMBuildStore(g->builder, value, var->value_ref);
} else if (lhs_node->type == NodeTypeArrayAccessExpr) {
LLVMValueRef ptr = gen_array_ptr(g, lhs_node);
LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2);
add_debug_source_node(g, node);
return LLVMBuildStore(g->builder, value, ptr);
} else {
zig_panic("bad assign target");
}
add_debug_source_node(g, node);
return LLVMBuildStore(g->builder, value, var->value_ref);
}
static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) {

View File

@ -520,6 +520,21 @@ fn f() {
(let a = 0);
}
)SOURCE", 1, ".tmp_source.zig:3:6: error: invalid token: 'let'");
add_compile_fail_case("array access errors", R"SOURCE(
fn f() {
let mut bad : bool;
i[i] = i[i];
bad[bad] = bad[bad];
}
)SOURCE", 8, ".tmp_source.zig:4:5: error: use of undeclared identifier 'i'",
".tmp_source.zig:4:7: error: use of undeclared identifier 'i'",
".tmp_source.zig:4:12: error: use of undeclared identifier 'i'",
".tmp_source.zig:4:14: error: use of undeclared identifier 'i'",
".tmp_source.zig:5:8: error: array access of non-array",
".tmp_source.zig:5:8: error: array subscripts must be integers",
".tmp_source.zig:5:19: error: array access of non-array",
".tmp_source.zig:5:19: error: array subscripts must be integers");
}
static void print_compiler_invocation(TestCase *test_case, Buf *zig_stderr) {