authorgravatar for thejoshwolfe@gmail.comJosh Wolfe <thejoshwolfe@gmail.com> 2015-12-01 14:41:03-07:00
committergravatar for thejoshwolfe@gmail.comJosh Wolfe <thejoshwolfe@gmail.com> 2015-12-01 14:41:03-07:00
logc6a9ab107bb383759f3627ed828ea2a779844f2b
tree1bcca15a80247cf083a53a1c51c70a6d3b753064
parentab327344b671bff7f874f24691d7e3f19176167c

string literals have type *const u8


6 files changed, 56 insertions(+), 38 deletions(-)

example/hello_world/hello.zig+1-1
...@@ -2,7 +2,7 @@ export executable "hello";...@@ -2,7 +2,7 @@ export executable "hello";
22
3#link("c")3#link("c")
4extern {4extern {
5 fn puts(s: *mut u8) -> i32;5 fn puts(s: *const u8) -> i32;
6 fn exit(code: i32) -> unreachable;6 fn exit(code: i32) -> unreachable;
7}7}
88
src/analyze.cpp+46-33
...@@ -54,6 +54,26 @@ static void set_root_export_version(CodeGen *g, Buf *version_buf, AstNode *node)...@@ -54,6 +54,26 @@ static void set_root_export_version(CodeGen *g, Buf *version_buf, AstNode *node)
54 }54 }
55}55}
5656
57TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) {
58 TypeTableEntry **parent_pointer = is_const ?
59 &child_type->pointer_const_parent :
60 &child_type->pointer_mut_parent;
61 const char *const_or_mut_str = is_const ? "const" : "mut";
62 if (*parent_pointer) {
63 return *parent_pointer;
64 } else {
65 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
66 entry->type_ref = LLVMPointerType(child_type->type_ref, 0);
67 buf_resize(&entry->name, 0);
68 buf_appendf(&entry->name, "*%s %s", const_or_mut_str, buf_ptr(&child_type->name));
69 entry->di_type = LLVMZigCreateDebugPointerType(g->dbuilder, child_type->di_type,
70 g->pointer_size_bytes * 8, g->pointer_size_bytes * 8, buf_ptr(&entry->name));
71 g->type_table.put(&entry->name, entry);
72 *parent_pointer = entry;
73 return entry;
74 }
75}
76
57static void resolve_type(CodeGen *g, AstNode *node) {77static void resolve_type(CodeGen *g, AstNode *node) {
58 assert(!node->codegen_node);78 assert(!node->codegen_node);
59 node->codegen_node = allocate<CodeGenNode>(1);79 node->codegen_node = allocate<CodeGenNode>(1);
...@@ -75,28 +95,12 @@ static void resolve_type(CodeGen *g, AstNode *node) {...@@ -75,28 +95,12 @@ static void resolve_type(CodeGen *g, AstNode *node) {
75 case AstNodeTypeTypePointer:95 case AstNodeTypeTypePointer:
76 {96 {
77 resolve_type(g, node->data.type.child_type);97 resolve_type(g, node->data.type.child_type);
78 TypeNode *child_type_node = &node->data.type.child_type->codegen_node->data.type_node;98 TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry;
79 if (child_type_node->entry == g->builtin_types.entry_unreachable) {99 if (child_type == g->builtin_types.entry_unreachable) {
80 add_node_error(g, node,100 add_node_error(g, node,
81 buf_create_from_str("pointer to unreachable not allowed"));101 buf_create_from_str("pointer to unreachable not allowed"));
82 }102 }
83 TypeTableEntry **parent_pointer = node->data.type.is_const ?103 type_node->entry = get_pointer_to_type(g, child_type, node->data.type.is_const);
84 &child_type_node->entry->pointer_const_parent :
85 &child_type_node->entry->pointer_mut_parent;
86 const char *const_or_mut_str = node->data.type.is_const ? "const" : "mut";
87 if (*parent_pointer) {
88 type_node->entry = *parent_pointer;
89 } else {
90 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
91 entry->type_ref = LLVMPointerType(child_type_node->entry->type_ref, 0);
92 buf_resize(&entry->name, 0);
93 buf_appendf(&entry->name, "*%s %s", const_or_mut_str, buf_ptr(&child_type_node->entry->name));
94 entry->di_type = LLVMZigCreateDebugPointerType(g->dbuilder, child_type_node->entry->di_type,
95 g->pointer_size_bytes * 8, g->pointer_size_bytes * 8, buf_ptr(&entry->name));
96 g->type_table.put(&entry->name, entry);
97 type_node->entry = entry;
98 *parent_pointer = entry;
99 }
100 break;104 break;
101 }105 }
102 }106 }
...@@ -284,23 +288,26 @@ static TypeTableEntry * get_return_type(BlockContext *context) {...@@ -284,23 +288,26 @@ static TypeTableEntry * get_return_type(BlockContext *context) {
284}288}
285289
286static void check_type_compatibility(CodeGen *g, AstNode *node, TypeTableEntry *expected_type, TypeTableEntry *actual_type) {290static void check_type_compatibility(CodeGen *g, AstNode *node, TypeTableEntry *expected_type, TypeTableEntry *actual_type) {
291 if (expected_type == nullptr)
292 return; // anything will do
287 if (expected_type == actual_type)293 if (expected_type == actual_type)
288 return; // good294 return; // match
289 if (expected_type == g->builtin_types.entry_invalid || actual_type == g->builtin_types.entry_invalid)295 if (expected_type == g->builtin_types.entry_invalid || actual_type == g->builtin_types.entry_invalid)
290 return; // already complained296 return; // already complained
291 if (actual_type == g->builtin_types.entry_unreachable)297 if (actual_type == g->builtin_types.entry_unreachable)
292 return; // TODO: is this true?298 return; // TODO: is this true?
293299
294 // TODO better error message300 // TODO better error message
295 add_node_error(g, node, buf_sprintf("type mismatch."));301 add_node_error(g, node, buf_sprintf("type mismatch. expected %s. got %s", buf_ptr(&expected_type->name), buf_ptr(&actual_type->name)));
296}302}
297303
298static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, TypeTableEntry *expected_type, AstNode *node) {304static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, TypeTableEntry *expected_type, AstNode *node) {
305 TypeTableEntry *return_type = nullptr;
299 switch (node->type) {306 switch (node->type) {
300 case NodeTypeBlock:307 case NodeTypeBlock:
301 {308 {
302 // TODO: nested block scopes309 // TODO: nested block scopes
303 TypeTableEntry *return_type = g->builtin_types.entry_void;310 return_type = g->builtin_types.entry_void;
304 for (int i = 0; i < node->data.block.statements.length; i += 1) {311 for (int i = 0; i < node->data.block.statements.length; i += 1) {
305 AstNode *child = node->data.block.statements.at(i);312 AstNode *child = node->data.block.statements.at(i);
306 if (return_type == g->builtin_types.entry_unreachable) {313 if (return_type == g->builtin_types.entry_unreachable) {
...@@ -310,7 +317,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -310,7 +317,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
310 }317 }
311 return_type = analyze_expression(g, import, context, nullptr, child);318 return_type = analyze_expression(g, import, context, nullptr, child);
312 }319 }
313 return return_type;320 break;
314 }321 }
315322
316 case NodeTypeReturnExpr:323 case NodeTypeReturnExpr:
...@@ -330,7 +337,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -330,7 +337,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
330 }337 }
331338
332 check_type_compatibility(g, node, expected_return_type, actual_return_type);339 check_type_compatibility(g, node, expected_return_type, actual_return_type);
333 return g->builtin_types.entry_unreachable;340 return_type = g->builtin_types.entry_unreachable;
341 break;
334 }342 }
335343
336 case NodeTypeBinOpExpr:344 case NodeTypeBinOpExpr:
...@@ -338,7 +346,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -338,7 +346,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
338 // TODO: think about expected types346 // TODO: think about expected types
339 analyze_expression(g, import, context, expected_type, node->data.bin_op_expr.op1);347 analyze_expression(g, import, context, expected_type, node->data.bin_op_expr.op1);
340 analyze_expression(g, import, context, expected_type, node->data.bin_op_expr.op2);348 analyze_expression(g, import, context, expected_type, node->data.bin_op_expr.op2);
341 return expected_type;349 return_type = expected_type;
350 break;
342 }351 }
343352
344 case NodeTypeFnCallExpr:353 case NodeTypeFnCallExpr:
...@@ -358,7 +367,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -358,7 +367,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
358 analyze_expression(g, import, context, nullptr, child);367 analyze_expression(g, import, context, nullptr, child);
359 }368 }
360369
361 return g->builtin_types.entry_invalid;370 return_type = g->builtin_types.entry_invalid;
362 } else {371 } else {
363 FnTableEntry *fn_table_entry = entry->value;372 FnTableEntry *fn_table_entry = entry->value;
364 assert(fn_table_entry->proto_node->type == NodeTypeFnProto);373 assert(fn_table_entry->proto_node->type == NodeTypeFnProto);
...@@ -388,21 +397,23 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -388,21 +397,23 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
388 analyze_expression(g, import, context, expected_param_type, child);397 analyze_expression(g, import, context, expected_param_type, child);
389 }398 }
390399
391 TypeTableEntry *return_type = fn_proto->return_type->codegen_node->data.type_node.entry;400 return_type = fn_proto->return_type->codegen_node->data.type_node.entry;
392 check_type_compatibility(g, node, expected_type, return_type);
393 return return_type;
394 }401 }
402 break;
395 }403 }
396404
397 case NodeTypeNumberLiteral:405 case NodeTypeNumberLiteral:
398 // TODO: generic literal int type406 // TODO: generic literal int type
399 return g->builtin_types.entry_i32;407 return_type = g->builtin_types.entry_i32;
408 break;
400409
401 case NodeTypeStringLiteral:410 case NodeTypeStringLiteral:
402 zig_panic("TODO: string literal");411 return_type = g->builtin_types.entry_string_literal;
412 break;
403413
404 case NodeTypeUnreachable:414 case NodeTypeUnreachable:
405 return g->builtin_types.entry_unreachable;415 return_type = g->builtin_types.entry_unreachable;
416 break;
406417
407 case NodeTypeSymbol:418 case NodeTypeSymbol:
408 // look up symbol in symbol table419 // look up symbol in symbol table
...@@ -423,7 +434,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -423,7 +434,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
423 case NodeTypeUse:434 case NodeTypeUse:
424 zig_unreachable();435 zig_unreachable();
425 }436 }
426 zig_unreachable();437 assert(return_type);
438 check_type_compatibility(g, node, expected_type, return_type);
439 return return_type;
427}440}
428441
429static void check_fn_def_control_flow(CodeGen *g, AstNode *node) {442static void check_fn_def_control_flow(CodeGen *g, AstNode *node) {
src/analyze.hpp+3
...@@ -12,7 +12,10 @@ struct CodeGen;...@@ -12,7 +12,10 @@ struct CodeGen;
12struct AstNode;12struct AstNode;
13struct Buf;13struct Buf;
1414
15struct TypeTableEntry;
16
15void semantic_analyze(CodeGen *g);17void semantic_analyze(CodeGen *g);
16void add_node_error(CodeGen *g, AstNode *node, Buf *msg);18void add_node_error(CodeGen *g, AstNode *node, Buf *msg);
19TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
1720
18#endif21#endif
src/codegen.cpp+1
...@@ -589,6 +589,7 @@ static void define_primitive_types(CodeGen *g) {...@@ -589,6 +589,7 @@ static void define_primitive_types(CodeGen *g) {
589 g->type_table.put(&entry->name, entry);589 g->type_table.put(&entry->name, entry);
590 g->builtin_types.entry_u8 = entry;590 g->builtin_types.entry_u8 = entry;
591 }591 }
592 g->builtin_types.entry_string_literal = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
592 {593 {
593 TypeTableEntry *entry = allocate<TypeTableEntry>(1);594 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
594 entry->type_ref = LLVMInt32Type();595 entry->type_ref = LLVMInt32Type();
src/semantic_info.hpp+1
...@@ -65,6 +65,7 @@ struct CodeGen {...@@ -65,6 +65,7 @@ struct CodeGen {
65 struct {65 struct {
66 TypeTableEntry *entry_u8;66 TypeTableEntry *entry_u8;
67 TypeTableEntry *entry_i32;67 TypeTableEntry *entry_i32;
68 TypeTableEntry *entry_string_literal;
68 TypeTableEntry *entry_void;69 TypeTableEntry *entry_void;
69 TypeTableEntry *entry_unreachable;70 TypeTableEntry *entry_unreachable;
70 TypeTableEntry *entry_invalid;71 TypeTableEntry *entry_invalid;
test/run_tests.cpp+4-4
...@@ -99,7 +99,7 @@ static void add_compiling_test_cases(void) {...@@ -99,7 +99,7 @@ static void add_compiling_test_cases(void) {
99 add_simple_case("hello world with libc", R"SOURCE(99 add_simple_case("hello world with libc", R"SOURCE(
100 #link("c")100 #link("c")
101 extern {101 extern {
102 fn puts(s: *mut u8) -> i32;102 fn puts(s: *const u8) -> i32;
103 fn exit(code: i32) -> unreachable;103 fn exit(code: i32) -> unreachable;
104 }104 }
105105
...@@ -112,7 +112,7 @@ static void add_compiling_test_cases(void) {...@@ -112,7 +112,7 @@ static void add_compiling_test_cases(void) {
112 add_simple_case("function call", R"SOURCE(112 add_simple_case("function call", R"SOURCE(
113 #link("c")113 #link("c")
114 extern {114 extern {
115 fn puts(s: *mut u8) -> i32;115 fn puts(s: *const u8) -> i32;
116 fn exit(code: i32) -> unreachable;116 fn exit(code: i32) -> unreachable;
117 }117 }
118118
...@@ -134,7 +134,7 @@ static void add_compiling_test_cases(void) {...@@ -134,7 +134,7 @@ static void add_compiling_test_cases(void) {
134 add_simple_case("comments", R"SOURCE(134 add_simple_case("comments", R"SOURCE(
135 #link("c")135 #link("c")
136 extern {136 extern {
137 fn puts(s: *mut u8) -> i32;137 fn puts(s: *const u8) -> i32;
138 fn exit(code: i32) -> unreachable;138 fn exit(code: i32) -> unreachable;
139 }139 }
140140
...@@ -169,7 +169,7 @@ static void add_compiling_test_cases(void) {...@@ -169,7 +169,7 @@ static void add_compiling_test_cases(void) {
169 add_source_file(tc, "libc.zig", R"SOURCE(169 add_source_file(tc, "libc.zig", R"SOURCE(
170 #link("c")170 #link("c")
171 extern {171 extern {
172 pub fn puts(s: *mut u8) -> i32;172 pub fn puts(s: *const u8) -> i32;
173 pub fn exit(code: i32) -> unreachable;173 pub fn exit(code: i32) -> unreachable;
174 }174 }
175 )SOURCE");175 )SOURCE");