mirror of
https://github.com/ziglang/zig.git
synced 2026-02-21 16:54:52 +00:00
std: print_str no longer requires length argument
add explicit casting support from array to string
This commit is contained in:
parent
a10277bd94
commit
ac630d354d
@ -1,12 +1,9 @@
|
||||
export executable "hello";
|
||||
|
||||
#link("c")
|
||||
extern {
|
||||
fn printf(__format: *const u8, ...) -> i32;
|
||||
fn exit(__status: i32) -> unreachable;
|
||||
}
|
||||
use "std.zig";
|
||||
|
||||
export fn _start() -> unreachable {
|
||||
printf("Hello, world!\n");
|
||||
exit(0);
|
||||
export fn main(argc: isize, argv: *mut *mut u8, env: *mut *mut u8) -> i32 {
|
||||
// TODO implicit coercion from array to string
|
||||
print_str("Hello, world!\n" as string);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
export executable "hello";
|
||||
|
||||
use "std.zig";
|
||||
|
||||
export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 {
|
||||
print_str("Hello, world!\n");
|
||||
return 0;
|
||||
}
|
||||
12
example/hello_world/hello_libc.zig
Normal file
12
example/hello_world/hello_libc.zig
Normal file
@ -0,0 +1,12 @@
|
||||
export executable "hello";
|
||||
|
||||
#link("c")
|
||||
extern {
|
||||
fn printf(__format: *const u8, ...) -> i32;
|
||||
fn exit(__status: i32) -> unreachable;
|
||||
}
|
||||
|
||||
export fn _start() -> unreachable {
|
||||
printf("Hello, world!\n");
|
||||
exit(0);
|
||||
}
|
||||
@ -599,14 +599,17 @@ LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name) {
|
||||
}
|
||||
}
|
||||
|
||||
static TypeStructField *get_struct_field(TypeTableEntry *struct_type, Buf *name) {
|
||||
static void get_struct_field(TypeTableEntry *struct_type, Buf *name, TypeStructField **out_tsf, int *out_i) {
|
||||
for (int i = 0; i < struct_type->data.structure.field_count; i += 1) {
|
||||
TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
|
||||
if (buf_eql_buf(type_struct_field->name, name)) {
|
||||
return type_struct_field;
|
||||
*out_tsf = type_struct_field;
|
||||
*out_i = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
*out_tsf = nullptr;
|
||||
*out_i = -1;
|
||||
}
|
||||
|
||||
static 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
|
||||
TypeTableEntry *return_type;
|
||||
|
||||
if (struct_type->id == TypeTableEntryIdStruct) {
|
||||
FieldAccessNode *codegen_field_access = &node->codegen_node->data.field_access_node;
|
||||
|
||||
Buf *field_name = &node->data.field_access_expr.field_name;
|
||||
TypeStructField *type_struct_field = get_struct_field(struct_type, field_name);
|
||||
if (type_struct_field) {
|
||||
return_type = type_struct_field->type_entry;
|
||||
|
||||
get_struct_field(struct_type, field_name,
|
||||
&codegen_field_access->type_struct_field,
|
||||
&codegen_field_access->field_index);
|
||||
if (codegen_field_access->type_struct_field) {
|
||||
return_type = codegen_field_access->type_struct_field->type_entry;
|
||||
} else {
|
||||
add_node_error(g, node,
|
||||
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,
|
||||
break;
|
||||
}
|
||||
|
||||
CastNode *cast_node = &node->codegen_node->data.cast_node;
|
||||
|
||||
// special casing this for now, TODO think about casting and do a general solution
|
||||
if (wanted_type == g->builtin_types.entry_isize &&
|
||||
actual_type->id == TypeTableEntryIdPointer)
|
||||
{
|
||||
cast_node->op = CastOpPtrToInt;
|
||||
return_type = wanted_type;
|
||||
} else if (wanted_type == g->builtin_types.entry_isize &&
|
||||
} else if (wanted_type->id == TypeTableEntryIdInt &&
|
||||
actual_type->id == TypeTableEntryIdInt)
|
||||
{
|
||||
cast_node->op = CastOpIntWidenOrShorten;
|
||||
return_type = wanted_type;
|
||||
} else if (wanted_type == g->builtin_types.entry_string &&
|
||||
actual_type->id == TypeTableEntryIdArray &&
|
||||
actual_type->data.array.child_type == g->builtin_types.entry_u8)
|
||||
{
|
||||
cast_node->op = CastOpArrayToString;
|
||||
return_type = wanted_type;
|
||||
} else {
|
||||
add_node_error(g, node,
|
||||
|
||||
@ -231,6 +231,21 @@ struct StructDeclNode {
|
||||
TypeTableEntry *type_entry;
|
||||
};
|
||||
|
||||
struct FieldAccessNode {
|
||||
int field_index;
|
||||
TypeStructField *type_struct_field;
|
||||
};
|
||||
|
||||
enum CastOp {
|
||||
CastOpPtrToInt,
|
||||
CastOpIntWidenOrShorten,
|
||||
CastOpArrayToString,
|
||||
};
|
||||
|
||||
struct CastNode {
|
||||
CastOp op;
|
||||
};
|
||||
|
||||
struct CodeGenNode {
|
||||
union {
|
||||
TypeNode type_node; // for NodeTypeType
|
||||
@ -240,6 +255,8 @@ struct CodeGenNode {
|
||||
AssignNode assign_node; // for NodeTypeBinOpExpr where op is BinOpTypeAssign
|
||||
BlockNode block_node; // for NodeTypeBlock
|
||||
StructDeclNode struct_decl_node; // for NodeTypeStructDecl
|
||||
FieldAccessNode field_access_node; // for NodeTypeFieldAccessExpr
|
||||
CastNode cast_node; // for NodeTypeCastExpr
|
||||
} data;
|
||||
ExprNode expr_node; // for all the expression nodes
|
||||
};
|
||||
|
||||
@ -197,6 +197,38 @@ static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {
|
||||
return LLVMBuildInBoundsGEP(g->builder, array_ref_value, indices, 2, "");
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_field_val(CodeGen *g, AstNode *node) {
|
||||
assert(node->type == NodeTypeFieldAccessExpr);
|
||||
|
||||
LLVMValueRef struct_val = gen_expr(g, node->data.field_access_expr.struct_expr);
|
||||
assert(struct_val);
|
||||
|
||||
FieldAccessNode *codegen_field_access = &node->codegen_node->data.field_access_node;
|
||||
assert(codegen_field_access->field_index >= 0);
|
||||
|
||||
return LLVMBuildExtractValue(g->builder, struct_val, codegen_field_access->field_index, "");
|
||||
}
|
||||
|
||||
/*
|
||||
static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node) {
|
||||
assert(node->type == NodeTypeFieldAccessExpr);
|
||||
|
||||
LLVMValueRef struct_ptr = gen_expr(g, node->data.field_access_expr.struct_expr);
|
||||
|
||||
assert(struct_ptr);
|
||||
|
||||
FieldAccessNode *codegen_field_access = &node->codegen_node->data.field_access_node;
|
||||
|
||||
assert(codegen_field_access->field_index >= 0);
|
||||
|
||||
LLVMValueRef indices[] = {
|
||||
LLVMConstInt(LLVMInt32Type(), 0, false),
|
||||
LLVMConstInt(LLVMInt32Type(), codegen_field_access->field_index, false)
|
||||
};
|
||||
return LLVMBuildStructGEP(g->builder, struct_ptr, indices, 2, "");
|
||||
}
|
||||
*/
|
||||
|
||||
static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node) {
|
||||
assert(node->type == NodeTypeArrayAccessExpr);
|
||||
|
||||
@ -208,12 +240,8 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node) {
|
||||
assert(node->type == NodeTypeFieldAccessExpr);
|
||||
|
||||
TypeTableEntry *struct_type = get_expr_type(node->data.field_access_expr.struct_expr);
|
||||
LLVMValueRef struct_ptr = gen_expr(g, node->data.field_access_expr.struct_expr);
|
||||
Buf *name = &node->data.field_access_expr.field_name;
|
||||
|
||||
// TODO add struct support
|
||||
(void)struct_ptr;
|
||||
|
||||
if (struct_type->id == TypeTableEntryIdArray) {
|
||||
if (buf_eql_str(name, "len")) {
|
||||
return LLVMConstInt(g->builtin_types.entry_usize->type_ref,
|
||||
@ -221,6 +249,12 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node) {
|
||||
} else {
|
||||
zig_panic("gen_field_access_expr bad array field");
|
||||
}
|
||||
} else if (struct_type->id == TypeTableEntryIdStruct) {
|
||||
/*
|
||||
LLVMValueRef ptr = gen_field_ptr(g, node);
|
||||
return LLVMBuildLoad(g->builder, ptr, "");
|
||||
*/
|
||||
return gen_field_val(g, node);
|
||||
} else {
|
||||
zig_panic("gen_field_access_expr bad struct type");
|
||||
}
|
||||
@ -259,30 +293,36 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
|
||||
TypeTableEntry *actual_type = get_expr_type(node->data.cast_expr.expr);
|
||||
TypeTableEntry *wanted_type = get_expr_type(node);
|
||||
|
||||
// this asserts are here only because no other casting codegen is supported currently
|
||||
assert(wanted_type == g->builtin_types.entry_isize);
|
||||
CastNode *cast_node = &node->codegen_node->data.cast_node;
|
||||
|
||||
if (wanted_type->id == TypeTableEntryIdPointer) {
|
||||
return LLVMBuildIntToPtr(g->builder, expr_val, wanted_type->type_ref, "");
|
||||
} else if (wanted_type->id == TypeTableEntryIdInt) {
|
||||
if (actual_type->size_in_bits == wanted_type->size_in_bits) {
|
||||
if (actual_type->id == TypeTableEntryIdPointer) {
|
||||
return LLVMBuildPtrToInt(g->builder, expr_val, wanted_type->type_ref, "");
|
||||
switch (cast_node->op) {
|
||||
case CastOpPtrToInt:
|
||||
return LLVMBuildPtrToInt(g->builder, expr_val, wanted_type->type_ref, "");
|
||||
case CastOpIntWidenOrShorten:
|
||||
if (actual_type->size_in_bits == wanted_type->size_in_bits) {
|
||||
return expr_val;
|
||||
} else if (actual_type->size_in_bits < wanted_type->size_in_bits) {
|
||||
if (actual_type->data.integral.is_signed && wanted_type->data.integral.is_signed) {
|
||||
return LLVMBuildSExt(g->builder, expr_val, wanted_type->type_ref, "");
|
||||
} else {
|
||||
zig_panic("TODO gen_cast_expr sign mismatch");
|
||||
}
|
||||
} else {
|
||||
zig_panic("TODO gen_cast_expr");
|
||||
}
|
||||
} else if (actual_type->size_in_bits < wanted_type->size_in_bits) {
|
||||
if (actual_type->data.integral.is_signed && wanted_type->data.integral.is_signed) {
|
||||
return LLVMBuildSExt(g->builder, expr_val, wanted_type->type_ref, "");
|
||||
} else {
|
||||
zig_panic("TODO gen_cast_expr sign mismatch");
|
||||
case CastOpArrayToString:
|
||||
{
|
||||
LLVMValueRef struct_vals[] = {
|
||||
expr_val,
|
||||
LLVMConstInt(g->builtin_types.entry_usize->type_ref, actual_type->data.array.len, false)
|
||||
};
|
||||
unsigned field_count = g->builtin_types.entry_string->data.structure.field_count;
|
||||
assert(field_count == 2);
|
||||
return LLVMConstNamedStruct(g->builtin_types.entry_string->type_ref,
|
||||
struct_vals, field_count);
|
||||
}
|
||||
} else {
|
||||
zig_panic("TODO gen_cast_expr");
|
||||
}
|
||||
} else {
|
||||
zig_panic("TODO gen_cast_expr");
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {
|
||||
|
||||
@ -14,14 +14,11 @@ fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {
|
||||
}
|
||||
|
||||
// TODO error handling
|
||||
// TODO zig strings instead of C strings
|
||||
// TODO handle buffering and flushing
|
||||
// TODO non-i32 integer literals so we can remove the casts
|
||||
// TODO constants for SYS_write and stdout_fileno
|
||||
//pub fn print_str(str : string) -> isize {
|
||||
pub fn print_str(str : *const u8, len: isize) -> isize {
|
||||
pub fn print_str(str : string) -> isize {
|
||||
let SYS_write = 1;
|
||||
let stdout_fileno = 1;
|
||||
//return syscall3(SYS_write as isize, stdout_fileno as isize, str.ptr as isize, str.len as isize);
|
||||
return syscall3(SYS_write as isize, stdout_fileno as isize, str as isize, len);
|
||||
return syscall3(SYS_write as isize, stdout_fileno as isize, str.ptr as isize, str.len as isize);
|
||||
}
|
||||
|
||||
@ -403,7 +403,7 @@ loop_2_end:
|
||||
use "std.zig";
|
||||
|
||||
export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 {
|
||||
print_str(c"Hello, world!\n", 14 as isize);
|
||||
print_str("Hello, world!\n" as string);
|
||||
return 0;
|
||||
}
|
||||
)SOURCE", "Hello, world!\n");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user