authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-08 15:31:43-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-08 15:31:43-07:00
loge8550814c5e4387e8b758736a1254a5c3b32674e
treee1f669d947987121be234fdd6bb7ccc55e4d7b2f
parent6e0c3dc173507b92fc04515659454044f918efbb

support assigning to arrays


4 files changed, 85 insertions(+), 38 deletions(-)

example/arrays/arrays.zig+2-4
......@@ -9,9 +9,7 @@ extern {
99export fn _start() -> unreachable {
1010 let mut array : [i32; 10];
1111
12 exit(array[1]);
13
14 //array[4] = array[1] + 5;
15
12 array[4] = array[1] + 5;
1613
14 exit(0);
1715}
src/analyze.cpp+40-22
......@@ -10,6 +10,9 @@
1010#include "zig_llvm.hpp"
1111#include "os.hpp"
1212
13static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
14 TypeTableEntry *expected_type, AstNode *node);
15
1316static AstNode *first_executing_node(AstNode *node) {
1417 switch (node->type) {
1518 case NodeTypeFnCallExpr:
......@@ -476,6 +479,35 @@ LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name) {
476479 }
477480}
478481
482static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
483 AstNode *node)
484{
485 TypeTableEntry *array_type = analyze_expression(g, import, context, nullptr,
486 node->data.array_access_expr.array_ref_expr);
487
488 TypeTableEntry *return_type;
489
490 if (array_type->id == TypeTableEntryIdArray) {
491 return_type = array_type->data.array.child_type;
492 } else {
493 if (array_type->id != TypeTableEntryIdInvalid) {
494 add_node_error(g, node, buf_sprintf("array access of non-array"));
495 }
496 return_type = g->builtin_types.entry_invalid;
497 }
498
499 TypeTableEntry *subscript_type = analyze_expression(g, import, context, nullptr,
500 node->data.array_access_expr.subscript);
501 if (subscript_type->id != TypeTableEntryIdInt &&
502 subscript_type->id != TypeTableEntryIdInvalid)
503 {
504 add_node_error(g, node,
505 buf_sprintf("array subscripts must be integers"));
506 }
507
508 return return_type;
509}
510
479511static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
480512 TypeTableEntry *expected_type, AstNode *node)
481513{
......@@ -593,6 +625,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
593625 case BinOpTypeAssign:
594626 {
595627 AstNode *lhs_node = node->data.bin_op_expr.op1;
628 TypeTableEntry *expected_rhs_type = nullptr;
596629 if (lhs_node->type == NodeTypeSymbol) {
597630 Buf *name = &lhs_node->data.symbol;
598631 LocalVariableTableEntry *var = find_local_variable(context, name);
......@@ -601,18 +634,19 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
601634 add_node_error(g, lhs_node,
602635 buf_sprintf("cannot assign to constant variable"));
603636 } else {
604 analyze_expression(g, import, context, var->type,
605 node->data.bin_op_expr.op2);
637 expected_rhs_type = var->type;
606638 }
607639 } else {
608640 add_node_error(g, lhs_node,
609641 buf_sprintf("use of undeclared identifier '%s'", buf_ptr(name)));
610642 }
611
643 } else if (lhs_node->type == NodeTypeArrayAccessExpr) {
644 expected_rhs_type = analyze_array_access_expr(g, import, context, lhs_node);
612645 } else {
613646 add_node_error(g, lhs_node,
614647 buf_sprintf("expected a bare identifier"));
615648 }
649 analyze_expression(g, import, context, expected_rhs_type, node->data.bin_op_expr.op2);
616650 return_type = g->builtin_types.entry_void;
617651 break;
618652 }
......@@ -736,25 +770,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
736770 }
737771
738772 case NodeTypeArrayAccessExpr:
739 {
740 // here we are always reading the array
741 TypeTableEntry *array_type = analyze_expression(g, import, context, nullptr,
742 node->data.array_access_expr.array_ref_expr);
743 if (array_type->id == TypeTableEntryIdArray) {
744 TypeTableEntry *subscript_type = analyze_expression(g, import, context,
745 nullptr, node->data.array_access_expr.subscript);
746 if (subscript_type->id != TypeTableEntryIdInt) {
747 add_node_error(g, node,
748 buf_sprintf("array subscripts must be integers"));
749 }
750 return_type = array_type->data.array.child_type;
751 } else {
752 add_node_error(g, node, buf_sprintf("array access of non-array"));
753 return_type = g->builtin_types.entry_invalid;
754 }
755
756 break;
757 }
773 // for reading array access; assignment handled elsewhere
774 return_type = analyze_array_access_expr(g, import, context, node);
775 break;
758776 case NodeTypeNumberLiteral:
759777 // TODO: generic literal int type
760778 return_type = g->builtin_types.entry_i32;
src/codegen.cpp+28-12
......@@ -167,7 +167,7 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
167167 }
168168}
169169
170static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node) {
170static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {
171171 assert(node->type == NodeTypeArrayAccessExpr);
172172
173173 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) {
180180 LLVMConstInt(LLVMInt32Type(), 0, false),
181181 subscript_value
182182 };
183 LLVMValueRef result_ptr = LLVMBuildInBoundsGEP(g->builder, array_ref_value, indices, 2, "");
184 return LLVMBuildLoad(g->builder, result_ptr, "");
183 return LLVMBuildInBoundsGEP(g->builder, array_ref_value, indices, 2, "");
184}
185
186static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node) {
187 assert(node->type == NodeTypeArrayAccessExpr);
188
189 LLVMValueRef ptr = gen_array_ptr(g, node);
190 return LLVMBuildLoad(g->builder, ptr, "");
185191}
186192
187193static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
......@@ -437,22 +443,32 @@ static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) {
437443 return phi;
438444}
439445
446
440447static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
441448 assert(node->type == NodeTypeBinOpExpr);
442449
443 AstNode *symbol_node = node->data.bin_op_expr.op1;
444 assert(symbol_node->type == NodeTypeSymbol);
450 AstNode *lhs_node = node->data.bin_op_expr.op1;
445451
446 LocalVariableTableEntry *var = find_local_variable(node->codegen_node->expr_node.block_context,
447 &symbol_node->data.symbol);
452 if (lhs_node->type == NodeTypeSymbol) {
453 LocalVariableTableEntry *var = find_local_variable(node->codegen_node->expr_node.block_context,
454 &lhs_node->data.symbol);
448455
449 // semantic checking ensures no variables are constant
450 assert(!var->is_const);
456 // semantic checking ensures no variables are constant
457 assert(!var->is_const);
451458
452 LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2);
459 LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2);
460
461 add_debug_source_node(g, node);
462 return LLVMBuildStore(g->builder, value, var->value_ref);
463 } else if (lhs_node->type == NodeTypeArrayAccessExpr) {
464 LLVMValueRef ptr = gen_array_ptr(g, lhs_node);
465 LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2);
466 add_debug_source_node(g, node);
467 return LLVMBuildStore(g->builder, value, ptr);
468 } else {
469 zig_panic("bad assign target");
470 }
453471
454 add_debug_source_node(g, node);
455 return LLVMBuildStore(g->builder, value, var->value_ref);
456472}
457473
458474static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) {
test/run_tests.cpp+15
......@@ -520,6 +520,21 @@ fn f() {
520520 (let a = 0);
521521}
522522 )SOURCE", 1, ".tmp_source.zig:3:6: error: invalid token: 'let'");
523
524 add_compile_fail_case("array access errors", R"SOURCE(
525fn f() {
526 let mut bad : bool;
527 i[i] = i[i];
528 bad[bad] = bad[bad];
529}
530 )SOURCE", 8, ".tmp_source.zig:4:5: error: use of undeclared identifier 'i'",
531 ".tmp_source.zig:4:7: error: use of undeclared identifier 'i'",
532 ".tmp_source.zig:4:12: error: use of undeclared identifier 'i'",
533 ".tmp_source.zig:4:14: error: use of undeclared identifier 'i'",
534 ".tmp_source.zig:5:8: error: array access of non-array",
535 ".tmp_source.zig:5:8: error: array subscripts must be integers",
536 ".tmp_source.zig:5:19: error: array access of non-array",
537 ".tmp_source.zig:5:19: error: array subscripts must be integers");
523538}
524539
525540static void print_compiler_invocation(TestCase *test_case, Buf *zig_stderr) {