From c6a9ab107bb383759f3627ed828ea2a779844f2b Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Tue, 1 Dec 2015 14:41:03 -0700 Subject: [PATCH] string literals have type *const u8 --- example/hello_world/hello.zig | 2 +- src/analyze.cpp | 79 ++++++++++++++++++++--------------- src/analyze.hpp | 3 ++ src/codegen.cpp | 1 + src/semantic_info.hpp | 1 + test/run_tests.cpp | 8 ++-- 6 files changed, 56 insertions(+), 38 deletions(-) diff --git a/example/hello_world/hello.zig b/example/hello_world/hello.zig index d9efc46e96..d950d9aa17 100644 --- a/example/hello_world/hello.zig +++ b/example/hello_world/hello.zig @@ -2,7 +2,7 @@ export executable "hello"; #link("c") extern { - fn puts(s: *mut u8) -> i32; + fn puts(s: *const u8) -> i32; fn exit(code: i32) -> unreachable; } diff --git a/src/analyze.cpp b/src/analyze.cpp index 2ae0b42a29..de0d5b1cdb 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -54,6 +54,26 @@ static void set_root_export_version(CodeGen *g, Buf *version_buf, AstNode *node) } } +TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) { + TypeTableEntry **parent_pointer = is_const ? + &child_type->pointer_const_parent : + &child_type->pointer_mut_parent; + const char *const_or_mut_str = is_const ? "const" : "mut"; + if (*parent_pointer) { + return *parent_pointer; + } else { + TypeTableEntry *entry = allocate(1); + entry->type_ref = LLVMPointerType(child_type->type_ref, 0); + buf_resize(&entry->name, 0); + buf_appendf(&entry->name, "*%s %s", const_or_mut_str, buf_ptr(&child_type->name)); + entry->di_type = LLVMZigCreateDebugPointerType(g->dbuilder, child_type->di_type, + g->pointer_size_bytes * 8, g->pointer_size_bytes * 8, buf_ptr(&entry->name)); + g->type_table.put(&entry->name, entry); + *parent_pointer = entry; + return entry; + } +} + static void resolve_type(CodeGen *g, AstNode *node) { assert(!node->codegen_node); node->codegen_node = allocate(1); @@ -75,28 +95,12 @@ static void resolve_type(CodeGen *g, AstNode *node) { case AstNodeTypeTypePointer: { resolve_type(g, node->data.type.child_type); - TypeNode *child_type_node = &node->data.type.child_type->codegen_node->data.type_node; - if (child_type_node->entry == g->builtin_types.entry_unreachable) { + TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry; + if (child_type == g->builtin_types.entry_unreachable) { add_node_error(g, node, buf_create_from_str("pointer to unreachable not allowed")); } - TypeTableEntry **parent_pointer = node->data.type.is_const ? - &child_type_node->entry->pointer_const_parent : - &child_type_node->entry->pointer_mut_parent; - const char *const_or_mut_str = node->data.type.is_const ? "const" : "mut"; - if (*parent_pointer) { - type_node->entry = *parent_pointer; - } else { - TypeTableEntry *entry = allocate(1); - entry->type_ref = LLVMPointerType(child_type_node->entry->type_ref, 0); - buf_resize(&entry->name, 0); - buf_appendf(&entry->name, "*%s %s", const_or_mut_str, buf_ptr(&child_type_node->entry->name)); - entry->di_type = LLVMZigCreateDebugPointerType(g->dbuilder, child_type_node->entry->di_type, - g->pointer_size_bytes * 8, g->pointer_size_bytes * 8, buf_ptr(&entry->name)); - g->type_table.put(&entry->name, entry); - type_node->entry = entry; - *parent_pointer = entry; - } + type_node->entry = get_pointer_to_type(g, child_type, node->data.type.is_const); break; } } @@ -284,23 +288,26 @@ static TypeTableEntry * get_return_type(BlockContext *context) { } static void check_type_compatibility(CodeGen *g, AstNode *node, TypeTableEntry *expected_type, TypeTableEntry *actual_type) { + if (expected_type == nullptr) + return; // anything will do if (expected_type == actual_type) - return; // good + return; // match if (expected_type == g->builtin_types.entry_invalid || actual_type == g->builtin_types.entry_invalid) return; // already complained if (actual_type == g->builtin_types.entry_unreachable) return; // TODO: is this true? // TODO better error message - add_node_error(g, node, buf_sprintf("type mismatch.")); + add_node_error(g, node, buf_sprintf("type mismatch. expected %s. got %s", buf_ptr(&expected_type->name), buf_ptr(&actual_type->name))); } static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, TypeTableEntry *expected_type, AstNode *node) { + TypeTableEntry *return_type = nullptr; switch (node->type) { case NodeTypeBlock: { // TODO: nested block scopes - TypeTableEntry *return_type = g->builtin_types.entry_void; + return_type = g->builtin_types.entry_void; for (int i = 0; i < node->data.block.statements.length; i += 1) { AstNode *child = node->data.block.statements.at(i); if (return_type == g->builtin_types.entry_unreachable) { @@ -310,7 +317,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, } return_type = analyze_expression(g, import, context, nullptr, child); } - return return_type; + break; } case NodeTypeReturnExpr: @@ -330,7 +337,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, } check_type_compatibility(g, node, expected_return_type, actual_return_type); - return g->builtin_types.entry_unreachable; + return_type = g->builtin_types.entry_unreachable; + break; } case NodeTypeBinOpExpr: @@ -338,7 +346,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, // TODO: think about expected types analyze_expression(g, import, context, expected_type, node->data.bin_op_expr.op1); analyze_expression(g, import, context, expected_type, node->data.bin_op_expr.op2); - return expected_type; + return_type = expected_type; + break; } case NodeTypeFnCallExpr: @@ -358,7 +367,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, analyze_expression(g, import, context, nullptr, child); } - return g->builtin_types.entry_invalid; + return_type = g->builtin_types.entry_invalid; } else { FnTableEntry *fn_table_entry = entry->value; assert(fn_table_entry->proto_node->type == NodeTypeFnProto); @@ -388,21 +397,23 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, analyze_expression(g, import, context, expected_param_type, child); } - TypeTableEntry *return_type = fn_proto->return_type->codegen_node->data.type_node.entry; - check_type_compatibility(g, node, expected_type, return_type); - return return_type; + return_type = fn_proto->return_type->codegen_node->data.type_node.entry; } + break; } case NodeTypeNumberLiteral: // TODO: generic literal int type - return g->builtin_types.entry_i32; + return_type = g->builtin_types.entry_i32; + break; case NodeTypeStringLiteral: - zig_panic("TODO: string literal"); + return_type = g->builtin_types.entry_string_literal; + break; case NodeTypeUnreachable: - return g->builtin_types.entry_unreachable; + return_type = g->builtin_types.entry_unreachable; + break; case NodeTypeSymbol: // look up symbol in symbol table @@ -423,7 +434,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, case NodeTypeUse: zig_unreachable(); } - zig_unreachable(); + assert(return_type); + check_type_compatibility(g, node, expected_type, return_type); + return return_type; } static void check_fn_def_control_flow(CodeGen *g, AstNode *node) { diff --git a/src/analyze.hpp b/src/analyze.hpp index 110a3614e0..72908c682b 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -12,7 +12,10 @@ struct CodeGen; struct AstNode; struct Buf; +struct TypeTableEntry; + void semantic_analyze(CodeGen *g); void add_node_error(CodeGen *g, AstNode *node, Buf *msg); +TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const); #endif diff --git a/src/codegen.cpp b/src/codegen.cpp index 692e23ad73..ab74ae19ce 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -589,6 +589,7 @@ static void define_primitive_types(CodeGen *g) { g->type_table.put(&entry->name, entry); g->builtin_types.entry_u8 = entry; } + g->builtin_types.entry_string_literal = get_pointer_to_type(g, g->builtin_types.entry_u8, true); { TypeTableEntry *entry = allocate(1); entry->type_ref = LLVMInt32Type(); diff --git a/src/semantic_info.hpp b/src/semantic_info.hpp index f0a79d685d..66b57f5a55 100644 --- a/src/semantic_info.hpp +++ b/src/semantic_info.hpp @@ -65,6 +65,7 @@ struct CodeGen { struct { TypeTableEntry *entry_u8; TypeTableEntry *entry_i32; + TypeTableEntry *entry_string_literal; TypeTableEntry *entry_void; TypeTableEntry *entry_unreachable; TypeTableEntry *entry_invalid; diff --git a/test/run_tests.cpp b/test/run_tests.cpp index 979ad38997..6b6d039f4c 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -99,7 +99,7 @@ static void add_compiling_test_cases(void) { add_simple_case("hello world with libc", R"SOURCE( #link("c") extern { - fn puts(s: *mut u8) -> i32; + fn puts(s: *const u8) -> i32; fn exit(code: i32) -> unreachable; } @@ -112,7 +112,7 @@ static void add_compiling_test_cases(void) { add_simple_case("function call", R"SOURCE( #link("c") extern { - fn puts(s: *mut u8) -> i32; + fn puts(s: *const u8) -> i32; fn exit(code: i32) -> unreachable; } @@ -134,7 +134,7 @@ static void add_compiling_test_cases(void) { add_simple_case("comments", R"SOURCE( #link("c") extern { - fn puts(s: *mut u8) -> i32; + fn puts(s: *const u8) -> i32; fn exit(code: i32) -> unreachable; } @@ -169,7 +169,7 @@ static void add_compiling_test_cases(void) { add_source_file(tc, "libc.zig", R"SOURCE( #link("c") extern { - pub fn puts(s: *mut u8) -> i32; + pub fn puts(s: *const u8) -> i32; pub fn exit(code: i32) -> unreachable; } )SOURCE");