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";
22
33use "std.zig";
44
5export fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
6 var array : [i32; 5];
5pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
6 var array : [u32; 5];
77
8 var i : i32 = 0;
9loop_start:
10 if i == 5 {
11 goto loop_end;
8 var i : u32 = 0;
9 while (i < 5) {
10 array[i] = i + 1;
11 i = array[i];
1212 }
13 array[i] = i + 1;
14 i = array[i];
15 goto loop_start;
16
17loop_end:
1813
1914 i = 0;
20 var accumulator : i32 = 0;
21loop_2_start:
22 if i == 5 {
23 goto loop_2_end;
24 }
25
26 accumulator += array[i];
15 var accumulator : u32 = 0;
16 while (i < 5) {
17 accumulator += array[i];
2718
28 i = i + 1;
29 goto loop_2_start;
30loop_2_end:
31
32 if accumulator == 15 {
33 print_str("OK\n" as string);
19 i += 1;
3420 }
3521
22 if (accumulator == 15) {
23 print_str("OK\n");
24 }
3625
3726 return 0;
3827}
src/analyze.cpp+4-9
......@@ -1057,6 +1057,8 @@ static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *i
10571057
10581058 if (array_type->id == TypeTableEntryIdArray) {
10591059 return_type = array_type->data.array.child_type;
1060 } else if (array_type->id == TypeTableEntryIdPointer) {
1061 return_type = array_type->data.pointer.child_type;
10601062 } else {
10611063 if (array_type->id != TypeTableEntryIdInvalid) {
10621064 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
10641066 return_type = g->builtin_types.entry_invalid;
10651067 }
10661068
1067 TypeTableEntry *subscript_type = analyze_expression(g, import, context, nullptr,
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 }
1069 analyze_expression(g, import, context, g->builtin_types.entry_usize, node->data.array_access_expr.subscript);
10751070
10761071 return return_type;
10771072}
......@@ -1150,7 +1145,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
11501145 cast_node->after_type = wanted_type;
11511146
11521147 // 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) &&
11541149 actual_type->id == TypeTableEntryIdPointer)
11551150 {
11561151 cast_node->op = CastOpPtrToInt;
src/codegen.cpp+65-24
......@@ -199,19 +199,48 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
199199static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {
200200 assert(node->type == NodeTypeArrayAccessExpr);
201201
202 // TODO gen_lvalue
203 LLVMValueRef array_ref_value = gen_expr(g, node->data.array_access_expr.array_ref_expr);
202 TypeTableEntry *type_entry = get_expr_type(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
204222 LLVMValueRef subscript_value = gen_expr(g, node->data.array_access_expr.subscript);
205223
206 assert(array_ref_value);
224 assert(array_ptr);
207225 assert(subscript_value);
208226
209 LLVMValueRef indices[] = {
210 LLVMConstInt(LLVMInt32Type(), 0, false),
211 subscript_value
212 };
213 add_debug_source_node(g, node);
214 return LLVMBuildInBoundsGEP(g->builder, array_ref_value, indices, 2, "");
227 if (type_entry->id == TypeTableEntryIdArray) {
228 LLVMValueRef indices[] = {
229 LLVMConstNull(g->builtin_types.entry_usize->type_ref),
230 subscript_value
231 };
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 }
215244}
216245
217246static 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
279308 if (buf_eql_str(name, "len")) {
280309 return LLVMConstInt(g->builtin_types.entry_usize->type_ref,
281310 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, "");
282319 } else {
283320 zig_panic("gen_field_access_expr bad array field");
284321 }
......@@ -314,9 +351,15 @@ static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node,
314351 target_ref = var->value_ref;
315352 } else if (node->type == NodeTypeArrayAccessExpr) {
316353 TypeTableEntry *array_type = get_expr_type(node->data.array_access_expr.array_ref_expr);
317 assert(array_type->id == TypeTableEntryIdArray);
318 *out_type_entry = array_type->data.array.child_type;
319 target_ref = gen_array_ptr(g, node);
354 if (array_type->id == TypeTableEntryIdArray) {
355 *out_type_entry = array_type->data.array.child_type;
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 }
320363 } else if (node->type == NodeTypeFieldAccessExpr) {
321364 target_ref = gen_field_ptr(g, node, out_type_entry);
322365 } else {
......@@ -389,28 +432,26 @@ static LLVMValueRef gen_bare_cast(CodeGen *g, AstNode *node, LLVMValueRef expr_v
389432 return cast_node->ptr;
390433 }
391434 case CastOpPtrToInt:
435 add_debug_source_node(g, node);
392436 return LLVMBuildPtrToInt(g->builder, expr_val, wanted_type->type_ref, "");
393437 case CastOpPointerReinterpret:
438 add_debug_source_node(g, node);
394439 return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");
395440 case CastOpIntWidenOrShorten:
396441 if (actual_type->size_in_bits == wanted_type->size_in_bits) {
397442 return expr_val;
398443 } 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);
400446 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, "");
403447 } 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, "");
405450 }
406451 } else {
407452 assert(actual_type->size_in_bits > wanted_type->size_in_bits);
408
409 if (actual_type->data.integral.is_signed && wanted_type->data.integral.is_signed) {
410 return LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, "");
411 } else {
412 zig_panic("TODO gen_cast_expr shorten unsigned");
413 }
453 add_debug_source_node(g, node);
454 return LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, "");
414455 }
415456 case CastOpArrayToString:
416457 {
......@@ -1232,8 +1273,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
12321273 Buf *str = &node->data.string_literal.buf;
12331274 LLVMValueRef str_val = find_or_create_string(g, str, node->data.string_literal.c);
12341275 LLVMValueRef indices[] = {
1235 LLVMConstInt(LLVMInt32Type(), 0, false),
1236 LLVMConstInt(LLVMInt32Type(), 0, false)
1276 LLVMConstNull(g->builtin_types.entry_usize->type_ref),
1277 LLVMConstNull(g->builtin_types.entry_usize->type_ref),
12371278 };
12381279 LLVMValueRef ptr_val = LLVMBuildInBoundsGEP(g->builder, str_val, indices, 2, "");
12391280 return ptr_val;
std/std.zig+19-26
......@@ -1,40 +1,37 @@
1const SYS_write : isize = 1;
2const SYS_exit : isize = 60;
3const SYS_getrandom : isize = 278;
1const SYS_write : usize = 1;
2const SYS_exit : usize = 60;
3const SYS_getrandom : usize = 278;
44
55const stdout_fileno : isize = 1;
66const stderr_fileno : isize = 2;
77
8fn syscall1(number: isize, arg1: isize) -> isize {
8fn syscall1(number: usize, arg1: usize) -> usize {
99 asm volatile ("syscall"
10 : [ret] "={rax}" (-> isize)
10 : [ret] "={rax}" (-> usize)
1111 : [number] "{rax}" (number), [arg1] "{rdi}" (arg1)
1212 : "rcx", "r11")
1313}
1414
15fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {
15fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) -> usize {
1616 asm volatile ("syscall"
17 : [ret] "={rax}" (-> isize)
17 : [ret] "={rax}" (-> usize)
1818 : [number] "{rax}" (number), [arg1] "{rdi}" (arg1), [arg2] "{rsi}" (arg2), [arg3] "{rdx}" (arg3)
1919 : "rcx", "r11")
2020}
2121
22/*
2322pub 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;
2524}
26*/
2725
2826pub 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;
3028}
3129
3230pub fn exit(status: i32) -> unreachable {
33 syscall1(SYS_exit, status as isize);
31 syscall1(SYS_exit, status as usize);
3432 unreachable;
3533}
3634
37/*
3835fn digit_to_char(digit: u64) -> u8 { '0' + (digit as u8) }
3936
4037const max_u64_base10_digits: usize = 20;
......@@ -66,17 +63,6 @@ fn buf_print_u64(out_buf: &u8, x: u64) -> usize {
6663 return len;
6764}
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
8066// TODO error handling
8167// TODO handle buffering and flushing (mutex protected)
8268pub fn print_str(str: string) -> isize { fprint_str(stdout_fileno, str) }
......@@ -87,9 +73,16 @@ pub fn fprint_str(fd: isize, str: string) -> isize {
8773 return write(fd, str.ptr, str.len);
8874}
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
9185// TODO error handling
9286pub fn os_get_random_bytes(buf: &u8, count: usize) -> isize {
9387 return getrandom(buf, count, 0);
9488}
95*/
test/run_tests.cpp+12-22
......@@ -319,31 +319,21 @@ done:
319319use "std.zig";
320320
321321pub 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;
325loop_start:
326 if (i == 5) {
327 goto loop_end;
324 var i : u32 = 0;
325 while (i < 5) {
326 array[i] = i + 1;
327 i = array[i];
328328 }
329 array[i] = i + 1;
330 i = array[i];
331 goto loop_start;
332
333loop_end:
334329
335330 i = 0;
336 var accumulator = 0 as i32;
337loop_2_start:
338 if (i == 5) {
339 goto loop_2_end;
340 }
331 var accumulator = 0 as u32;
332 while (i < 5) {
333 accumulator += array[i];
341334
342 accumulator = accumulator + array[i];
343
344 i = i + 1;
345 goto loop_2_start;
346loop_2_end:
335 i += 1;
336 }
347337
348338 if (accumulator == 15) {
349339 print_str("OK\n");
......@@ -871,9 +861,9 @@ fn f() {
871861 ".tmp_source.zig:4:12: error: use of undeclared identifier 'i'",
872862 ".tmp_source.zig:4:14: error: use of undeclared identifier 'i'",
873863 ".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'",
875865 ".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
878868 add_compile_fail_case("variadic functions only allowed in extern", R"SOURCE(
879869fn f(...) {}