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 {...@@ -9,9 +9,7 @@ extern {
9export fn _start() -> unreachable {9export fn _start() -> unreachable {
10 let mut array : [i32; 10];10 let mut array : [i32; 10];
1111
12 exit(array[1]);12 array[4] = array[1] + 5;
13
14 //array[4] = array[1] + 5;
15
1613
14 exit(0);
17}15}
src/analyze.cpp+40-22
...@@ -10,6 +10,9 @@...@@ -10,6 +10,9 @@
10#include "zig_llvm.hpp"10#include "zig_llvm.hpp"
11#include "os.hpp"11#include "os.hpp"
1212
13static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
14 TypeTableEntry *expected_type, AstNode *node);
15
13static AstNode *first_executing_node(AstNode *node) {16static AstNode *first_executing_node(AstNode *node) {
14 switch (node->type) {17 switch (node->type) {
15 case NodeTypeFnCallExpr:18 case NodeTypeFnCallExpr:
...@@ -476,6 +479,35 @@ LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name) {...@@ -476,6 +479,35 @@ LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name) {
476 }479 }
477}480}
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
479static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,511static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
480 TypeTableEntry *expected_type, AstNode *node)512 TypeTableEntry *expected_type, AstNode *node)
481{513{
...@@ -593,6 +625,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -593,6 +625,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
593 case BinOpTypeAssign:625 case BinOpTypeAssign:
594 {626 {
595 AstNode *lhs_node = node->data.bin_op_expr.op1;627 AstNode *lhs_node = node->data.bin_op_expr.op1;
628 TypeTableEntry *expected_rhs_type = nullptr;
596 if (lhs_node->type == NodeTypeSymbol) {629 if (lhs_node->type == NodeTypeSymbol) {
597 Buf *name = &lhs_node->data.symbol;630 Buf *name = &lhs_node->data.symbol;
598 LocalVariableTableEntry *var = find_local_variable(context, name);631 LocalVariableTableEntry *var = find_local_variable(context, name);
...@@ -601,18 +634,19 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -601,18 +634,19 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
601 add_node_error(g, lhs_node,634 add_node_error(g, lhs_node,
602 buf_sprintf("cannot assign to constant variable"));635 buf_sprintf("cannot assign to constant variable"));
603 } else {636 } else {
604 analyze_expression(g, import, context, var->type,637 expected_rhs_type = var->type;
605 node->data.bin_op_expr.op2);
606 }638 }
607 } else {639 } else {
608 add_node_error(g, lhs_node,640 add_node_error(g, lhs_node,
609 buf_sprintf("use of undeclared identifier '%s'", buf_ptr(name)));641 buf_sprintf("use of undeclared identifier '%s'", buf_ptr(name)));
610 }642 }
611643 } else if (lhs_node->type == NodeTypeArrayAccessExpr) {
644 expected_rhs_type = analyze_array_access_expr(g, import, context, lhs_node);
612 } else {645 } else {
613 add_node_error(g, lhs_node,646 add_node_error(g, lhs_node,
614 buf_sprintf("expected a bare identifier"));647 buf_sprintf("expected a bare identifier"));
615 }648 }
649 analyze_expression(g, import, context, expected_rhs_type, node->data.bin_op_expr.op2);
616 return_type = g->builtin_types.entry_void;650 return_type = g->builtin_types.entry_void;
617 break;651 break;
618 }652 }
...@@ -736,25 +770,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -736,25 +770,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
736 }770 }
737771
738 case NodeTypeArrayAccessExpr:772 case NodeTypeArrayAccessExpr:
739 {773 // for reading array access; assignment handled elsewhere
740 // here we are always reading the array774 return_type = analyze_array_access_expr(g, import, context, node);
741 TypeTableEntry *array_type = analyze_expression(g, import, context, nullptr,775 break;
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 }
758 case NodeTypeNumberLiteral:776 case NodeTypeNumberLiteral:
759 // TODO: generic literal int type777 // TODO: generic literal int type
760 return_type = g->builtin_types.entry_i32;778 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) {...@@ -167,7 +167,7 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
167 }167 }
168}168}
169169
170static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node) {170static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {
171 assert(node->type == NodeTypeArrayAccessExpr);171 assert(node->type == NodeTypeArrayAccessExpr);
172172
173 LLVMValueRef array_ref_value = gen_expr(g, node->data.array_access_expr.array_ref_expr);173 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) {...@@ -180,8 +180,14 @@ static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node) {
180 LLVMConstInt(LLVMInt32Type(), 0, false),180 LLVMConstInt(LLVMInt32Type(), 0, false),
181 subscript_value181 subscript_value
182 };182 };
183 LLVMValueRef result_ptr = LLVMBuildInBoundsGEP(g->builder, array_ref_value, indices, 2, "");183 return LLVMBuildInBoundsGEP(g->builder, array_ref_value, indices, 2, "");
184 return LLVMBuildLoad(g->builder, result_ptr, "");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, "");
185}191}
186192
187static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {193static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
...@@ -437,22 +443,32 @@ static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) {...@@ -437,22 +443,32 @@ static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) {
437 return phi;443 return phi;
438}444}
439445
446
440static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {447static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
441 assert(node->type == NodeTypeBinOpExpr);448 assert(node->type == NodeTypeBinOpExpr);
442449
443 AstNode *symbol_node = node->data.bin_op_expr.op1;450 AstNode *lhs_node = node->data.bin_op_expr.op1;
444 assert(symbol_node->type == NodeTypeSymbol);
445451
446 LocalVariableTableEntry *var = find_local_variable(node->codegen_node->expr_node.block_context,452 if (lhs_node->type == NodeTypeSymbol) {
447 &symbol_node->data.symbol);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 constant456 // semantic checking ensures no variables are constant
450 assert(!var->is_const);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);
456}472}
457473
458static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) {474static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) {
test/run_tests.cpp+15
...@@ -520,6 +520,21 @@ fn f() {...@@ -520,6 +520,21 @@ fn f() {
520 (let a = 0);520 (let a = 0);
521}521}
522 )SOURCE", 1, ".tmp_source.zig:3:6: error: invalid token: 'let'");522 )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");
523}538}
524539
525static void print_compiler_invocation(TestCase *test_case, Buf *zig_stderr) {540static void print_compiler_invocation(TestCase *test_case, Buf *zig_stderr) {