support assigning to arrays
parent
6e0c3dc173
commit
e8550814c5
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue