prepare codebase for struct and string support

parsing code for structs, strings, and c string literals
partial semantic analyzing code for structs, strings, and c string literals
This commit is contained in:
Andrew Kelley 2015-12-12 00:10:37 -07:00
parent 4c16eaa640
commit a10277bd94
15 changed files with 599 additions and 107 deletions

View File

@ -32,7 +32,11 @@ zig | C equivalent | Description
```
Root : many(TopLevelDecl) token(EOF)
TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use
TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | StructDecl
StructDecl : many(Directive) token(Struct) token(Symbol) token(LBrace) many(StructField) token(RBrace)
StructField : token(Symbol) token(Colon) Type token(Comma)
Use : many(Directive) token(Use) token(String) token(Semicolon)
@ -126,7 +130,9 @@ CastExpression : PrefixOpExpression token(as) Type | PrefixOpExpression
PrefixOpExpression : PrefixOp SuffixOpExpression | SuffixOpExpression
SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression)
SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression)
FieldAccessExpression : token(Dot) token(Symbol)
FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
@ -146,7 +152,7 @@ KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False)
## Operator Precedence
```
x() x[]
x() x[] x.y
!x -x ~x
as
* / %
@ -165,11 +171,11 @@ as
### Characters and Strings
| Example | Characters | Escapes | Null Terminated
-------------------------------------------------------------------------------
Byte | 'H' | All ASCII | Byte | No
UTF-8 Bytes | "hello" | All Unicode | Byte & Unicode | No
UTF-8 C string | c"hello" | All Unicode | Byte & Unicode | Yes
| Example | Characters | Escapes | Null Term | Type
---------------------------------------------------------------------------------
Byte | 'H' | All ASCII | Byte | No | u8
UTF-8 Bytes | "hello" | All Unicode | Byte & Unicode | No | [5; u8]
UTF-8 C string | c"hello" | All Unicode | Byte & Unicode | Yes | *const u8
### Byte Escapes

View File

@ -9,7 +9,7 @@ endif
syn keyword zigKeyword fn return mut const extern unreachable export pub as use while asm
syn keyword zigKeyword if else let void goto type enum struct continue break match volatile
syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128
syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 string
syn keyword zigConstant null

View File

@ -3,6 +3,6 @@ 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", 14 as isize);
print_str("Hello, world!\n");
return 0;
}

View File

@ -0,0 +1,27 @@
export executable "structs";
use "std.zig";
export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 {
let mut foo : Foo;
foo.a = foo.a + 1;
foo.b = foo.a == 1;
test_foo(foo);
return 0;
}
struct Foo {
a : i32,
b : bool,
c : f32,
}
fn test_foo(foo : Foo) {
if foo.b {
print_str("OK");
}
}

View File

@ -13,6 +13,11 @@
static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node);
static void alloc_codegen_node(AstNode *node) {
assert(!node->codegen_node);
node->codegen_node = allocate<CodeGenNode>(1);
}
static AstNode *first_executing_node(AstNode *node) {
switch (node->type) {
case NodeTypeFnCallExpr:
@ -44,6 +49,9 @@ static AstNode *first_executing_node(AstNode *node) {
case NodeTypeLabel:
case NodeTypeGoto:
case NodeTypeAsmExpr:
case NodeTypeFieldAccessExpr:
case NodeTypeStructDecl:
case NodeTypeStructField:
return node;
}
zig_panic("unreachable");
@ -129,6 +137,7 @@ static TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, in
entry->di_type = LLVMZigCreateDebugArrayType(g->dbuilder, entry->size_in_bits,
entry->align_in_bits, child_type->di_type, array_size);
entry->data.array.child_type = child_type;
entry->data.array.len = array_size;
g->type_table.put(&entry->name, entry);
child_type->arrays_by_size.put(array_size, entry);
@ -143,8 +152,7 @@ static int parse_int(Buf *number) {
static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeType);
assert(!node->codegen_node);
node->codegen_node = allocate<CodeGenNode>(1);
alloc_codegen_node(node);
TypeNode *type_node = &node->codegen_node->data.type_node;
switch (node->data.type.type) {
case AstNodeTypeTypePrimitive:
@ -259,8 +267,7 @@ static void preview_function_labels(CodeGen *g, AstNode *node, FnTableEntry *fn_
Buf *name = &label_node->data.label.name;
fn_table_entry->label_table.put(name, label_entry);
assert(!label_node->codegen_node);
label_node->codegen_node = allocate<CodeGenNode>(1);
alloc_codegen_node(label_node);
label_node->codegen_node->data.label_entry = label_entry;
}
}
@ -302,8 +309,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
g->fn_table.put(name, fn_table_entry);
}
assert(!fn_proto->codegen_node);
fn_proto->codegen_node = allocate<CodeGenNode>(1);
alloc_codegen_node(fn_proto);
fn_proto->codegen_node->data.fn_proto_node.fn_table_entry = fn_table_entry;
}
break;
@ -319,8 +325,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
if (entry) {
add_node_error(g, node,
buf_sprintf("redefinition of '%s'", buf_ptr(proto_name)));
assert(!node->codegen_node);
node->codegen_node = allocate<CodeGenNode>(1);
alloc_codegen_node(node);
node->codegen_node->data.fn_def_node.skip = true;
skip = true;
} else if (is_pub) {
@ -328,8 +333,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
if (entry) {
add_node_error(g, node,
buf_sprintf("redefinition of '%s'", buf_ptr(proto_name)));
assert(!node->codegen_node);
node->codegen_node = allocate<CodeGenNode>(1);
alloc_codegen_node(node);
node->codegen_node->data.fn_def_node.skip = true;
skip = true;
}
@ -358,8 +362,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
resolve_function_proto(g, proto_node, fn_table_entry);
assert(!proto_node->codegen_node);
proto_node->codegen_node = allocate<CodeGenNode>(1);
alloc_codegen_node(proto_node);
proto_node->codegen_node->data.fn_proto_node.fn_table_entry = fn_table_entry;
preview_function_labels(g, node->data.fn_def.body, fn_table_entry);
@ -409,6 +412,31 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
buf_sprintf("root export declaration only valid in root source file"));
}
break;
case NodeTypeStructDecl:
{
StructDeclNode *struct_codegen = &node->codegen_node->data.struct_decl_node;
TypeTableEntry *type_entry = struct_codegen->type_entry;
int field_count = node->data.struct_decl.fields.length;;
type_entry->data.structure.field_count = field_count;
type_entry->data.structure.fields = allocate<TypeStructField>(field_count);
LLVMTypeRef *element_types = allocate<LLVMTypeRef>(field_count);
for (int i = 0; i < field_count; i += 1) {
AstNode *field_node = node->data.struct_decl.fields.at(i);
TypeStructField *type_struct_field = &type_entry->data.structure.fields[i];
type_struct_field->name = &field_node->data.struct_field.name;
type_struct_field->type_entry = resolve_type(g, field_node->data.struct_field.type);
element_types[i] = type_struct_field->type_entry->type_ref;
}
// TODO align_in_bits and size_in_bits
// TODO set up ditype for the struct
LLVMStructSetBody(type_entry->type_ref, element_types, field_count, false);
break;
}
case NodeTypeUse:
// nothing to do here
break;
@ -436,6 +464,68 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
case NodeTypeLabel:
case NodeTypeGoto:
case NodeTypeAsmExpr:
case NodeTypeFieldAccessExpr:
case NodeTypeStructField:
zig_unreachable();
}
}
static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) {
switch (node->type) {
case NodeTypeStructDecl:
{
alloc_codegen_node(node);
StructDeclNode *struct_codegen = &node->codegen_node->data.struct_decl_node;
Buf *name = &node->data.struct_decl.name;
auto table_entry = g->type_table.maybe_get(name);
if (table_entry) {
struct_codegen->type_entry = table_entry->value;
add_node_error(g, node,
buf_sprintf("redefinition of '%s'", buf_ptr(name)));
} else {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct);
entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(name));
buf_init_from_buf(&entry->name, name);
// put off adding the debug type until we do the full struct body
// this type is incomplete until we do another pass
g->type_table.put(&entry->name, entry);
struct_codegen->type_entry = entry;
}
break;
}
case NodeTypeExternBlock:
case NodeTypeFnDef:
case NodeTypeRootExportDecl:
case NodeTypeUse:
// nothing to do
break;
case NodeTypeDirective:
case NodeTypeParamDecl:
case NodeTypeFnProto:
case NodeTypeType:
case NodeTypeFnDecl:
case NodeTypeReturnExpr:
case NodeTypeVariableDeclaration:
case NodeTypeRoot:
case NodeTypeBlock:
case NodeTypeBinOpExpr:
case NodeTypeFnCallExpr:
case NodeTypeArrayAccessExpr:
case NodeTypeNumberLiteral:
case NodeTypeStringLiteral:
case NodeTypeUnreachable:
case NodeTypeVoid:
case NodeTypeBoolLiteral:
case NodeTypeSymbol:
case NodeTypeCastExpr:
case NodeTypePrefixOpExpr:
case NodeTypeIfExpr:
case NodeTypeLabel:
case NodeTypeGoto:
case NodeTypeAsmExpr:
case NodeTypeFieldAccessExpr:
case NodeTypeStructField:
zig_unreachable();
}
}
@ -460,7 +550,9 @@ static FnTableEntry *get_context_fn_entry(BlockContext *context) {
return fn_proto_node->codegen_node->data.fn_proto_node.fn_table_entry;
}
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)
@ -471,7 +563,7 @@ static void check_type_compatibility(CodeGen *g, AstNode *node, TypeTableEntry *
return; // sorry toots; gotta run. good luck with that expected type.
add_node_error(g, node,
buf_sprintf("type mismatch. expected %s. got %s",
buf_sprintf("expected type '%s', got '%s'",
buf_ptr(&expected_type->name),
buf_ptr(&actual_type->name)));
}
@ -507,6 +599,55 @@ LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name) {
}
}
static TypeStructField *get_struct_field(TypeTableEntry *struct_type, Buf *name) {
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;
}
}
return nullptr;
}
static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
AstNode *node)
{
TypeTableEntry *struct_type = analyze_expression(g, import, context, nullptr,
node->data.field_access_expr.struct_expr);
TypeTableEntry *return_type;
if (struct_type->id == TypeTableEntryIdStruct) {
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;
} else {
add_node_error(g, node,
buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&struct_type->name)));
return_type = g->builtin_types.entry_invalid;
}
} else if (struct_type->id == TypeTableEntryIdArray) {
Buf *name = &node->data.field_access_expr.field_name;
if (buf_eql_str(name, "len")) {
return_type = g->builtin_types.entry_usize;
} else {
add_node_error(g, node,
buf_sprintf("no member named '%s' in '%s'", buf_ptr(name),
buf_ptr(&struct_type->name)));
return_type = g->builtin_types.entry_invalid;
}
} else {
if (struct_type->id != TypeTableEntryIdInvalid) {
add_node_error(g, node,
buf_sprintf("type '%s' does not support field access", buf_ptr(&struct_type->name)));
}
return_type = g->builtin_types.entry_invalid;
}
return return_type;
}
static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
AstNode *node)
{
@ -554,8 +695,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
TypeTableEntry *expected_type, AstNode *node)
{
TypeTableEntry *return_type = nullptr;
assert(!node->codegen_node);
node->codegen_node = allocate<CodeGenNode>(1);
alloc_codegen_node(node);
switch (node->type) {
case NodeTypeBlock:
{
@ -698,9 +838,11 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
}
} else if (lhs_node->type == NodeTypeArrayAccessExpr) {
expected_rhs_type = analyze_array_access_expr(g, import, context, lhs_node);
} else if (lhs_node->type == NodeTypeFieldAccessExpr) {
expected_rhs_type = analyze_field_access_expr(g, import, context, lhs_node);
} else {
add_node_error(g, lhs_node,
buf_sprintf("expected a bare identifier"));
buf_sprintf("assignment target must be variable, field, or array element"));
}
analyze_expression(g, import, context, expected_rhs_type, node->data.bin_op_expr.op2);
return_type = g->builtin_types.entry_void;
@ -835,15 +977,21 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
// for reading array access; assignment handled elsewhere
return_type = analyze_array_access_expr(g, import, context, node);
break;
case NodeTypeFieldAccessExpr:
return_type = analyze_field_access_expr(g, import, context, node);
break;
case NodeTypeNumberLiteral:
// TODO: generic literal int type
return_type = g->builtin_types.entry_i32;
break;
case NodeTypeStringLiteral:
return_type = g->builtin_types.entry_string_literal;
if (node->data.string_literal.c) {
return_type = g->builtin_types.entry_c_string_literal;
} else {
return_type = get_array_type(g, g->builtin_types.entry_u8, buf_len(&node->data.string_literal.buf));
}
break;
case NodeTypeUnreachable:
return_type = g->builtin_types.entry_unreachable;
break;
@ -884,7 +1032,10 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
{
return_type = wanted_type;
} else {
zig_panic("TODO analyze_expression cast expr");
add_node_error(g, node,
buf_sprintf("TODO handle cast from '%s' to '%s'",
buf_ptr(&actual_type->name), buf_ptr(&wanted_type->name)));
return_type = g->builtin_types.entry_invalid;
}
break;
}
@ -946,6 +1097,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
case NodeTypeFnDef:
case NodeTypeUse:
case NodeTypeLabel:
case NodeTypeStructDecl:
case NodeTypeStructField:
zig_unreachable();
}
assert(return_type);
@ -970,8 +1123,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
AstNode *fn_proto_node = node->data.fn_def.fn_proto;
assert(fn_proto_node->type == NodeTypeFnProto);
assert(!node->codegen_node);
node->codegen_node = allocate<CodeGenNode>(1);
alloc_codegen_node(node);
BlockContext *context = new_block_context(node, nullptr);
node->codegen_node->data.fn_def_node.block_context = context;
@ -1044,6 +1196,9 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
}
break;
case NodeTypeStructDecl:
// nothing to do
break;
case NodeTypeDirective:
case NodeTypeParamDecl:
case NodeTypeFnProto:
@ -1068,6 +1223,8 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
case NodeTypeLabel:
case NodeTypeGoto:
case NodeTypeAsmExpr:
case NodeTypeFieldAccessExpr:
case NodeTypeStructField:
zig_unreachable();
}
}
@ -1082,6 +1239,16 @@ static void find_function_declarations_root(CodeGen *g, ImportTableEntry *import
}
static void preview_types_root(CodeGen *g, ImportTableEntry *import, AstNode *node) {
assert(node->type == NodeTypeRoot);
for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {
AstNode *child = node->data.root.top_level_decls.at(i);
preview_types(g, import, child);
}
}
static void analyze_top_level_decls_root(CodeGen *g, ImportTableEntry *import, AstNode *node) {
assert(node->type == NodeTypeRoot);
@ -1092,6 +1259,17 @@ static void analyze_top_level_decls_root(CodeGen *g, ImportTableEntry *import, A
}
void semantic_analyze(CodeGen *g) {
{
auto it = g->import_table.entry_iterator();
for (;;) {
auto *entry = it.next();
if (!entry)
break;
ImportTableEntry *import = entry->value;
preview_types_root(g, import, import->root);
}
}
{
auto it = g->import_table.entry_iterator();
for (;;) {

View File

@ -28,6 +28,18 @@ struct TypeTableEntryInt {
struct TypeTableEntryArray {
TypeTableEntry *child_type;
uint64_t len;
};
struct TypeStructField {
Buf *name;
TypeTableEntry *type_entry;
};
struct TypeTableEntryStruct {
bool is_packed;
int field_count;
TypeStructField *fields;
};
enum TypeTableEntryId {
@ -39,6 +51,7 @@ enum TypeTableEntryId {
TypeTableEntryIdFloat,
TypeTableEntryIdPointer,
TypeTableEntryIdArray,
TypeTableEntryIdStruct,
};
struct TypeTableEntry {
@ -55,6 +68,7 @@ struct TypeTableEntry {
TypeTableEntryPointer pointer;
TypeTableEntryInt integral;
TypeTableEntryArray array;
TypeTableEntryStruct structure;
} data;
// use these fields to make sure we don't duplicate type table entries for the same type
@ -122,8 +136,10 @@ struct CodeGen {
TypeTableEntry *entry_u8;
TypeTableEntry *entry_i32;
TypeTableEntry *entry_isize;
TypeTableEntry *entry_usize;
TypeTableEntry *entry_f32;
TypeTableEntry *entry_string_literal;
TypeTableEntry *entry_c_string_literal;
TypeTableEntry *entry_string;
TypeTableEntry *entry_void;
TypeTableEntry *entry_unreachable;
TypeTableEntry *entry_invalid;
@ -211,6 +227,10 @@ struct BlockNode {
BlockContext *block_context;
};
struct StructDeclNode {
TypeTableEntry *type_entry;
};
struct CodeGenNode {
union {
TypeNode type_node; // for NodeTypeType
@ -219,6 +239,7 @@ struct CodeGenNode {
LabelTableEntry *label_entry; // for NodeTypeGoto and NodeTypeLabel
AssignNode assign_node; // for NodeTypeBinOpExpr where op is BinOpTypeAssign
BlockNode block_node; // for NodeTypeBlock
StructDeclNode struct_decl_node; // for NodeTypeStructDecl
} data;
ExprNode expr_node; // for all the expression nodes
};

View File

@ -106,12 +106,12 @@ static void add_debug_source_node(CodeGen *g, AstNode *node) {
g->cur_block_context->di_scope);
}
static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str) {
static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str, bool c) {
auto entry = g->str_table.maybe_get(str);
if (entry) {
return entry->value;
}
LLVMValueRef text = LLVMConstString(buf_ptr(str), buf_len(str), false);
LLVMValueRef text = LLVMConstString(buf_ptr(str), buf_len(str), !c);
LLVMValueRef global_value = LLVMAddGlobal(g->module, LLVMTypeOf(text), "");
LLVMSetLinkage(global_value, LLVMPrivateLinkage);
LLVMSetInitializer(global_value, text);
@ -204,6 +204,28 @@ static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node) {
return LLVMBuildLoad(g->builder, ptr, "");
}
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,
struct_type->data.array.len, false);
} else {
zig_panic("gen_field_access_expr bad array field");
}
} else {
zig_panic("gen_field_access_expr bad struct type");
}
}
static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypePrefixOpExpr);
assert(node->data.prefix_op_expr.primary_expr);
@ -785,6 +807,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
return gen_fn_call_expr(g, node);
case NodeTypeArrayAccessExpr:
return gen_array_access_expr(g, node);
case NodeTypeFieldAccessExpr:
return gen_field_access_expr(g, node);
case NodeTypeUnreachable:
add_debug_source_node(g, node);
return LLVMBuildUnreachable(g->builder);
@ -809,8 +833,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
}
case NodeTypeStringLiteral:
{
Buf *str = &node->data.string;
LLVMValueRef str_val = find_or_create_string(g, str);
Buf *str = &node->data.string_literal.buf;
LLVMValueRef str_val = find_or_create_string(g, str, node->data.string_literal.c);
LLVMValueRef indices[] = {
LLVMConstInt(LLVMInt32Type(), 0, false),
LLVMConstInt(LLVMInt32Type(), 0, false)
@ -864,6 +888,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
case NodeTypeExternBlock:
case NodeTypeDirective:
case NodeTypeUse:
case NodeTypeStructDecl:
case NodeTypeStructField:
zig_unreachable();
}
zig_unreachable();
@ -1072,7 +1098,7 @@ static void do_code_gen(CodeGen *g) {
#endif
}
static void define_primitive_types(CodeGen *g) {
static void define_builtin_types(CodeGen *g) {
{
// if this type is anywhere in the AST, we should never hit codegen.
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInvalid);
@ -1103,7 +1129,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);
g->builtin_types.entry_c_string_literal = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
entry->type_ref = LLVMInt32Type();
@ -1130,6 +1156,19 @@ static void define_primitive_types(CodeGen *g) {
g->type_table.put(&entry->name, entry);
g->builtin_types.entry_isize = entry;
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
entry->type_ref = LLVMIntType(g->pointer_size_bytes * 8);
buf_init_from_str(&entry->name, "usize");
entry->size_in_bits = g->pointer_size_bytes * 8;
entry->align_in_bits = g->pointer_size_bytes * 8;
entry->data.integral.is_signed = false;
entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
entry->size_in_bits, entry->align_in_bits,
LLVMZigEncoding_DW_ATE_unsigned());
g->type_table.put(&entry->name, entry);
g->builtin_types.entry_usize = entry;
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
entry->type_ref = LLVMFloatType();
@ -1160,6 +1199,43 @@ static void define_primitive_types(CodeGen *g) {
g->type_table.put(&entry->name, entry);
g->builtin_types.entry_unreachable = entry;
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct);
TypeTableEntry *const_pointer_to_u8 = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
unsigned element_count = 2;
LLVMTypeRef element_types[] = {
const_pointer_to_u8->type_ref,
g->builtin_types.entry_usize->type_ref
};
entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), "string");
LLVMStructSetBody(entry->type_ref, element_types, element_count, false);
buf_init_from_str(&entry->name, "string");
entry->size_in_bits = g->pointer_size_bytes * 2 * 8;
entry->align_in_bits = g->pointer_size_bytes;
entry->data.structure.is_packed = false;
entry->data.structure.field_count = element_count;
entry->data.structure.fields = allocate<TypeStructField>(element_count);
entry->data.structure.fields[0].name = buf_create_from_str("ptr");
entry->data.structure.fields[0].type_entry = const_pointer_to_u8;
entry->data.structure.fields[1].name = buf_create_from_str("len");
entry->data.structure.fields[1].type_entry = g->builtin_types.entry_usize;
LLVMZigDIType *di_element_types[] = {
const_pointer_to_u8->di_type,
g->builtin_types.entry_usize->di_type
};
LLVMZigDIScope *compile_unit_scope = LLVMZigCompileUnitToScope(g->compile_unit);
LLVMZigDIFile *difile = nullptr; // TODO make sure this ok
entry->di_type = LLVMZigCreateDebugStructType(g->dbuilder, compile_unit_scope,
"string", difile, 0, entry->size_in_bits, entry->align_in_bits, 0,
nullptr, di_element_types, element_count, 0, nullptr, "");
g->type_table.put(&entry->name, entry);
g->builtin_types.entry_string = entry;
}
}
@ -1213,8 +1289,6 @@ static void init(CodeGen *g, Buf *source_path) {
LLVMZigSetFastMath(g->builder, true);
define_primitive_types(g);
Buf *producer = buf_sprintf("zig %s", ZIG_VERSION_STRING);
bool is_optimized = g->build_type == CodeGenBuildTypeRelease;
const char *flags = "";
@ -1224,6 +1298,7 @@ static void init(CodeGen *g, Buf *source_path) {
buf_ptr(producer), is_optimized, flags, runtime_version,
"", 0, !g->strip_debug_symbols);
define_builtin_types(g);
}

