mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
string literals have type *const u8
This commit is contained in:
parent
ab327344b6
commit
c6a9ab107b
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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();
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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");
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user