string literals have type *const u8

This commit is contained in:
Josh Wolfe 2015-12-01 14:41:03 -07:00
parent ab327344b6
commit c6a9ab107b
6 changed files with 56 additions and 38 deletions

View File

@ -2,7 +2,7 @@ export executable "hello";
#link("c") #link("c")
extern { extern {
fn puts(s: *mut u8) -> i32; fn puts(s: *const u8) -> i32;
fn exit(code: i32) -> unreachable; fn exit(code: i32) -> unreachable;
} }

View File

@ -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<TypeTableEntry>(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) { static void resolve_type(CodeGen *g, AstNode *node) {
assert(!node->codegen_node); assert(!node->codegen_node);
node->codegen_node = allocate<CodeGenNode>(1); node->codegen_node = allocate<CodeGenNode>(1);
@ -75,28 +95,12 @@ static void resolve_type(CodeGen *g, AstNode *node) {
case AstNodeTypeTypePointer: case AstNodeTypeTypePointer:
{ {
resolve_type(g, node->data.type.child_type); resolve_type(g, node->data.type.child_type);
TypeNode *child_type_node = &node->data.type.child_type->codegen_node->data.type_node; TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry;
if (child_type_node->entry == g->builtin_types.entry_unreachable) { if (child_type == g->builtin_types.entry_unreachable) {
add_node_error(g, node, add_node_error(g, node,
buf_create_from_str("pointer to unreachable not allowed")); buf_create_from_str("pointer to unreachable not allowed"));
} }
TypeTableEntry **parent_pointer = node->data.type.is_const ? type_node->entry = get_pointer_to_type(g, child_type, 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<TypeTableEntry>(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;
}
break; 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) { 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) if (expected_type == actual_type)
return; // good return; // match
if (expected_type == g->builtin_types.entry_invalid || actual_type == g->builtin_types.entry_invalid) if (expected_type == g->builtin_types.entry_invalid || actual_type == g->builtin_types.entry_invalid)
return; // already complained return; // already complained
if (actual_type == g->builtin_types.entry_unreachable) if (actual_type == g->builtin_types.entry_unreachable)
return; // TODO: is this true? return; // TODO: is this true?
// TODO better error message // 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) { static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, TypeTableEntry *expected_type, AstNode *node) {
TypeTableEntry *return_type = nullptr;
switch (node->type) { switch (node->type) {
case NodeTypeBlock: case NodeTypeBlock:
{ {
// TODO: nested block scopes // 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) { for (int i = 0; i < node->data.block.statements.length; i += 1) {
AstNode *child = node->data.block.statements.at(i); AstNode *child = node->data.block.statements.at(i);
if (return_type == g->builtin_types.entry_unreachable) { 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_type = analyze_expression(g, import, context, nullptr, child);
} }
return return_type; break;
} }
case NodeTypeReturnExpr: 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); 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: case NodeTypeBinOpExpr:
@ -338,7 +346,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
// TODO: think about expected types // 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.op1);
analyze_expression(g, import, context, expected_type, node->data.bin_op_expr.op2); analyze_expression(g, import, context, expected_type, node->data.bin_op_expr.op2);
return expected_type; return_type = expected_type;
break;
} }
case NodeTypeFnCallExpr: case NodeTypeFnCallExpr:
@ -358,7 +367,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
analyze_expression(g, import, context, nullptr, child); analyze_expression(g, import, context, nullptr, child);
} }
return g->builtin_types.entry_invalid; return_type = g->builtin_types.entry_invalid;
} else { } else {
FnTableEntry *fn_table_entry = entry->value; FnTableEntry *fn_table_entry = entry->value;
assert(fn_table_entry->proto_node->type == NodeTypeFnProto); 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); analyze_expression(g, import, context, expected_param_type, child);
} }
TypeTableEntry *return_type = fn_proto->return_type->codegen_node->data.type_node.entry; return_type = fn_proto->return_type->codegen_node->data.type_node.entry;
check_type_compatibility(g, node, expected_type, return_type);
return return_type;
} }
break;
} }
case NodeTypeNumberLiteral: case NodeTypeNumberLiteral:
// TODO: generic literal int type // TODO: generic literal int type
return g->builtin_types.entry_i32; return_type = g->builtin_types.entry_i32;
break;
case NodeTypeStringLiteral: case NodeTypeStringLiteral:
zig_panic("TODO: string literal"); return_type = g->builtin_types.entry_string_literal;
break;
case NodeTypeUnreachable: case NodeTypeUnreachable:
return g->builtin_types.entry_unreachable; return_type = g->builtin_types.entry_unreachable;
break;
case NodeTypeSymbol: case NodeTypeSymbol:
// look up symbol in symbol table // look up symbol in symbol table
@ -423,7 +434,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
case NodeTypeUse: case NodeTypeUse:
zig_unreachable(); 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) { static void check_fn_def_control_flow(CodeGen *g, AstNode *node) {

View File

@ -12,7 +12,10 @@ struct CodeGen;
struct AstNode; struct AstNode;
struct Buf; struct Buf;
struct TypeTableEntry;
void semantic_analyze(CodeGen *g); void semantic_analyze(CodeGen *g);
void add_node_error(CodeGen *g, AstNode *node, Buf *msg); void add_node_error(CodeGen *g, AstNode *node, Buf *msg);
TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
#endif #endif

View File

@ -589,6 +589,7 @@ static void define_primitive_types(CodeGen *g) {
g->type_table.put(&entry->name, entry); g->type_table.put(&entry->name, entry);
g->builtin_types.entry_u8 = 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<TypeTableEntry>(1); TypeTableEntry *entry = allocate<TypeTableEntry>(1);
entry->type_ref = LLVMInt32Type(); entry->type_ref = LLVMInt32Type();

View File

@ -65,6 +65,7 @@ struct CodeGen {
struct { struct {
TypeTableEntry *entry_u8; TypeTableEntry *entry_u8;
TypeTableEntry *entry_i32; TypeTableEntry *entry_i32;
TypeTableEntry *entry_string_literal;
TypeTableEntry *entry_void; TypeTableEntry *entry_void;
TypeTableEntry *entry_unreachable; TypeTableEntry *entry_unreachable;
TypeTableEntry *entry_invalid; TypeTableEntry *entry_invalid;

View File

@ -99,7 +99,7 @@ static void add_compiling_test_cases(void) {
add_simple_case("hello world with libc", R"SOURCE( add_simple_case("hello world with libc", R"SOURCE(
#link("c") #link("c")
extern { extern {
fn puts(s: *mut u8) -> i32; fn puts(s: *const u8) -> i32;
fn exit(code: i32) -> unreachable; fn exit(code: i32) -> unreachable;
} }
@ -112,7 +112,7 @@ static void add_compiling_test_cases(void) {
add_simple_case("function call", R"SOURCE( add_simple_case("function call", R"SOURCE(
#link("c") #link("c")
extern { extern {
fn puts(s: *mut u8) -> i32; fn puts(s: *const u8) -> i32;
fn exit(code: i32) -> unreachable; fn exit(code: i32) -> unreachable;
} }
@ -134,7 +134,7 @@ static void add_compiling_test_cases(void) {
add_simple_case("comments", R"SOURCE( add_simple_case("comments", R"SOURCE(
#link("c") #link("c")
extern { extern {
fn puts(s: *mut u8) -> i32; fn puts(s: *const u8) -> i32;
fn exit(code: i32) -> unreachable; fn exit(code: i32) -> unreachable;
} }
@ -169,7 +169,7 @@ static void add_compiling_test_cases(void) {
add_source_file(tc, "libc.zig", R"SOURCE( add_source_file(tc, "libc.zig", R"SOURCE(
#link("c") #link("c")
extern { extern {
pub fn puts(s: *mut u8) -> i32; pub fn puts(s: *const u8) -> i32;
pub fn exit(code: i32) -> unreachable; pub fn exit(code: i32) -> unreachable;
} }
)SOURCE"); )SOURCE");