View File

@ -106,6 +106,12 @@ const char *node_type_str(NodeType node_type) {
return "Label";
case NodeTypeAsmExpr:
return "AsmExpr";
case NodeTypeFieldAccessExpr:
return "FieldAccessExpr";
case NodeTypeStructDecl:
return "StructDecl";
case NodeTypeStructField:
return "StructField";
}
zig_unreachable();
}
@ -259,9 +265,12 @@ void ast_print(AstNode *node, int indent) {
buf_ptr(&node->data.number));
break;
case NodeTypeStringLiteral:
fprintf(stderr, "StringLiteral '%s'\n",
buf_ptr(&node->data.string));
break;
{
const char *c = node->data.string_literal.c ? "c" : "";
fprintf(stderr, "StringLiteral %s'%s'\n", c,
buf_ptr(&node->data.string_literal.buf));
break;
}
case NodeTypeUnreachable:
fprintf(stderr, "Unreachable\n");
break;
@ -295,6 +304,19 @@ void ast_print(AstNode *node, int indent) {
case NodeTypeAsmExpr:
fprintf(stderr, "%s\n", node_type_str(node->type));
break;
case NodeTypeFieldAccessExpr:
fprintf(stderr, "%s '%s'\n", node_type_str(node->type),
buf_ptr(&node->data.field_access_expr.field_name));
ast_print(node->data.field_access_expr.struct_expr, indent + 2);
break;
case NodeTypeStructDecl:
fprintf(stderr, "%s '%s'\n",
node_type_str(node->type), buf_ptr(&node->data.struct_decl.name));
break;
case NodeTypeStructField:
fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.struct_field.name));
ast_print(node->data.struct_field.type, indent + 2);
break;
}
}
@ -475,18 +497,28 @@ static void parse_asm_template(ParseContext *pc, AstNode *node) {
}
}
static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, ZigList<SrcPos> *offset_map) {
static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, bool *out_c_str,
ZigList<SrcPos> *offset_map)
{
// skip the double quotes at beginning and end
// convert escape sequences
// detect c string literal
buf_resize(buf, 0);
bool escape = false;
bool first = true;
bool skip_quote;
SrcPos pos = {token->start_line, token->start_column};
for (int i = token->start_pos; i < token->end_pos - 1; i += 1) {
uint8_t c = *((uint8_t*)buf_ptr(pc->buf) + i);
if (first) {
first = false;
if (i == token->start_pos) {
skip_quote = (c == 'c');
if (out_c_str) {
*out_c_str = skip_quote;
} else if (skip_quote) {
ast_error(pc, token, "C string literal not allowed here");
}
} else if (skip_quote) {
skip_quote = false;
} else {
if (escape) {
switch (c) {
@ -541,13 +573,20 @@ static AstNode *ast_parse_expression(ParseContext *pc, int *token_index, bool ma
static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandatory);
static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool mandatory);
static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) {
if (token->id != token_id) {
ast_invalid_token_error(pc, token);
}
}
static Token *ast_eat_token(ParseContext *pc, int *token_index, TokenId token_id) {
Token *token = &pc->tokens->at(*token_index);
ast_expect_token(pc, token, token_id);
*token_index += 1;
return token;
}
static AstNode *ast_parse_directive(ParseContext *pc, int token_index, int *new_token_index) {
Token *number_sign = &pc->tokens->at(token_index);
token_index += 1;
@ -569,7 +608,7 @@ static AstNode *ast_parse_directive(ParseContext *pc, int token_index, int *new_
token_index += 1;
ast_expect_token(pc, param_str, TokenIdStringLiteral);
parse_string_literal(pc, param_str, &node->data.directive.param, nullptr);
parse_string_literal(pc, param_str, &node->data.directive.param, nullptr, nullptr);
Token *r_paren = &pc->tokens->at(token_index);
token_index += 1;
@ -782,7 +821,7 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
return node;
} else if (token->id == TokenIdStringLiteral) {
AstNode *node = ast_create_node(pc, NodeTypeStringLiteral, token);
parse_string_literal(pc, token, &node->data.string, nullptr);
parse_string_literal(pc, token, &node->data.string_literal.buf, &node->data.string_literal.c, nullptr);
*token_index += 1;
return node;
} else if (token->id == TokenIdKeywordUnreachable) {
@ -832,9 +871,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
}
/*
SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression)
SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression)
FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
ArrayAccessExpression : token(LBracket) Expression token(RBracket)
FieldAccessExpression : token(Dot) token(Symbol)
*/
static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, bool mandatory) {
AstNode *primary_expr = ast_parse_primary_expr(pc, token_index, mandatory);
@ -861,6 +901,16 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, boo
*token_index += 1;
ast_expect_token(pc, r_bracket, TokenIdRBracket);
return node;
} else if (token->id == TokenIdDot) {
*token_index += 1;
Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol);
AstNode *node = ast_create_node(pc, NodeTypeFieldAccessExpr, token);
node->data.field_access_expr.struct_expr = primary_expr;
ast_buf_from_token(pc, name_token, &node->data.field_access_expr.field_name);
return node;
} else {
return primary_expr;
@ -1397,14 +1447,6 @@ static AstNode *ast_parse_ass_expr(ParseContext *pc, int *token_index, bool mand
return node;
}
static Token *ast_eat_token(ParseContext *pc, int *token_index, TokenId token_id) {
Token *token = &pc->tokens->at(*token_index);
ast_expect_token(pc, token, token_id);
*token_index += 1;
return token;
}
/*
AsmInputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) Expression token(RParen)
*/
@ -1421,7 +1463,7 @@ static void ast_parse_asm_input_item(ParseContext *pc, int *token_index, AstNode
AsmInput *asm_input = allocate<AsmInput>(1);
ast_buf_from_token(pc, alias, &asm_input->asm_symbolic_name);
parse_string_literal(pc, constraint, &asm_input->constraint, nullptr);
parse_string_literal(pc, constraint, &asm_input->constraint, nullptr, nullptr);
asm_input->expr = expr_node;
node->data.asm_expr.input_list.append(asm_input);
}
@ -1442,7 +1484,7 @@ static void ast_parse_asm_output_item(ParseContext *pc, int *token_index, AstNod
AsmOutput *asm_output = allocate<AsmOutput>(1);
ast_buf_from_token(pc, alias, &asm_output->asm_symbolic_name);
parse_string_literal(pc, constraint, &asm_output->constraint, nullptr);
parse_string_literal(pc, constraint, &asm_output->constraint, nullptr, nullptr);
ast_buf_from_token(pc, out_symbol, &asm_output->variable_name);
node->data.asm_expr.output_list.append(asm_output);
}
@ -1464,7 +1506,7 @@ static void ast_parse_asm_clobbers(ParseContext *pc, int *token_index, AstNode *
*token_index += 1;
Buf *clobber_buf = buf_alloc();
parse_string_literal(pc, string_tok, clobber_buf, nullptr);
parse_string_literal(pc, string_tok, clobber_buf, nullptr, nullptr);
node->data.asm_expr.clobber_list.append(clobber_buf);
Token *comma = &pc->tokens->at(*token_index);
@ -1565,7 +1607,7 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mand
ast_expect_token(pc, template_tok, TokenIdStringLiteral);
*token_index += 1;
parse_string_literal(pc, template_tok, &node->data.asm_expr.asm_template,
parse_string_literal(pc, template_tok, &node->data.asm_expr.asm_template, nullptr,
&node->data.asm_expr.offset_map);
parse_asm_template(pc, node);
@ -1877,7 +1919,7 @@ static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index, b
*token_index += 1;
ast_expect_token(pc, export_name, TokenIdStringLiteral);
parse_string_literal(pc, export_name, &node->data.root_export_decl.name, nullptr);
parse_string_literal(pc, export_name, &node->data.root_export_decl.name, nullptr, nullptr);
Token *semicolon = &pc->tokens->at(*token_index);
*token_index += 1;
@ -1889,9 +1931,7 @@ static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index, b
/*
Use : many(Directive) token(Use) token(String) token(Semicolon)
*/
static AstNode *ast_parse_use(ParseContext *pc, int *token_index, bool mandatory) {
assert(mandatory == false);
static AstNode *ast_parse_use(ParseContext *pc, int *token_index) {
Token *use_kw = &pc->tokens->at(*token_index);
if (use_kw->id != TokenIdKeywordUse)
return nullptr;
@ -1907,7 +1947,7 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index, bool mandatory
AstNode *node = ast_create_node(pc, NodeTypeUse, use_kw);
parse_string_literal(pc, use_name, &node->data.use.path, nullptr);
parse_string_literal(pc, use_name, &node->data.use.path, nullptr, nullptr);
node->data.use.directives = pc->directive_list;
pc->directive_list = nullptr;
@ -1916,7 +1956,57 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index, bool mandatory
}
/*
TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use
StructDecl : many(Directive) token(Struct) token(Symbol) token(LBrace) many(StructField) token(RBrace)
StructField : token(Symbol) token(Colon) Type token(Comma)
*/
static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) {
Token *struct_kw = &pc->tokens->at(*token_index);
if (struct_kw->id != TokenIdKeywordStruct)
return nullptr;
*token_index += 1;
Token *struct_name = &pc->tokens->at(*token_index);
*token_index += 1;
ast_expect_token(pc, struct_name, TokenIdSymbol);
AstNode *node = ast_create_node(pc, NodeTypeStructDecl, struct_kw);
ast_buf_from_token(pc, struct_name, &node->data.struct_decl.name);
ast_eat_token(pc, token_index, TokenIdLBrace);
for (;;) {
Token *token = &pc->tokens->at(*token_index);
if (token->id == TokenIdRBrace) {
*token_index += 1;
break;
} else if (token->id == TokenIdSymbol) {
AstNode *field_node = ast_create_node(pc, NodeTypeStructField, token);
*token_index += 1;
ast_buf_from_token(pc, token, &field_node->data.struct_field.name);
ast_eat_token(pc, token_index, TokenIdColon);
field_node->data.struct_field.type = ast_parse_type(pc, *token_index, token_index);
ast_eat_token(pc, token_index, TokenIdComma);
node->data.struct_decl.fields.append(field_node);
} else {
ast_invalid_token_error(pc, token);
}
}
node->data.struct_decl.directives = pc->directive_list;
pc->directive_list = nullptr;
return node;
}
/*
TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | StructDecl
*/
static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigList<AstNode *> *top_level_decls) {
for (;;) {
@ -1943,12 +2033,18 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis
continue;
}
AstNode *use_node = ast_parse_use(pc, token_index, false);
AstNode *use_node = ast_parse_use(pc, token_index);
if (use_node) {
top_level_decls->append(use_node);
continue;
}
AstNode *struct_node = ast_parse_struct_decl(pc, token_index);
if (struct_node) {
top_level_decls->append(struct_node);
continue;
}
if (pc->directive_list->length > 0) {
ast_error(pc, directive_token, "invalid directive");
}

View File

@ -40,6 +40,7 @@ enum NodeType {
NodeTypePrefixOpExpr,
NodeTypeFnCallExpr,
NodeTypeArrayAccessExpr,
NodeTypeFieldAccessExpr,
NodeTypeUse,
NodeTypeVoid,
NodeTypeBoolLiteral,
@ -47,6 +48,8 @@ enum NodeType {
NodeTypeLabel,
NodeTypeGoto,
NodeTypeAsmExpr,
NodeTypeStructDecl,
NodeTypeStructField,
};
struct AstNodeRoot {
@ -152,6 +155,11 @@ struct AstNodeArrayAccessExpr {
AstNode *subscript;
};
struct AstNodeFieldAccessExpr {
AstNode *struct_expr;
Buf field_name;
};
struct AstNodeExternBlock {
ZigList<AstNode *> *directives;
ZigList<AstNode *> fn_decls;
@ -231,6 +239,22 @@ struct AstNodeAsmExpr {
ZigList<Buf*> clobber_list;
};
struct AstNodeStructDecl {
Buf name;
ZigList<AstNode *> fields;
ZigList<AstNode *> *directives;
};
struct AstNodeStructField {
Buf name;
AstNode *type;
};
struct AstNodeStringLiteral {
Buf buf;
bool c;
};
struct AstNode {
enum NodeType type;
int line;
@ -260,8 +284,11 @@ struct AstNode {
AstNodeLabel label;
AstNodeGoto go_to;
AstNodeAsmExpr asm_expr;
AstNodeFieldAccessExpr field_access_expr;
AstNodeStructDecl struct_decl;
AstNodeStructField struct_field;
AstNodeStringLiteral string_literal;
Buf number;
Buf string;
Buf symbol;
bool bool_literal;
} data;

View File

@ -28,10 +28,9 @@
case '8': \
case '9'
#define ALPHA \
#define ALPHA_EXCEPT_C \
'a': \
case 'b': \
case 'c': \
case 'd': \
case 'e': \
case 'f': \
@ -82,6 +81,10 @@
case 'Y': \
case 'Z'
#define ALPHA \
ALPHA_EXCEPT_C: \
case 'c'
#define SYMBOL_CHAR \
ALPHA: \
case DIGIT: \
@ -90,6 +93,7 @@
enum TokenizeState {
TokenizeStateStart,
TokenizeStateSymbol,
TokenizeStateSymbolFirst,
TokenizeStateNumber,
TokenizeStateString,
TokenizeStateSawDash,
@ -201,6 +205,8 @@ static void end_token(Tokenize *t) {
t->cur_tok->id = TokenIdKeywordVolatile;
} else if (mem_eql_str(token_mem, token_len, "asm")) {
t->cur_tok->id = TokenIdKeywordAsm;
} else if (mem_eql_str(token_mem, token_len, "struct")) {
t->cur_tok->id = TokenIdKeywordStruct;
}
t->cur_tok = nullptr;
@ -224,7 +230,11 @@ void tokenize(Buf *buf, Tokenization *out) {
switch (c) {
case WHITESPACE:
break;
case ALPHA:
case 'c':
t.state = TokenizeStateSymbolFirst;
begin_token(&t, TokenIdSymbol);
break;
case ALPHA_EXCEPT_C:
case '_':
t.state = TokenizeStateSymbol;
begin_token(&t, TokenIdSymbol);
@ -526,6 +536,22 @@ void tokenize(Buf *buf, Tokenization *out) {
break;
}
break;
case TokenizeStateSymbolFirst:
switch (c) {
case '"':
t.cur_tok->id = TokenIdStringLiteral;
t.state = TokenizeStateString;
break;
case SYMBOL_CHAR:
t.state = TokenizeStateSymbol;
break;
default:
t.pos -= 1;
end_token(&t);
t.state = TokenizeStateStart;
continue;
}
break;
case TokenizeStateSymbol:
switch (c) {
case SYMBOL_CHAR:
@ -589,6 +615,7 @@ void tokenize(Buf *buf, Tokenization *out) {
tokenize_error(&t, "unterminated string");
break;
case TokenizeStateSymbol:
case TokenizeStateSymbolFirst:
case TokenizeStateNumber:
case TokenizeStateSawDash:
case TokenizeStatePipe:
@ -643,6 +670,7 @@ static const char * token_name(Token *token) {
case TokenIdKeywordGoto: return "Goto";
case TokenIdKeywordVolatile: return "Volatile";
case TokenIdKeywordAsm: return "Asm";
case TokenIdKeywordStruct: return "Struct";
case TokenIdLParen: return "LParen";
case TokenIdRParen: return "RParen";
case TokenIdComma: return "Comma";

View File

@ -32,6 +32,7 @@ enum TokenId {
TokenIdKeywordGoto,
TokenIdKeywordAsm,
TokenIdKeywordVolatile,
TokenIdKeywordStruct,
TokenIdLParen,
TokenIdRParen,
TokenIdComma,

View File

@ -161,6 +161,31 @@ LLVMZigDIType *LLVMZigCreateDebugArrayType(LLVMZigDIBuilder *dibuilder, uint64_t
return reinterpret_cast<LLVMZigDIType*>(di_type);
}
LLVMZigDIType *LLVMZigCreateDebugStructType(LLVMZigDIBuilder *dibuilder, LLVMZigDIScope *scope,
const char *name, LLVMZigDIFile *file, unsigned line_number, uint64_t size_in_bits,
uint64_t align_in_bits, unsigned flags, LLVMZigDIType *derived_from,
LLVMZigDIType **types_array, int types_array_len, unsigned run_time_lang, LLVMZigDIType *vtable_holder,
const char *unique_id)
{
SmallVector<Metadata *, 8> fields;
for (int i = 0; i < types_array_len; i += 1) {
DIType *ditype = reinterpret_cast<DIType*>(types_array[i]);
fields.push_back(ditype);
}
DIType *di_type = reinterpret_cast<DIBuilder*>(dibuilder)->createStructType(
reinterpret_cast<DIScope*>(scope),
name,
reinterpret_cast<DIFile*>(file),
line_number, size_in_bits, align_in_bits, flags,
reinterpret_cast<DIType*>(derived_from),
reinterpret_cast<DIBuilder*>(dibuilder)->getOrCreateArray(fields),
run_time_lang,
reinterpret_cast<DIType*>(vtable_holder),
unique_id);
return reinterpret_cast<LLVMZigDIType*>(di_type);
}
LLVMZigDISubroutineType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder_wrapped,
LLVMZigDIFile *file, LLVMZigDIType **types_array, int types_array_len, unsigned flags)
{

View File

@ -49,6 +49,11 @@ LLVMZigDIType *LLVMZigCreateDebugArrayType(LLVMZigDIBuilder *dibuilder,
uint64_t size_in_bits, uint64_t align_in_bits, LLVMZigDIType *elem_type,
int elem_count);
LLVMZigDIType *LLVMZigCreateDebugStructType(LLVMZigDIBuilder *dibuilder, LLVMZigDIScope *scope,
const char *name, LLVMZigDIFile *file, unsigned line_number, uint64_t size_in_bits,
uint64_t align_in_bits, unsigned flags, LLVMZigDIType *derived_from,
LLVMZigDIType **types_array, int types_array_len, unsigned run_time_lang, LLVMZigDIType *vtable_holder,
const char *unique_id);
LLVMZigDISubroutineType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder_wrapped,
LLVMZigDIFile *file, LLVMZigDIType **types_array, int types_array_len, unsigned flags);

View File

@ -17,8 +17,11 @@ fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {
// TODO zig strings instead of C strings
// TODO handle buffering and flushing
// TODO non-i32 integer literals so we can remove the casts
pub fn print_str(str : *const u8, len: isize) {
// 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 {
let SYS_write = 1;
let stdout_fileno = 1;
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);
return syscall3(SYS_write as isize, stdout_fileno as isize, str as isize, len);
}

View File

@ -104,7 +104,7 @@ static void add_compiling_test_cases(void) {
}
export fn _start() -> unreachable {
puts("Hello, world!");
puts(c"Hello, world!");
exit(0);
}
)SOURCE", "Hello, world!\n");
@ -126,7 +126,7 @@ static void add_compiling_test_cases(void) {
}
fn this_is_a_function() -> unreachable {
puts("OK");
puts(c"OK");
exit(0);
}
)SOURCE", "OK\n");
@ -146,7 +146,7 @@ static void add_compiling_test_cases(void) {
/// this is a documentation comment
/// doc comment line 2
export fn _start() -> unreachable {
puts(/* mid-line comment /* nested */ */ "OK");
puts(/* mid-line comment /* nested */ */ c"OK");
exit(0);
}
)SOURCE", "OK\n");
@ -180,7 +180,7 @@ static void add_compiling_test_cases(void) {
// purposefully conflicting function with main source file
// but it's private so it should be OK
fn private_function() {
puts("OK");
puts(c"OK");
}
pub fn print_text() {
@ -198,17 +198,17 @@ static void add_compiling_test_cases(void) {
export fn _start() -> unreachable {
if 1 != 0 {
puts("1 is true");
puts(c"1 is true");
} else {
puts("1 is false");
puts(c"1 is false");
}
if 0 != 0 {
puts("0 is true");
puts(c"0 is true");
} else if 1 - 1 != 0 {
puts("1 - 1 is true");
puts(c"1 - 1 is true");
}
if !(0 != 0) {
puts("!0 is true");
puts(c"!0 is true");
}
exit(0);
}
@ -227,7 +227,7 @@ static void add_compiling_test_cases(void) {
export fn _start() -> unreachable {
if add(22, 11) == 33 {
puts("pass");
puts(c"pass");
}
exit(0);
}
@ -244,7 +244,7 @@ static void add_compiling_test_cases(void) {
if a == 0 {
goto done;
}
puts("loop");
puts(c"loop");
loop(a - 1);
done:
@ -268,7 +268,7 @@ export fn _start() -> unreachable {
let a : i32 = 1;
let b = 2;
if (a + b == 3) {
puts("OK");
puts(c"OK");
}
exit(0);
}
@ -282,10 +282,10 @@ extern {
}
export fn _start() -> unreachable {
if (true) { puts("OK 1"); }
if (false) { puts("BAD 1"); }
if (!true) { puts("BAD 2"); }
if (!false) { puts("OK 2"); }
if (true) { puts(c"OK 1"); }
if (false) { puts(c"BAD 1"); }
if (!true) { puts(c"BAD 2"); }
if (!false) { puts(c"OK 2"); }
exit(0);
}
)SOURCE", "OK 1\nOK 2\n");
@ -300,14 +300,14 @@ extern {
export fn _start() -> unreachable {
if (true) {
let no_conflict = 5;
if (no_conflict == 5) { puts("OK 1"); }
if (no_conflict == 5) { puts(c"OK 1"); }
}
let c = {
let no_conflict = 10;
no_conflict
};
if (c == 10) { puts("OK 2"); }
if (c == 10) { puts(c"OK 2"); }
exit(0);
}
)SOURCE", "OK 1\nOK 2\n");
@ -327,7 +327,7 @@ export fn _start() -> unreachable {
fn void_fun(a : i32, b : void, c : i32) {
let v = b;
let vv : void = if (a == 1) {v} else {};
if (a + c == 3) { puts("OK"); }
if (a + c == 3) { puts(c"OK"); }
return vv;
}
)SOURCE", "OK\n");
@ -341,14 +341,14 @@ extern {
export fn _start() -> unreachable {
let mut zero : i32;
if (zero == 0) { puts("zero"); }
if (zero == 0) { puts(c"zero"); }
let mut i = 0;
loop_start:
if i == 3 {
goto done;
}
puts("loop");
puts(c"loop");
i = i + 1;
goto loop_start;
done:
@ -391,7 +391,7 @@ loop_2_start:
loop_2_end:
if accumulator == 15 {
puts("OK");
puts(c"OK");
}
exit(0);
@ -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("Hello, world!\n", 14 as isize);
print_str(c"Hello, world!\n", 14 as isize);
return 0;
}
)SOURCE", "Hello, world!\n");
@ -430,11 +430,11 @@ fn a() {}
add_compile_fail_case("unreachable with return", R"SOURCE(
fn a() -> unreachable {return;}
)SOURCE", 1, ".tmp_source.zig:2:24: error: type mismatch. expected unreachable. got void");
)SOURCE", 1, ".tmp_source.zig:2:24: error: expected type 'unreachable', got 'void'");
add_compile_fail_case("control reaches end of non-void function", R"SOURCE(
fn a() -> i32 {}
)SOURCE", 1, ".tmp_source.zig:2:15: error: type mismatch. expected i32. got void");
)SOURCE", 1, ".tmp_source.zig:2:15: error: expected type 'i32', got 'void'");
add_compile_fail_case("undefined function call", R"SOURCE(
fn a() {
@ -514,16 +514,16 @@ fn f(a : i32) {
add_compile_fail_case("variable has wrong type", R"SOURCE(
fn f() -> i32 {
let a = "a";
let a = c"a";
a
}
)SOURCE", 1, ".tmp_source.zig:2:15: error: type mismatch. expected i32. got *const u8");
)SOURCE", 1, ".tmp_source.zig:2:15: error: expected type 'i32', got '*const u8'");
add_compile_fail_case("if condition is bool, not int", R"SOURCE(
fn f() {
if (0) {}
}
)SOURCE", 1, ".tmp_source.zig:3:9: error: type mismatch. expected bool. got i32");
)SOURCE", 1, ".tmp_source.zig:3:9: error: expected type 'bool', got 'i32'");
add_compile_fail_case("assign unreachable", R"SOURCE(
fn f() {
@ -551,11 +551,11 @@ a_label:
}
)SOURCE", 1, ".tmp_source.zig:3:1: error: label 'a_label' defined but not used");
add_compile_fail_case("expected bare identifier", R"SOURCE(
add_compile_fail_case("bad assignment target", R"SOURCE(
fn f() {
3 = 3;
}
)SOURCE", 1, ".tmp_source.zig:3:5: error: expected a bare identifier");
)SOURCE", 1, ".tmp_source.zig:3:5: error: assignment target must be variable, field, or array element");
add_compile_fail_case("assign to constant variable", R"SOURCE(
fn f() {