authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-02 19:47:36-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-02 19:47:36-07:00
log187d00ca835d2c923cbc0a3ab9e861e82888d403
tree923b224c44e801b3d6bb9e8a2432d216c1f7e6d6
parent968b85ad77892da945d478799d4e775222248f1f

ability to access pointers with array indexing syntax

closes #40

5 files changed, 113 insertions(+), 105 deletions(-)

example/arrays/arrays.zig+13-24
...@@ -2,37 +2,26 @@ export executable "arrays";...@@ -2,37 +2,26 @@ export executable "arrays";
22
3use "std.zig";3use "std.zig";
44
5export fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {5pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
6 var array : [i32; 5];6 var array : [u32; 5];
77
8 var i : i32 = 0;8 var i : u32 = 0;
9loop_start:9 while (i < 5) {
10 if i == 5 {10 array[i] = i + 1;
11 goto loop_end;11 i = array[i];
12 }12 }
13 array[i] = i + 1;
14 i = array[i];
15 goto loop_start;
16
17loop_end:
1813
19 i = 0;14 i = 0;
20 var accumulator : i32 = 0;15 var accumulator : u32 = 0;
21loop_2_start:16 while (i < 5) {
22 if i == 5 {17 accumulator += array[i];
23 goto loop_2_end;
24 }
25
26 accumulator += array[i];
2718
28 i = i + 1;19 i += 1;
29 goto loop_2_start;
30loop_2_end:
31
32 if accumulator == 15 {
33 print_str("OK\n" as string);
34 }20 }
3521
22 if (accumulator == 15) {
23 print_str("OK\n");
24 }
3625
37 return 0;26 return 0;
38}27}
src/analyze.cpp+4-9
...@@ -1057,6 +1057,8 @@ static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *i...@@ -1057,6 +1057,8 @@ static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *i
10571057
1058 if (array_type->id == TypeTableEntryIdArray) {1058 if (array_type->id == TypeTableEntryIdArray) {
1059 return_type = array_type->data.array.child_type;1059 return_type = array_type->data.array.child_type;
1060 } else if (array_type->id == TypeTableEntryIdPointer) {
1061 return_type = array_type->data.pointer.child_type;
1060 } else {1062 } else {
1061 if (array_type->id != TypeTableEntryIdInvalid) {1063 if (array_type->id != TypeTableEntryIdInvalid) {
1062 add_node_error(g, node, buf_sprintf("array access of non-array"));1064 add_node_error(g, node, buf_sprintf("array access of non-array"));
...@@ -1064,14 +1066,7 @@ static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *i...@@ -1064,14 +1066,7 @@ static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *i
1064 return_type = g->builtin_types.entry_invalid;1066 return_type = g->builtin_types.entry_invalid;
1065 }1067 }
10661068
1067 TypeTableEntry *subscript_type = analyze_expression(g, import, context, nullptr,1069 analyze_expression(g, import, context, g->builtin_types.entry_usize, node->data.array_access_expr.subscript);
1068 node->data.array_access_expr.subscript);
1069 if (subscript_type->id != TypeTableEntryIdInt &&
1070 subscript_type->id != TypeTableEntryIdInvalid)
1071 {
1072 add_node_error(g, node,
1073 buf_sprintf("array subscripts must be integers"));
1074 }
10751070
1076 return return_type;1071 return return_type;
1077}1072}
...@@ -1150,7 +1145,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B...@@ -1150,7 +1145,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
1150 cast_node->after_type = wanted_type;1145 cast_node->after_type = wanted_type;
11511146
1152 // special casing this for now, TODO think about casting and do a general solution1147 // special casing this for now, TODO think about casting and do a general solution
1153 if (wanted_type == g->builtin_types.entry_isize &&1148 if ((wanted_type == g->builtin_types.entry_isize || wanted_type == g->builtin_types.entry_usize) &&
1154 actual_type->id == TypeTableEntryIdPointer)1149 actual_type->id == TypeTableEntryIdPointer)
1155 {1150 {
1156 cast_node->op = CastOpPtrToInt;1151 cast_node->op = CastOpPtrToInt;
src/codegen.cpp+65-24
...@@ -199,19 +199,48 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {...@@ -199,19 +199,48 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
199static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {199static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {
200 assert(node->type == NodeTypeArrayAccessExpr);200 assert(node->type == NodeTypeArrayAccessExpr);
201201
202 // TODO gen_lvalue202 TypeTableEntry *type_entry = get_expr_type(node->data.array_access_expr.array_ref_expr);
203 LLVMValueRef array_ref_value = gen_expr(g, node->data.array_access_expr.array_ref_expr);203 AstNode *array_expr_node = node->data.array_access_expr.array_ref_expr;
204
205 LLVMValueRef array_ptr = gen_expr(g, array_expr_node);
206 /*
207 if (array_expr_node->type == NodeTypeSymbol) {
208 VariableTableEntry *var = find_variable(array_expr_node->codegen_node->expr_node.block_context,
209 &array_expr_node->data.symbol);
210 assert(var);
211
212 array_ptr = var->value_ref;
213 } else if (array_expr_node->type == NodeTypeFieldAccessExpr) {
214 zig_panic("TODO gen array ptr field access expr");
215 } else if (array_expr_node->type == NodeTypeArrayAccessExpr) {
216 zig_panic("TODO gen array ptr array access expr");
217 } else {
218 array_ptr = gen_expr(g, array_expr_node);
219 }
220 */
221
204 LLVMValueRef subscript_value = gen_expr(g, node->data.array_access_expr.subscript);222 LLVMValueRef subscript_value = gen_expr(g, node->data.array_access_expr.subscript);
205223
206 assert(array_ref_value);224 assert(array_ptr);
207 assert(subscript_value);225 assert(subscript_value);
208226
209 LLVMValueRef indices[] = {227 if (type_entry->id == TypeTableEntryIdArray) {
210 LLVMConstInt(LLVMInt32Type(), 0, false),228 LLVMValueRef indices[] = {
211 subscript_value229 LLVMConstNull(g->builtin_types.entry_usize->type_ref),
212 };230 subscript_value
213 add_debug_source_node(g, node);231 };
214 return LLVMBuildInBoundsGEP(g->builder, array_ref_value, indices, 2, "");232 add_debug_source_node(g, node);
233 return LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, "");
234 } else if (type_entry->id == TypeTableEntryIdPointer) {
235 assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);
236 LLVMValueRef indices[] = {
237 subscript_value
238 };
239 add_debug_source_node(g, node);
240 return LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 1, "");
241 } else {
242 zig_unreachable();
243 }
215}244}
216245
217static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **out_type_entry) {246static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **out_type_entry) {
...@@ -279,6 +308,14 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lva...@@ -279,6 +308,14 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lva
279 if (buf_eql_str(name, "len")) {308 if (buf_eql_str(name, "len")) {
280 return LLVMConstInt(g->builtin_types.entry_usize->type_ref,309 return LLVMConstInt(g->builtin_types.entry_usize->type_ref,
281 struct_type->data.array.len, false);310 struct_type->data.array.len, false);
311 } else if (buf_eql_str(name, "ptr")) {
312 LLVMValueRef array_val = gen_expr(g, node->data.field_access_expr.struct_expr);
313 LLVMValueRef indices[] = {
314 LLVMConstNull(g->builtin_types.entry_usize->type_ref),
315 LLVMConstNull(g->builtin_types.entry_usize->type_ref),
316 };
317 add_debug_source_node(g, node);
318 return LLVMBuildInBoundsGEP(g->builder, array_val, indices, 2, "");
282 } else {319 } else {
283 zig_panic("gen_field_access_expr bad array field");320 zig_panic("gen_field_access_expr bad array field");
284 }321 }
...@@ -314,9 +351,15 @@ static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node,...@@ -314,9 +351,15 @@ static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node,
314 target_ref = var->value_ref;351 target_ref = var->value_ref;
315 } else if (node->type == NodeTypeArrayAccessExpr) {352 } else if (node->type == NodeTypeArrayAccessExpr) {
316 TypeTableEntry *array_type = get_expr_type(node->data.array_access_expr.array_ref_expr);353 TypeTableEntry *array_type = get_expr_type(node->data.array_access_expr.array_ref_expr);
317 assert(array_type->id == TypeTableEntryIdArray);354 if (array_type->id == TypeTableEntryIdArray) {
318 *out_type_entry = array_type->data.array.child_type;355 *out_type_entry = array_type->data.array.child_type;
319 target_ref = gen_array_ptr(g, node);356 target_ref = gen_array_ptr(g, node);
357 } else if (array_type->id == TypeTableEntryIdPointer) {
358 *out_type_entry = array_type->data.pointer.child_type;
359 target_ref = gen_array_ptr(g, node);
360 } else {
361 zig_unreachable();
362 }
320 } else if (node->type == NodeTypeFieldAccessExpr) {363 } else if (node->type == NodeTypeFieldAccessExpr) {
321 target_ref = gen_field_ptr(g, node, out_type_entry);364 target_ref = gen_field_ptr(g, node, out_type_entry);
322 } else {365 } else {
...@@ -389,28 +432,26 @@ static LLVMValueRef gen_bare_cast(CodeGen *g, AstNode *node, LLVMValueRef expr_v...@@ -389,28 +432,26 @@ static LLVMValueRef gen_bare_cast(CodeGen *g, AstNode *node, LLVMValueRef expr_v
389 return cast_node->ptr;432 return cast_node->ptr;
390 }433 }
391 case CastOpPtrToInt:434 case CastOpPtrToInt:
435 add_debug_source_node(g, node);
392 return LLVMBuildPtrToInt(g->builder, expr_val, wanted_type->type_ref, "");436 return LLVMBuildPtrToInt(g->builder, expr_val, wanted_type->type_ref, "");
393 case CastOpPointerReinterpret:437 case CastOpPointerReinterpret:
438 add_debug_source_node(g, node);
394 return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");439 return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");
395 case CastOpIntWidenOrShorten:440 case CastOpIntWidenOrShorten:
396 if (actual_type->size_in_bits == wanted_type->size_in_bits) {441 if (actual_type->size_in_bits == wanted_type->size_in_bits) {
397 return expr_val;442 return expr_val;
398 } else if (actual_type->size_in_bits < wanted_type->size_in_bits) {443 } else if (actual_type->size_in_bits < wanted_type->size_in_bits) {
399 if (actual_type->data.integral.is_signed && wanted_type->data.integral.is_signed) {444 if (actual_type->data.integral.is_signed) {
445 add_debug_source_node(g, node);
400 return LLVMBuildSExt(g->builder, expr_val, wanted_type->type_ref, "");446 return LLVMBuildSExt(g->builder, expr_val, wanted_type->type_ref, "");
401 } else if (!actual_type->data.integral.is_signed && !wanted_type->data.integral.is_signed) {
402 return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, "");
403 } else {447 } else {
404 zig_panic("TODO gen_cast_expr mixing of signness");448 add_debug_source_node(g, node);
449 return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, "");
405 }450 }
406 } else {451 } else {
407 assert(actual_type->size_in_bits > wanted_type->size_in_bits);452 assert(actual_type->size_in_bits > wanted_type->size_in_bits);
408453 add_debug_source_node(g, node);
409 if (actual_type->data.integral.is_signed && wanted_type->data.integral.is_signed) {454 return LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, "");
410 return LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, "");
411 } else {
412 zig_panic("TODO gen_cast_expr shorten unsigned");
413 }
414 }455 }
415 case CastOpArrayToString:456 case CastOpArrayToString:
416 {457 {
...@@ -1232,8 +1273,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {...@@ -1232,8 +1273,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
1232 Buf *str = &node->data.string_literal.buf;1273 Buf *str = &node->data.string_literal.buf;
1233 LLVMValueRef str_val = find_or_create_string(g, str, node->data.string_literal.c);1274 LLVMValueRef str_val = find_or_create_string(g, str, node->data.string_literal.c);
1234 LLVMValueRef indices[] = {1275 LLVMValueRef indices[] = {
1235 LLVMConstInt(LLVMInt32Type(), 0, false),1276 LLVMConstNull(g->builtin_types.entry_usize->type_ref),
1236 LLVMConstInt(LLVMInt32Type(), 0, false)1277 LLVMConstNull(g->builtin_types.entry_usize->type_ref),
1237 };1278 };
1238 LLVMValueRef ptr_val = LLVMBuildInBoundsGEP(g->builder, str_val, indices, 2, "");1279 LLVMValueRef ptr_val = LLVMBuildInBoundsGEP(g->builder, str_val, indices, 2, "");
1239 return ptr_val;1280 return ptr_val;
std/std.zig+19-26
...@@ -1,40 +1,37 @@...@@ -1,40 +1,37 @@
1const SYS_write : isize = 1;1const SYS_write : usize = 1;
2const SYS_exit : isize = 60;2const SYS_exit : usize = 60;
3const SYS_getrandom : isize = 278;3const SYS_getrandom : usize = 278;
44
5const stdout_fileno : isize = 1;5const stdout_fileno : isize = 1;
6const stderr_fileno : isize = 2;6const stderr_fileno : isize = 2;
77
8fn syscall1(number: isize, arg1: isize) -> isize {8fn syscall1(number: usize, arg1: usize) -> usize {
9 asm volatile ("syscall"9 asm volatile ("syscall"
10 : [ret] "={rax}" (-> isize)10 : [ret] "={rax}" (-> usize)
11 : [number] "{rax}" (number), [arg1] "{rdi}" (arg1)11 : [number] "{rax}" (number), [arg1] "{rdi}" (arg1)
12 : "rcx", "r11")12 : "rcx", "r11")
13}13}
1414
15fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {15fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) -> usize {
16 asm volatile ("syscall"16 asm volatile ("syscall"
17 : [ret] "={rax}" (-> isize)17 : [ret] "={rax}" (-> usize)
18 : [number] "{rax}" (number), [arg1] "{rdi}" (arg1), [arg2] "{rsi}" (arg2), [arg3] "{rdx}" (arg3)18 : [number] "{rax}" (number), [arg1] "{rdi}" (arg1), [arg2] "{rsi}" (arg2), [arg3] "{rdx}" (arg3)
19 : "rcx", "r11")19 : "rcx", "r11")
20}20}
2121
22/*
23pub fn getrandom(buf: &u8, count: usize, flags: u32) -> isize {22pub fn getrandom(buf: &u8, count: usize, flags: u32) -> isize {
24 return syscall3(SYS_getrandom, buf as isize, count as isize, flags as isize);23 return syscall3(SYS_getrandom, buf as usize, count, flags as usize) as isize;
25}24}
26*/
2725
28pub fn write(fd: isize, buf: &const u8, count: usize) -> isize {26pub fn write(fd: isize, buf: &const u8, count: usize) -> isize {
29 return syscall3(SYS_write, fd, buf as isize, count as isize);27 return syscall3(SYS_write, fd as usize, buf as usize, count) as isize;
30}28}
3129
32pub fn exit(status: i32) -> unreachable {30pub fn exit(status: i32) -> unreachable {
33 syscall1(SYS_exit, status as isize);31 syscall1(SYS_exit, status as usize);
34 unreachable;32 unreachable;
35}33}
3634
37/*
38fn digit_to_char(digit: u64) -> u8 { '0' + (digit as u8) }35fn digit_to_char(digit: u64) -> u8 { '0' + (digit as u8) }
3936
40const max_u64_base10_digits: usize = 20;37const max_u64_base10_digits: usize = 20;
...@@ -66,17 +63,6 @@ fn buf_print_u64(out_buf: &u8, x: u64) -> usize {...@@ -66,17 +63,6 @@ fn buf_print_u64(out_buf: &u8, x: u64) -> usize {
66 return len;63 return len;
67}64}
6865
69// TODO handle buffering and flushing (mutex protected)
70// TODO error handling
71pub fn print_u64(x: u64) -> isize {
72 // TODO use max_u64_base10_digits instead of hardcoding 20
73 var buf: [u8; 20];
74 const len = buf_print_u64(buf.ptr, x);
75 return write(stdout_fileno, buf.ptr, len);
76}
77*/
78
79
80// TODO error handling66// TODO error handling
81// TODO handle buffering and flushing (mutex protected)67// TODO handle buffering and flushing (mutex protected)
82pub fn print_str(str: string) -> isize { fprint_str(stdout_fileno, str) }68pub fn print_str(str: string) -> isize { fprint_str(stdout_fileno, str) }
...@@ -87,9 +73,16 @@ pub fn fprint_str(fd: isize, str: string) -> isize {...@@ -87,9 +73,16 @@ pub fn fprint_str(fd: isize, str: string) -> isize {
87 return write(fd, str.ptr, str.len);73 return write(fd, str.ptr, str.len);
88}74}
8975
90/*76// TODO handle buffering and flushing (mutex protected)
77// TODO error handling
78pub fn print_u64(x: u64) -> isize {
79 // TODO use max_u64_base10_digits instead of hardcoding 20
80 var buf: [u8; 20];
81 const len = buf_print_u64(buf.ptr, x);
82 return write(stdout_fileno, buf.ptr, len);
83}
84
91// TODO error handling85// TODO error handling
92pub fn os_get_random_bytes(buf: &u8, count: usize) -> isize {86pub fn os_get_random_bytes(buf: &u8, count: usize) -> isize {
93 return getrandom(buf, count, 0);87 return getrandom(buf, count, 0);
94}88}
95*/
test/run_tests.cpp+12-22
...@@ -319,31 +319,21 @@ done:...@@ -319,31 +319,21 @@ done:
319use "std.zig";319use "std.zig";
320320
321pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {321pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
322 var array : [i32; 5];322 var array : [u32; 5];
323323
324 var i : i32 = 0;324 var i : u32 = 0;
325loop_start:325 while (i < 5) {
326 if (i == 5) {326 array[i] = i + 1;
327 goto loop_end;327 i = array[i];
328 }328 }
329 array[i] = i + 1;
330 i = array[i];
331 goto loop_start;
332
333loop_end:
334329
335 i = 0;330 i = 0;
336 var accumulator = 0 as i32;331 var accumulator = 0 as u32;
337loop_2_start:332 while (i < 5) {
338 if (i == 5) {333 accumulator += array[i];
339 goto loop_2_end;
340 }
341334
342 accumulator = accumulator + array[i];335 i += 1;
343336 }
344 i = i + 1;
345 goto loop_2_start;
346loop_2_end:
347337
348 if (accumulator == 15) {338 if (accumulator == 15) {
349 print_str("OK\n");339 print_str("OK\n");
...@@ -871,9 +861,9 @@ fn f() {...@@ -871,9 +861,9 @@ fn f() {
871 ".tmp_source.zig:4:12: error: use of undeclared identifier 'i'",861 ".tmp_source.zig:4:12: error: use of undeclared identifier 'i'",
872 ".tmp_source.zig:4:14: error: use of undeclared identifier 'i'",862 ".tmp_source.zig:4:14: error: use of undeclared identifier 'i'",
873 ".tmp_source.zig:5:8: error: array access of non-array",863 ".tmp_source.zig:5:8: error: array access of non-array",
874 ".tmp_source.zig:5:8: error: array subscripts must be integers",864 ".tmp_source.zig:5:9: error: expected type 'usize', got 'bool'",
875 ".tmp_source.zig:5:19: error: array access of non-array",865 ".tmp_source.zig:5:19: error: array access of non-array",
876 ".tmp_source.zig:5:19: error: array subscripts must be integers");866 ".tmp_source.zig:5:20: error: expected type 'usize', got 'bool'");
877867
878 add_compile_fail_case("variadic functions only allowed in extern", R"SOURCE(868 add_compile_fail_case("variadic functions only allowed in extern", R"SOURCE(
879fn f(...) {}869fn f(...) {}