authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-12 02:05:08-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-12 02:05:08-07:00
logac630d354d51488d895bc14e26a069ae954ac5c6
treeff99cc11334991a76d7ab0837112f00b8b1b0c3c
parenta10277bd949d47370e427d4457d93e907de9a6f7

std: print_str no longer requires length argument

add explicit casting support from array to string

8 files changed, 125 insertions(+), 52 deletions(-)

example/hello_world/hello.zig+5-8
...@@ -1,12 +1,9 @@...@@ -1,12 +1,9 @@
1export executable "hello";1export executable "hello";
22
3#link("c")3use "std.zig";
4extern {
5 fn printf(__format: *const u8, ...) -> i32;
6 fn exit(__status: i32) -> unreachable;
7}
84
9export fn _start() -> unreachable {5export fn main(argc: isize, argv: *mut *mut u8, env: *mut *mut u8) -> i32 {
10 printf("Hello, world!\n");6 // TODO implicit coercion from array to string
11 exit(0);7 print_str("Hello, world!\n" as string);
8 return 0;
12}9}
example/hello_world/hello2.zig deleted-8
...@@ -1,8 +0,0 @@
1export executable "hello";
2
3use "std.zig";
4
5export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 {
6 print_str("Hello, world!\n");
7 return 0;
8}
example/hello_world/hello_libc.zig created+12
...@@ -0,0 +1,12 @@
1export executable "hello";
2
3#link("c")
4extern {
5 fn printf(__format: *const u8, ...) -> i32;
6 fn exit(__status: i32) -> unreachable;
7}
8
9export fn _start() -> unreachable {
10 printf("Hello, world!\n");
11 exit(0);
12}
src/analyze.cpp+25-7
...@@ -599,14 +599,17 @@ LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name) {...@@ -599,14 +599,17 @@ LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name) {
599 }599 }
600}600}
601601
602static TypeStructField *get_struct_field(TypeTableEntry *struct_type, Buf *name) {602static void get_struct_field(TypeTableEntry *struct_type, Buf *name, TypeStructField **out_tsf, int *out_i) {
603 for (int i = 0; i < struct_type->data.structure.field_count; i += 1) {603 for (int i = 0; i < struct_type->data.structure.field_count; i += 1) {
604 TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];604 TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
605 if (buf_eql_buf(type_struct_field->name, name)) {605 if (buf_eql_buf(type_struct_field->name, name)) {
606 return type_struct_field;606 *out_tsf = type_struct_field;
607 *out_i = i;
608 return;
607 }609 }
608 }610 }
609 return nullptr;611 *out_tsf = nullptr;
612 *out_i = -1;
610}613}
611614
612static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,615static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
...@@ -618,10 +621,15 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i...@@ -618,10 +621,15 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
618 TypeTableEntry *return_type;621 TypeTableEntry *return_type;
619622
620 if (struct_type->id == TypeTableEntryIdStruct) {623 if (struct_type->id == TypeTableEntryIdStruct) {
624 FieldAccessNode *codegen_field_access = &node->codegen_node->data.field_access_node;
625
621 Buf *field_name = &node->data.field_access_expr.field_name;626 Buf *field_name = &node->data.field_access_expr.field_name;
622 TypeStructField *type_struct_field = get_struct_field(struct_type, field_name);627
623 if (type_struct_field) {628 get_struct_field(struct_type, field_name,
624 return_type = type_struct_field->type_entry;629 &codegen_field_access->type_struct_field,
630 &codegen_field_access->field_index);
631 if (codegen_field_access->type_struct_field) {
632 return_type = codegen_field_access->type_struct_field->type_entry;
625 } else {633 } else {
626 add_node_error(g, node,634 add_node_error(g, node,
627 buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&struct_type->name)));635 buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&struct_type->name)));
...@@ -1022,14 +1030,24 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -1022,14 +1030,24 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
1022 break;1030 break;
1023 }1031 }
10241032
1033 CastNode *cast_node = &node->codegen_node->data.cast_node;
1034
1025 // special casing this for now, TODO think about casting and do a general solution1035 // special casing this for now, TODO think about casting and do a general solution
1026 if (wanted_type == g->builtin_types.entry_isize &&1036 if (wanted_type == g->builtin_types.entry_isize &&
1027 actual_type->id == TypeTableEntryIdPointer)1037 actual_type->id == TypeTableEntryIdPointer)
1028 {1038 {
1039 cast_node->op = CastOpPtrToInt;
1029 return_type = wanted_type;1040 return_type = wanted_type;
1030 } else if (wanted_type == g->builtin_types.entry_isize &&1041 } else if (wanted_type->id == TypeTableEntryIdInt &&
1031 actual_type->id == TypeTableEntryIdInt)1042 actual_type->id == TypeTableEntryIdInt)
1032 {1043 {
1044 cast_node->op = CastOpIntWidenOrShorten;
1045 return_type = wanted_type;
1046 } else if (wanted_type == g->builtin_types.entry_string &&
1047 actual_type->id == TypeTableEntryIdArray &&
1048 actual_type->data.array.child_type == g->builtin_types.entry_u8)
1049 {
1050 cast_node->op = CastOpArrayToString;
1033 return_type = wanted_type;1051 return_type = wanted_type;
1034 } else {1052 } else {
1035 add_node_error(g, node,1053 add_node_error(g, node,
src/analyze.hpp+17
...@@ -231,6 +231,21 @@ struct StructDeclNode {...@@ -231,6 +231,21 @@ struct StructDeclNode {
231 TypeTableEntry *type_entry;231 TypeTableEntry *type_entry;
232};232};
233233
234struct FieldAccessNode {
235 int field_index;
236 TypeStructField *type_struct_field;
237};
238
239enum CastOp {
240 CastOpPtrToInt,
241 CastOpIntWidenOrShorten,
242 CastOpArrayToString,
243};
244
245struct CastNode {
246 CastOp op;
247};
248
234struct CodeGenNode {249struct CodeGenNode {
235 union {250 union {
236 TypeNode type_node; // for NodeTypeType251 TypeNode type_node; // for NodeTypeType
...@@ -240,6 +255,8 @@ struct CodeGenNode {...@@ -240,6 +255,8 @@ struct CodeGenNode {
240 AssignNode assign_node; // for NodeTypeBinOpExpr where op is BinOpTypeAssign255 AssignNode assign_node; // for NodeTypeBinOpExpr where op is BinOpTypeAssign
241 BlockNode block_node; // for NodeTypeBlock256 BlockNode block_node; // for NodeTypeBlock
242 StructDeclNode struct_decl_node; // for NodeTypeStructDecl257 StructDeclNode struct_decl_node; // for NodeTypeStructDecl
258 FieldAccessNode field_access_node; // for NodeTypeFieldAccessExpr
259 CastNode cast_node; // for NodeTypeCastExpr
243 } data;260 } data;
244 ExprNode expr_node; // for all the expression nodes261 ExprNode expr_node; // for all the expression nodes
245};262};
src/codegen.cpp+63-23
...@@ -197,6 +197,38 @@ static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {...@@ -197,6 +197,38 @@ static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {
197 return LLVMBuildInBoundsGEP(g->builder, array_ref_value, indices, 2, "");197 return LLVMBuildInBoundsGEP(g->builder, array_ref_value, indices, 2, "");
198}198}
199199
200static LLVMValueRef gen_field_val(CodeGen *g, AstNode *node) {
201 assert(node->type == NodeTypeFieldAccessExpr);
202
203 LLVMValueRef struct_val = gen_expr(g, node->data.field_access_expr.struct_expr);
204 assert(struct_val);
205
206 FieldAccessNode *codegen_field_access = &node->codegen_node->data.field_access_node;
207 assert(codegen_field_access->field_index >= 0);
208
209 return LLVMBuildExtractValue(g->builder, struct_val, codegen_field_access->field_index, "");
210}
211
212/*
213static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node) {
214 assert(node->type == NodeTypeFieldAccessExpr);
215
216 LLVMValueRef struct_ptr = gen_expr(g, node->data.field_access_expr.struct_expr);
217
218 assert(struct_ptr);
219
220 FieldAccessNode *codegen_field_access = &node->codegen_node->data.field_access_node;
221
222 assert(codegen_field_access->field_index >= 0);
223
224 LLVMValueRef indices[] = {
225 LLVMConstInt(LLVMInt32Type(), 0, false),
226 LLVMConstInt(LLVMInt32Type(), codegen_field_access->field_index, false)
227 };
228 return LLVMBuildStructGEP(g->builder, struct_ptr, indices, 2, "");
229}
230*/
231
200static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node) {232static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node) {
201 assert(node->type == NodeTypeArrayAccessExpr);233 assert(node->type == NodeTypeArrayAccessExpr);
202234
...@@ -208,12 +240,8 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node) {...@@ -208,12 +240,8 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node) {
208 assert(node->type == NodeTypeFieldAccessExpr);240 assert(node->type == NodeTypeFieldAccessExpr);
209241
210 TypeTableEntry *struct_type = get_expr_type(node->data.field_access_expr.struct_expr);242 TypeTableEntry *struct_type = get_expr_type(node->data.field_access_expr.struct_expr);
211 LLVMValueRef struct_ptr = gen_expr(g, node->data.field_access_expr.struct_expr);
212 Buf *name = &node->data.field_access_expr.field_name;243 Buf *name = &node->data.field_access_expr.field_name;
213244
214 // TODO add struct support
215 (void)struct_ptr;
216
217 if (struct_type->id == TypeTableEntryIdArray) {245 if (struct_type->id == TypeTableEntryIdArray) {
218 if (buf_eql_str(name, "len")) {246 if (buf_eql_str(name, "len")) {
219 return LLVMConstInt(g->builtin_types.entry_usize->type_ref,247 return LLVMConstInt(g->builtin_types.entry_usize->type_ref,
...@@ -221,6 +249,12 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node) {...@@ -221,6 +249,12 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node) {
221 } else {249 } else {
222 zig_panic("gen_field_access_expr bad array field");250 zig_panic("gen_field_access_expr bad array field");
223 }251 }
252 } else if (struct_type->id == TypeTableEntryIdStruct) {
253 /*
254 LLVMValueRef ptr = gen_field_ptr(g, node);
255 return LLVMBuildLoad(g->builder, ptr, "");
256 */
257 return gen_field_val(g, node);
224 } else {258 } else {
225 zig_panic("gen_field_access_expr bad struct type");259 zig_panic("gen_field_access_expr bad struct type");
226 }260 }
...@@ -259,30 +293,36 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {...@@ -259,30 +293,36 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
259 TypeTableEntry *actual_type = get_expr_type(node->data.cast_expr.expr);293 TypeTableEntry *actual_type = get_expr_type(node->data.cast_expr.expr);
260 TypeTableEntry *wanted_type = get_expr_type(node);294 TypeTableEntry *wanted_type = get_expr_type(node);
261295
262 // this asserts are here only because no other casting codegen is supported currently296 CastNode *cast_node = &node->codegen_node->data.cast_node;
263 assert(wanted_type == g->builtin_types.entry_isize);297
264298 switch (cast_node->op) {
265 if (wanted_type->id == TypeTableEntryIdPointer) {299 case CastOpPtrToInt:
266 return LLVMBuildIntToPtr(g->builder, expr_val, wanted_type->type_ref, "");300 return LLVMBuildPtrToInt(g->builder, expr_val, wanted_type->type_ref, "");
267 } else if (wanted_type->id == TypeTableEntryIdInt) {301 case CastOpIntWidenOrShorten:
268 if (actual_type->size_in_bits == wanted_type->size_in_bits) {302 if (actual_type->size_in_bits == wanted_type->size_in_bits) {
269 if (actual_type->id == TypeTableEntryIdPointer) {303 return expr_val;
270 return LLVMBuildPtrToInt(g->builder, expr_val, wanted_type->type_ref, "");304 } else if (actual_type->size_in_bits < wanted_type->size_in_bits) {
305 if (actual_type->data.integral.is_signed && wanted_type->data.integral.is_signed) {
306 return LLVMBuildSExt(g->builder, expr_val, wanted_type->type_ref, "");
307 } else {
308 zig_panic("TODO gen_cast_expr sign mismatch");
309 }
271 } else {310 } else {
272 zig_panic("TODO gen_cast_expr");311 zig_panic("TODO gen_cast_expr");
273 }312 }
274 } else if (actual_type->size_in_bits < wanted_type->size_in_bits) {313 case CastOpArrayToString:
275 if (actual_type->data.integral.is_signed && wanted_type->data.integral.is_signed) {314 {
276 return LLVMBuildSExt(g->builder, expr_val, wanted_type->type_ref, "");315 LLVMValueRef struct_vals[] = {
277 } else {316 expr_val,
278 zig_panic("TODO gen_cast_expr sign mismatch");317 LLVMConstInt(g->builtin_types.entry_usize->type_ref, actual_type->data.array.len, false)
318 };
319 unsigned field_count = g->builtin_types.entry_string->data.structure.field_count;
320 assert(field_count == 2);
321 return LLVMConstNamedStruct(g->builtin_types.entry_string->type_ref,
322 struct_vals, field_count);
279 }323 }
280 } else {
281 zig_panic("TODO gen_cast_expr");
282 }
283 } else {
284 zig_panic("TODO gen_cast_expr");
285 }324 }
325 zig_unreachable();
286}326}
287327
288static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {328static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {
std/std.zig+2-5
...@@ -14,14 +14,11 @@ fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {...@@ -14,14 +14,11 @@ fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {
14}14}
1515
16// TODO error handling16// TODO error handling
17// TODO zig strings instead of C strings
18// TODO handle buffering and flushing17// TODO handle buffering and flushing
19// TODO non-i32 integer literals so we can remove the casts18// TODO non-i32 integer literals so we can remove the casts
20// TODO constants for SYS_write and stdout_fileno19// TODO constants for SYS_write and stdout_fileno
21//pub fn print_str(str : string) -> isize {20pub fn print_str(str : string) -> isize {
22pub fn print_str(str : *const u8, len: isize) -> isize {
23 let SYS_write = 1;21 let SYS_write = 1;
24 let stdout_fileno = 1;22 let stdout_fileno = 1;
25 //return syscall3(SYS_write as isize, stdout_fileno as isize, str.ptr as isize, str.len as isize);23 return syscall3(SYS_write as isize, stdout_fileno as isize, str.ptr as isize, str.len as isize);
26 return syscall3(SYS_write as isize, stdout_fileno as isize, str as isize, len);
27}24}
test/run_tests.cpp+1-1
...@@ -403,7 +403,7 @@ loop_2_end:...@@ -403,7 +403,7 @@ loop_2_end:
403use "std.zig";403use "std.zig";
404404
405export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 {405export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 {
406 print_str(c"Hello, world!\n", 14 as isize);406 print_str("Hello, world!\n" as string);
407 return 0;407 return 0;
408}408}
409 )SOURCE", "Hello, world!\n");409 )SOURCE", "Hello, world!\n");