all types are now expressions

See #22
This commit is contained in:
Andrew Kelley 2016-01-13 18:15:51 -07:00
parent cb46d0b5b0
commit b28b7f63d1
26 changed files with 1632 additions and 1880 deletions

View File

@ -34,13 +34,13 @@ Root : many(TopLevelDecl) token(EOF)
TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | ContainerDecl | VariableDeclaration
VariableDeclaration : option(FnVisibleMod) (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) Type option(token(Eq) Expression))
VariableDeclaration : option(FnVisibleMod) (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) UnwrapMaybeExpression option(token(Eq) Expression))
ContainerDecl : many(Directive) option(FnVisibleMod) (token(Struct) | token(Enum)) token(Symbol) token(LBrace) many(StructMember) token(RBrace)
StructMember: StructField | FnDecl
StructField : token(Symbol) option(token(Colon) Type token(Comma))
StructField : token(Symbol) option(token(Colon) Expression) token(Comma))
Use : many(Directive) token(Use) token(String) token(Semicolon)
@ -48,7 +48,7 @@ RootExportDecl : many(Directive) token(Export) token(Symbol) token(String) token
ExternBlock : many(Directive) token(Extern) token(LBrace) many(FnDecl) token(RBrace)
FnProto : many(Directive) option(FnVisibleMod) token(Fn) token(Symbol) ParamDeclList option(token(Arrow) Type)
FnProto : many(Directive) option(FnVisibleMod) token(Fn) token(Symbol) ParamDeclList option(Expression)
Directive : token(NumberSign) token(Symbol) token(LParen) token(String) token(RParen)
@ -56,23 +56,11 @@ FnVisibleMod : token(Pub) | token(Export)
FnDecl : FnProto token(Semicolon)
FnDef : FnProto Block
FnDef : FnProto token(FatArrow) Block
ParamDeclList : token(LParen) list(ParamDecl, token(Comma)) token(RParen)
ParamDecl : token(Symbol) token(Colon) Type | token(Ellipsis)
Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType | MaybeType | CompilerFnExpr
CompilerFnExpr : token(NumberSign) token(Symbol) token(LParen) Expression token(RParen)
CompilerFnType : token(NumberSign) token(Symbol) token(LParen) Type token(RParen)
PointerType : token(Ampersand) option(token(Const)) option(token(NoAlias)) Type
MaybeType : token(Question) Type
ArrayType : token(LBracket) option(Expression) token(RBracket) option(token(Const)) option(token(NoAlias)) Type
ParamDecl : option(token(NoAlias)) token(Symbol) token(Colon) UnwrapMaybeExpression | token(Ellipsis)
Block : token(LBrace) list(option(Statement), token(Semicolon)) token(RBrace)
@ -80,11 +68,9 @@ Statement : Label | VariableDeclaration token(Semicolon) | NonBlockExpression to
Label: token(Symbol) token(Colon)
VariableDeclaration : (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) Type option(token(Eq) Expression))
Expression : BlockExpression | NonBlockExpression
NonBlockExpression : ReturnExpression | AssignmentExpression | AsmExpression
NonBlockExpression : ReturnExpression | AssignmentExpression
AsmExpression : token(Asm) option(token(Volatile)) token(LParen) token(String) option(AsmOutput) token(RParen)
@ -92,13 +78,13 @@ AsmOutput : token(Colon) list(AsmOutputItem, token(Comma)) option(AsmInput)
AsmInput : token(Colon) list(AsmInputItem, token(Comma)) option(AsmClobbers)
AsmOutputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) (token(Symbol) | token(Arrow) Type) token(RParen)
AsmOutputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) (token(Symbol) | token(Arrow) Expression) token(RParen)
AsmInputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) Expression token(RParen)
AsmClobbers: token(Colon) list(token(String), token(Comma))
UnwrapMaybeExpression : BoolOrExpression token(DoubleQuestion) BoolOrExpression | BoolOrExpression
UnwrapMaybeExpression : BoolOrExpression token(DoubleQuestionMark) BoolOrExpression | BoolOrExpression
AssignmentExpression : UnwrapMaybeExpression AssignmentOperator UnwrapMaybeExpression | UnwrapMaybeExpression
@ -116,7 +102,7 @@ IfExpression : IfVarExpression | IfBoolExpression
IfBoolExpression : token(If) token(LParen) Expression token(RParen) Expression option(Else)
IfVarExpression : token(If) token(LParen) (token(Const) | token(Var)) token(Symbol) option(token(Colon) Type) Token(MaybeAssign) Expression token(RParen) Expression Option(Else)
IfVarExpression : token(If) token(LParen) (token(Const) | token(Var)) token(Symbol) option(token(Colon) Expression) Token(MaybeAssign) Expression token(RParen) Expression Option(Else)
Else : token(Else) Expression
@ -144,11 +130,11 @@ MultiplyExpression : CastExpression MultiplyOperator MultiplyExpression | CastEx
MultiplyOperator : token(Star) | token(Slash) | token(Percent)
CastExpression : CastExpression token(as) Type | PrefixOpExpression
CastExpression : CastExpression token(as) PrimaryExpression | PrefixOpExpression
PrefixOpExpression : PrefixOp PrefixOpExpression | SuffixOpExpression
SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression | ContainerInitExpression)
FieldAccessExpression : token(Dot) token(Symbol)
@ -158,26 +144,30 @@ ArrayAccessExpression : token(LBracket) Expression token(RBracket)
SliceExpression : token(LBracket) Expression token(Ellipsis) option(Expression) token(RBracket) option(token(Const))
PrefixOp : token(Not) | token(Dash) | token(Tilde) | token(Star) | (token(Ampersand) option(token(Const)))
ContainerInitExpression : token(LBrace) ContainerInitBody token(RBrace)
PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression | CompilerFnType | (token(AtSign) token(Symbol) FnCallExpression)
ContainerInitBody : list(StructLiteralField, token(Comma)) | list(Expression, token(Comma))
StructValueExpression : token(Type) token(LBrace) list(StructValueExpressionField, token(Comma)) token(RBrace)
StructLiteralField : token(Dot) token(Symbol) token(Eq) Expression
StructValueExpressionField : token(Dot) token(Symbol) token(Eq) Expression
PrefixOp : token(Not) | token(Dash) | token(Tilde) | token(Star) | (token(Ampersand) option(token(Const))) | token(QuestionMark)
Goto: token(Goto) token(Symbol)
PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | token(Symbol) | (token(AtSign) token(Symbol) FnCallExpression) | ArrayType | AsmExpression
ArrayType : token(LBracket) option(Expression) token(RBracket) option(token(Const)) Expression
GotoExpression: token(Goto) token(Symbol)
GroupedExpression : token(LParen) Expression token(RParen)
KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False) | token(Null)
KeywordLiteral : token(True) | token(False) | token(Null) | token(Break) | token(Continue)
```
## Operator Precedence
```
x() x[] x.y
!x -x ~x *x &x &const x
x() x[] x{} x.y
!x -x ~x *x &x
as
* / %
+ -

View File

@ -15,8 +15,8 @@ syn keyword zigConditional if else switch
syn keyword zigRepeat while for
syn keyword zigConstant null
syn keyword zigKeyword fn unreachable use void
syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 string
syn keyword zigKeyword fn use
syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 string void unreachable
syn keyword zigBoolean true false

View File

@ -1,36 +0,0 @@
export executable "arrays";
use "std.zig";
pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
var array : [5]u32;
var i : u32 = 0;
while (i < 5) {
array[i] = i + 1;
i = array[i];
}
i = 0;
var accumulator : u32 = 0;
while (i < 5) {
accumulator += array[i];
i += 1;
}
if (accumulator != 15) {
print_str("BAD\n");
}
if (get_array_len(array) != 5) {
print_str("BAD\n");
}
print_str("OK\n");
return 0;
}
fn get_array_len(a: []u32) -> usize {
a.len
}

7
example/cat/main.zig Normal file
View File

@ -0,0 +1,7 @@
export executable "cat";
pub main(argv: [][]u8) -> i32 {
return 0;
}

View File

@ -1,52 +0,0 @@
export executable "expressions";
use "std.zig";
fn other_exit() -> unreachable {
if (true) { exit(0); }
// the unreachable statement is the programmer assuring the compiler that this code is impossible to execute.
unreachable;
}
export fn main(argc: isize, argv: &&u8, env: &&u8) -> unreachable {
const a : i32 = 1;
const b = 2 as i32;
// const c : i32; // not yet support for const variables
// const d; // parse error
if (a + b == 3) {
const no_conflict : i32 = 5;
if (no_conflict == 5) { print_str("OK 1\n" as string); }
}
const c = {
const no_conflict : i32 = 10;
no_conflict
};
if (c == 10) { print_str("OK 2\n" as string); }
void_fun(1, void, 2);
test_mutable_vars();
other_exit();
}
fn void_fun(a : i32, b : void, c : i32) -> void {
const x = a + 1; // i32
const y = c + 1; // i32
const z = b; // void
const w : void = z; // void
if (x + y == 4) { return w; }
}
fn test_mutable_vars() {
var i : i32 = 0;
loop_start:
if i == 3 {
goto done;
}
print_str("loop\n" as string);
i = i + 1;
goto loop_start;
done:
}

View File

@ -3,12 +3,12 @@ export executable "guess_number";
use "std.zig";
use "rand.zig";
pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
print_str("Welcome to the Guess Number Game in Zig.\n");
var seed : u32;
const err = os_get_random_bytes(&seed as &u8, #sizeof(u32));
if (err != #sizeof(u32)) {
const err = os_get_random_bytes(&seed as (&u8), @sizeof(u32));
if (err != @sizeof(u32)) {
// TODO full error message
fprint_str(stderr_fileno, "unable to get random bytes\n");
return 1;

View File

@ -2,7 +2,7 @@ export executable "hello";
use "std.zig";
pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
print_str("Hello, world!\n");
return 0;
}

View File

@ -2,11 +2,10 @@ export executable "hello";
#link("c")
extern {
fn printf(__format: &const u8, ...) -> i32;
fn exit(__status: i32) -> unreachable;
fn printf(__format: &const u8, ...) i32;
}
export fn main(argc: i32, argv: &&u8, env: &&u8) -> i32 {
export fn main(argc: i32, argv: &&u8, env: &&u8) i32 => {
printf(c"Hello, world!\n");
return 0;
}

View File

@ -1,16 +1,16 @@
pub struct List#(T: type) {
items: ?&T,
length: usize,
capacity: usize,
length: isize,
capacity: isize,
pub fn (l: &List) deinit() {
pub fn deinit(l: &List) {
free(l.items);
l.items = None;
l.items = null;
}
pub fn append(l: &List, item: T) -> error {
const err = l.ensure_capacity(l.length + 1);
if err != Error.None {
if err != error.None {
return err;
}
const raw_items = l.items ?? unreachable;
@ -47,11 +47,11 @@ pub struct List#(T: type) {
better_capacity *= 2;
}
if better_capacity != l.capacity {
const new_items = realloc(l.items, better_capacity) ?? { return Error.NoMem };
const new_items = realloc(l.items, better_capacity) ?? { return error.NoMem };
l.items = new_items;
l.capacity = better_capacity;
}
Error.None
error.None
}
}
@ -64,3 +64,41 @@ pub fn realloc#(T: type)(ptr: ?&T, new_count: usize) -> ?&T {
pub fn free#(T: type)(ptr: ?&T) {
}
////////////////// alternate
// previously proposed, but with : instead of ->
// `:` means "parser should expect a type now"
fn max#(T :type)(a :T, b :T) :T {
if (a > b) a else b
}
// andy's new idea
// parameters can talk about @typeof() for previous parameters.
// using :T here is equivalent to @child_type(@typeof(T))
fn max(T :type, a :T, b :T) :T {
if (a > b) a else b
}
fn f() {
const x :i32 = 1234;
const y :i32 = 5678;
const z = max(@typeof(x), x, y);
}
// So, type-generic functions don't need any fancy syntax. type-generic
// containers still do, though:
pub struct List(T :type) {
items :?&T,
length :isize,
capacity :isize,
}
// Types are always marked with ':' so we don't need '#' to indicate type generic parameters.
fn f() {
var list :List(:u8);
}

View File

@ -2,7 +2,7 @@ export executable "maybe_type";
use "std.zig";
pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
const x : ?bool = true;
if (const y ?= x) {
@ -25,7 +25,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
const final_x : ?i32 = 13;
const num = final_x ?? unreachable;
const num = final_x ?? unreachable{};
if (num != 13) {
print_str("BAD\n");

View File

@ -2,10 +2,10 @@ use "std.zig";
// purposefully conflicting function with main.zig
// but it's private so it should be OK
fn private_function() {
fn private_function() => {
print_str("OK 1\n");
}
pub fn print_text() {
pub fn print_text() => {
private_function();
}

View File

@ -3,12 +3,12 @@ export executable "test-multiple-files";
use "std.zig";
use "foo.zig";
pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
private_function();
print_str("OK 2\n");
return 0;
}
fn private_function() {
fn private_function() => {
print_text();
}

View File

@ -1,87 +0,0 @@
export executable "structs";
use "std.zig";
pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
var foo : Foo;
foo.a = foo.a + 1;
foo.b = foo.a == 1;
test_foo(foo);
modify_foo(&foo);
if foo.c != 100 {
print_str("BAD\n");
}
test_point_to_self();
test_byval_assign();
test_initializer();
print_str("OK\n");
return 0;
}
struct Foo {
a : i32,
b : bool,
c : f32,
}
struct Node {
val: Val,
next: &Node,
}
struct Val {
x: i32,
}
fn test_foo(foo : Foo) {
if !foo.b {
print_str("BAD\n");
}
}
fn modify_foo(foo : &Foo) {
foo.c = 100;
}
fn test_point_to_self() {
var root : Node;
root.val.x = 1;
var node : Node;
node.next = &root;
node.val.x = 2;
root.next = &node;
if node.next.next.next.val.x != 1 {
print_str("BAD\n");
}
}
fn test_byval_assign() {
var foo1 : Foo;
var foo2 : Foo;
foo1.a = 1234;
if foo2.a != 0 { print_str("BAD\n"); }
foo2 = foo1;
if foo2.a != 1234 { print_str("BAD - byval assignment failed\n"); }
}
fn test_initializer() {
const val = Val { .x = 42 };
if val.x != 42 { print_str("BAD\n"); }
}

View File

@ -100,7 +100,6 @@ enum NodeType {
NodeTypeFnDef,
NodeTypeFnDecl,
NodeTypeParamDecl,
NodeTypeType,
NodeTypeBlock,
NodeTypeExternBlock,
NodeTypeDirective,
@ -111,7 +110,6 @@ enum NodeType {
NodeTypeNumberLiteral,
NodeTypeStringLiteral,
NodeTypeCharLiteral,
NodeTypeUnreachable,
NodeTypeSymbol,
NodeTypePrefixOpExpr,
NodeTypeFnCallExpr,
@ -119,7 +117,6 @@ enum NodeType {
NodeTypeSliceExpr,
NodeTypeFieldAccessExpr,
NodeTypeUse,
NodeTypeVoid,
NodeTypeBoolLiteral,
NodeTypeNullLiteral,
NodeTypeIfBoolExpr,
@ -132,10 +129,9 @@ enum NodeType {
NodeTypeAsmExpr,
NodeTypeStructDecl,
NodeTypeStructField,
NodeTypeStructValueExpr,
NodeTypeContainerInitExpr,
NodeTypeStructValueField,
NodeTypeCompilerFnExpr,
NodeTypeCompilerFnType,
NodeTypeArrayType,
};
struct AstNodeRoot {
@ -185,32 +181,12 @@ struct AstNodeFnDecl {
struct AstNodeParamDecl {
Buf name;
AstNode *type;
bool is_noalias;
// populated by semantic analyzer
VariableTableEntry *variable;
};
enum AstNodeTypeType {
AstNodeTypeTypePrimitive,
AstNodeTypeTypePointer,
AstNodeTypeTypeArray,
AstNodeTypeTypeMaybe,
AstNodeTypeTypeCompilerExpr,
};
struct AstNodeType {
AstNodeTypeType type;
Buf primitive_name;
AstNode *child_type;
AstNode *array_size; // can be null
bool is_const;
bool is_noalias;
AstNode *compiler_expr;
// populated by semantic analyzer
TypeTableEntry *entry;
};
struct AstNodeBlock {
ZigList<AstNode *> statements;
@ -295,6 +271,7 @@ struct AstNodeFnCallExpr {
// populated by semantic analyzer:
BuiltinFnEntry *builtin_fn;
Expr resolved_expr;
NumLitCodeGen resolved_num_lit;
};
struct AstNodeArrayAccessExpr {
@ -360,6 +337,7 @@ enum PrefixOp {
PrefixOpAddressOf,
PrefixOpConstAddressOf,
PrefixOpDereference,
PrefixOpMaybe,
};
struct AstNodePrefixOpExpr {
@ -537,45 +515,24 @@ struct AstNodeStructValueField {
TypeStructField *type_struct_field;
};
struct AstNodeStructValueExpr {
enum ContainerInitKind {
ContainerInitKindStruct,
ContainerInitKindArray,
};
struct AstNodeContainerInitExpr {
AstNode *type;
ZigList<AstNode *> fields;
ZigList<AstNode *> entries;
ContainerInitKind kind;
// populated by semantic analyzer
StructValExprCodeGen codegen;
Expr resolved_expr;
};
struct AstNodeCompilerFnExpr {
Buf name;
AstNode *expr;
// populated by semantic analyzer
Expr resolved_expr;
};
struct AstNodeCompilerFnType {
Buf name;
AstNode *type;
// populated by semantic analyzer
Expr resolved_expr;
NumLitCodeGen resolved_num_lit;
};
struct AstNodeNullLiteral {
// populated by semantic analyzer
StructValExprCodeGen resolved_struct_val_expr;
Expr resolved_expr;
};
struct AstNodeVoidExpr {
// populated by semantic analyzer
Expr resolved_expr;
};
struct AstNodeUnreachableExpr {
struct AstNodeNullLiteral {
// populated by semantic analyzer
StructValExprCodeGen resolved_struct_val_expr;
Expr resolved_expr;
};
@ -603,6 +560,15 @@ struct AstNodeContinueExpr {
Expr resolved_expr;
};
struct AstNodeArrayType {
AstNode *size;
AstNode *child_type;
bool is_const;
// populated by semantic analyzer
Expr resolved_expr;
};
struct AstNode {
enum NodeType type;
int line;
@ -615,7 +581,6 @@ struct AstNode {
AstNodeFnDef fn_def;
AstNodeFnDecl fn_decl;
AstNodeFnProto fn_proto;
AstNodeType type;
AstNodeParamDecl param_decl;
AstNodeBlock block;
AstNodeReturnExpr return_expr;
@ -641,17 +606,14 @@ struct AstNode {
AstNodeStringLiteral string_literal;
AstNodeCharLiteral char_literal;
AstNodeNumberLiteral number_literal;
AstNodeStructValueExpr struct_val_expr;
AstNodeContainerInitExpr container_init_expr;
AstNodeStructValueField struct_val_field;
AstNodeCompilerFnExpr compiler_fn_expr;
AstNodeCompilerFnType compiler_fn_type;
AstNodeNullLiteral null_literal;
AstNodeVoidExpr void_expr;
AstNodeUnreachableExpr unreachable_expr;
AstNodeSymbolExpr symbol_expr;
AstNodeBoolLiteral bool_literal;
AstNodeBreakExpr break_expr;
AstNodeContinueExpr continue_expr;
AstNodeArrayType array_type;
} data;
};
@ -670,7 +632,6 @@ struct AsmToken {
struct TypeTableEntryPointer {
TypeTableEntry *child_type;
bool is_const;
bool is_noalias;
};
struct TypeTableEntryInt {
@ -770,8 +731,8 @@ struct TypeTableEntry {
} data;
// use these fields to make sure we don't duplicate type table entries for the same type
TypeTableEntry *pointer_parent[2][2]; // 0 - const. 1 - noalias
TypeTableEntry *unknown_size_array_parent[2][2]; // 0 - const. 1 - noalias
TypeTableEntry *pointer_parent[2];
TypeTableEntry *unknown_size_array_parent[2];
HashMap<uint64_t, TypeTableEntry *, uint64_hash, uint64_eq> arrays_by_size;
TypeTableEntry *maybe_parent;
TypeTableEntry *meta_parent;
@ -830,6 +791,11 @@ enum BuiltinFnId {
BuiltinFnIdArithmeticWithOverflow,
BuiltinFnIdMemcpy,
BuiltinFnIdMemset,
BuiltinFnIdSizeof,
BuiltinFnIdMaxValue,
BuiltinFnIdMinValue,
BuiltinFnIdValueCount,
BuiltinFnIdTypeof,
};
struct BuiltinFnEntry {

File diff suppressed because it is too large Load Diff

View File

@ -13,12 +13,13 @@
void semantic_analyze(CodeGen *g);
void add_node_error(CodeGen *g, AstNode *node, Buf *msg);
TypeTableEntry *new_type_table_entry(TypeTableEntryId id);
TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const, bool is_noalias);
TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
VariableTableEntry *find_variable(BlockContext *context, Buf *name);
TypeTableEntry *find_container(BlockContext *context, Buf *name);
BlockContext *new_block_context(AstNode *node, BlockContext *parent);
Expr *get_resolved_expr(AstNode *node);
NumLitCodeGen *get_resolved_num_lit(AstNode *node);
TopLevelDecl *get_resolved_top_level_decl(AstNode *node);
bool is_node_void_expr(AstNode *node);
#endif

View File

@ -72,35 +72,35 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType b
LLVMValueRef target_ref, LLVMValueRef value,
TypeTableEntry *op1_type, TypeTableEntry *op2_type);
static TypeTableEntry *get_type_for_type_node(CodeGen *g, AstNode *type_node) {
assert(type_node->type == NodeTypeType);
return type_node->data.type.entry;
static TypeTableEntry *get_type_for_type_node(AstNode *node) {
TypeTableEntry *meta_type_entry = get_resolved_expr(node)->type_entry;
assert(meta_type_entry->id == TypeTableEntryIdMetaType);
return meta_type_entry->data.meta_type.child_type;
}
static TypeTableEntry *fn_proto_type_from_type_node(CodeGen *g, AstNode *type_node) {
TypeTableEntry *type_entry = get_type_for_type_node(g, type_node);
TypeTableEntry *type_entry = get_type_for_type_node(type_node);
if (type_entry->id == TypeTableEntryIdStruct || type_entry->id == TypeTableEntryIdArray) {
return get_pointer_to_type(g, type_entry, true, true);
return get_pointer_to_type(g, type_entry, true);
} else {
return type_entry;
}
}
static LLVMZigDIType *to_llvm_debug_type(CodeGen *g, AstNode *type_node) {
TypeTableEntry *type_entry = get_type_for_type_node(g, type_node);
TypeTableEntry *type_entry = get_type_for_type_node(type_node);
return type_entry->di_type;
}
static bool type_is_unreachable(CodeGen *g, AstNode *type_node) {
return get_type_for_type_node(g, type_node)->id == TypeTableEntryIdUnreachable;
return get_type_for_type_node(type_node)->id == TypeTableEntryIdUnreachable;
}
static bool is_param_decl_type_void(CodeGen *g, AstNode *param_decl_node) {
assert(param_decl_node->type == NodeTypeParamDecl);
return get_type_for_type_node(g, param_decl_node->data.param_decl.type)->id == TypeTableEntryIdVoid;
return get_type_for_type_node(param_decl_node->data.param_decl.type)->id == TypeTableEntryIdVoid;
}
static int count_non_void_params(CodeGen *g, ZigList<AstNode *> *params) {
@ -146,6 +146,32 @@ static TypeTableEntry *get_expr_type(AstNode *node) {
return expr->type_entry;
}
static LLVMValueRef gen_number_literal_raw(CodeGen *g, AstNode *source_node,
NumLitCodeGen *codegen_num_lit, AstNodeNumberLiteral *num_lit_node)
{
TypeTableEntry *type_entry = codegen_num_lit->resolved_type;
assert(type_entry);
// override the expression type for number literals
get_resolved_expr(source_node)->type_entry = type_entry;
if (type_entry->id == TypeTableEntryIdInt) {
// here the union has int64_t and uint64_t and we purposefully read
// the uint64_t value in either case, because we want the twos
// complement representation
return LLVMConstInt(type_entry->type_ref,
num_lit_node->data.x_uint,
type_entry->data.integral.is_signed);
} else if (type_entry->id == TypeTableEntryIdFloat) {
return LLVMConstReal(type_entry->type_ref,
num_lit_node->data.x_float);
} else {
zig_panic("bad number literal type");
}
}
static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeFnCallExpr);
AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
@ -154,6 +180,7 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
switch (builtin_fn->id) {
case BuiltinFnIdInvalid:
case BuiltinFnIdTypeof:
zig_unreachable();
case BuiltinFnIdArithmeticWithOverflow:
{
@ -238,6 +265,74 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
LLVMBuildCall(g->builder, builtin_fn->fn_val, params, 5, "");
return nullptr;
}
case BuiltinFnIdSizeof:
{
assert(node->data.fn_call_expr.params.length == 1);
AstNode *type_node = node->data.fn_call_expr.params.at(0);
TypeTableEntry *type_entry = get_type_for_type_node(type_node);
NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node);
AstNodeNumberLiteral num_lit_node;
num_lit_node.kind = NumLitU64; // this field isn't even read
num_lit_node.overflow = false;
num_lit_node.data.x_uint = type_entry->size_in_bits / 8;
return gen_number_literal_raw(g, node, codegen_num_lit, &num_lit_node);
}
case BuiltinFnIdMinValue:
{
assert(node->data.fn_call_expr.params.length == 1);
AstNode *type_node = node->data.fn_call_expr.params.at(0);
TypeTableEntry *type_entry = get_type_for_type_node(type_node);
if (type_entry->id == TypeTableEntryIdInt) {
if (type_entry->data.integral.is_signed) {
return LLVMConstInt(type_entry->type_ref, 1ULL << (type_entry->size_in_bits - 1), false);
} else {
return LLVMConstNull(type_entry->type_ref);
}
} else if (type_entry->id == TypeTableEntryIdFloat) {
zig_panic("TODO codegen min_value float");
} else {
zig_unreachable();
}
}
case BuiltinFnIdMaxValue:
{
assert(node->data.fn_call_expr.params.length == 1);
AstNode *type_node = node->data.fn_call_expr.params.at(0);
TypeTableEntry *type_entry = get_type_for_type_node(type_node);
if (type_entry->id == TypeTableEntryIdInt) {
if (type_entry->data.integral.is_signed) {
return LLVMConstInt(type_entry->type_ref, (1ULL << (type_entry->size_in_bits - 1)) - 1, false);
} else {
return LLVMConstAllOnes(type_entry->type_ref);
}
} else if (type_entry->id == TypeTableEntryIdFloat) {
zig_panic("TODO codegen max_value float");
} else {
zig_unreachable();
}
}
case BuiltinFnIdValueCount:
{
assert(node->data.fn_call_expr.params.length == 1);
AstNode *type_node = node->data.fn_call_expr.params.at(0);
TypeTableEntry *type_entry = get_type_for_type_node(type_node);
if (type_entry->id == TypeTableEntryIdEnum) {
NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node);
AstNodeNumberLiteral num_lit_node;
num_lit_node.kind = NumLitU64; // field ignored
num_lit_node.overflow = false;
num_lit_node.data.x_uint = type_entry->data.enumeration.field_count;
return gen_number_literal_raw(g, node, codegen_num_lit, &num_lit_node);
} else {
zig_unreachable();
}
}
}
zig_unreachable();
}
@ -692,6 +787,10 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
add_debug_source_node(g, node);
return LLVMBuildLoad(g->builder, expr, "");
}
case PrefixOpMaybe:
{
zig_panic("TODO codegen PrefixOpMaybe");
}
}
zig_unreachable();
}
@ -1484,35 +1583,46 @@ static LLVMValueRef gen_null_literal(CodeGen *g, AstNode *node) {
return tmp_struct_ptr;
}
static LLVMValueRef gen_struct_val_expr(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeStructValueExpr);
static LLVMValueRef gen_container_init_expr(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeContainerInitExpr);
TypeTableEntry *type_entry = get_expr_type(node);
assert(type_entry->id == TypeTableEntryIdStruct);
if (type_entry->id == TypeTableEntryIdStruct) {
assert(node->data.container_init_expr.kind == ContainerInitKindStruct);
int field_count = type_entry->data.structure.field_count;
assert(field_count == node->data.struct_val_expr.fields.length);
int field_count = type_entry->data.structure.field_count;
assert(field_count == node->data.container_init_expr.entries.length);
StructValExprCodeGen *struct_val_expr_node = &node->data.struct_val_expr.codegen;
LLVMValueRef tmp_struct_ptr = struct_val_expr_node->ptr;
StructValExprCodeGen *struct_val_expr_node = &node->data.container_init_expr.resolved_struct_val_expr;
LLVMValueRef tmp_struct_ptr = struct_val_expr_node->ptr;
for (int i = 0; i < field_count; i += 1) {
AstNode *field_node = node->data.struct_val_expr.fields.at(i);
assert(field_node->type == NodeTypeStructValueField);
TypeStructField *type_struct_field = field_node->data.struct_val_field.type_struct_field;
if (type_struct_field->type_entry->id == TypeTableEntryIdVoid) {
continue;
for (int i = 0; i < field_count; i += 1) {
AstNode *field_node = node->data.container_init_expr.entries.at(i);
assert(field_node->type == NodeTypeStructValueField);
TypeStructField *type_struct_field = field_node->data.struct_val_field.type_struct_field;
if (type_struct_field->type_entry->id == TypeTableEntryIdVoid) {
continue;
}
assert(buf_eql_buf(type_struct_field->name, &field_node->data.struct_val_field.name));
add_debug_source_node(g, field_node);
LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, type_struct_field->gen_index, "");
LLVMValueRef value = gen_expr(g, field_node->data.struct_val_field.expr);
LLVMBuildStore(g->builder, value, field_ptr);
}
assert(buf_eql_buf(type_struct_field->name, &field_node->data.struct_val_field.name));
add_debug_source_node(g, field_node);
LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, type_struct_field->gen_index, "");
LLVMValueRef value = gen_expr(g, field_node->data.struct_val_field.expr);
LLVMBuildStore(g->builder, value, field_ptr);
return tmp_struct_ptr;
} else if (type_entry->id == TypeTableEntryIdUnreachable) {
assert(node->data.container_init_expr.entries.length == 0);
add_debug_source_node(g, node);
return LLVMBuildUnreachable(g->builder);
} else if (type_entry->id == TypeTableEntryIdVoid) {
assert(node->data.container_init_expr.entries.length == 0);
return nullptr;
} else {
zig_unreachable();
}
return tmp_struct_ptr;
}
static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
@ -1659,84 +1769,6 @@ static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) {
get_resolved_expr(node)->block_context, false, &init_val);
}
static LLVMValueRef gen_number_literal_raw(CodeGen *g, AstNode *source_node,
NumLitCodeGen *codegen_num_lit, AstNodeNumberLiteral *num_lit_node)
{
TypeTableEntry *type_entry = codegen_num_lit->resolved_type;
assert(type_entry);
// override the expression type for number literals
get_resolved_expr(source_node)->type_entry = type_entry;
if (type_entry->id == TypeTableEntryIdInt) {
// here the union has int64_t and uint64_t and we purposefully read
// the uint64_t value in either case, because we want the twos
// complement representation
return LLVMConstInt(type_entry->type_ref,
num_lit_node->data.x_uint,
type_entry->data.integral.is_signed);
} else if (type_entry->id == TypeTableEntryIdFloat) {
return LLVMConstReal(type_entry->type_ref,
num_lit_node->data.x_float);
} else {
zig_panic("bad number literal type");
}
}
static LLVMValueRef gen_compiler_fn_type(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeCompilerFnType);
Buf *name = &node->data.compiler_fn_type.name;
TypeTableEntry *type_entry = get_type_for_type_node(g, node->data.compiler_fn_type.type);
if (buf_eql_str(name, "sizeof")) {
NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node);
AstNodeNumberLiteral num_lit_node;
num_lit_node.kind = type_entry->data.num_lit.kind;
num_lit_node.overflow = false;
num_lit_node.data.x_uint = type_entry->size_in_bits / 8;
return gen_number_literal_raw(g, node, codegen_num_lit, &num_lit_node);
} else if (buf_eql_str(name, "min_value")) {
if (type_entry->id == TypeTableEntryIdInt) {
if (type_entry->data.integral.is_signed) {
return LLVMConstInt(type_entry->type_ref, 1ULL << (type_entry->size_in_bits - 1), false);
} else {
return LLVMConstNull(type_entry->type_ref);
}
} else if (type_entry->id == TypeTableEntryIdFloat) {
zig_panic("TODO codegen min_value float");
} else {
zig_unreachable();
}
} else if (buf_eql_str(name, "max_value")) {
if (type_entry->id == TypeTableEntryIdInt) {
if (type_entry->data.integral.is_signed) {
return LLVMConstInt(type_entry->type_ref, (1ULL << (type_entry->size_in_bits - 1)) - 1, false);
} else {
return LLVMConstAllOnes(type_entry->type_ref);
}
} else if (type_entry->id == TypeTableEntryIdFloat) {
zig_panic("TODO codegen max_value float");
} else {
zig_unreachable();
}
} else if (buf_eql_str(name, "value_count")) {
if (type_entry->id == TypeTableEntryIdEnum) {
NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node);
AstNodeNumberLiteral num_lit_node;
num_lit_node.kind = type_entry->data.num_lit.kind;
num_lit_node.overflow = false;
num_lit_node.data.x_uint = type_entry->data.enumeration.field_count;
return gen_number_literal_raw(g, node, codegen_num_lit, &num_lit_node);
} else {
zig_unreachable();
}
} else {
zig_unreachable();
}
}
static LLVMValueRef gen_number_literal(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeNumberLiteral);
@ -1746,6 +1778,30 @@ static LLVMValueRef gen_number_literal(CodeGen *g, AstNode *node) {
return gen_number_literal_raw(g, node, codegen_num_lit, &node->data.number_literal);
}
static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) {
VariableTableEntry *variable = find_variable(
get_resolved_expr(node)->block_context,
&node->data.symbol_expr.symbol);
assert(variable);
if (variable->type->id == TypeTableEntryIdVoid) {
return nullptr;
} else if (variable->is_ptr) {
assert(variable->value_ref);
if (variable->type->id == TypeTableEntryIdArray) {
return variable->value_ref;
} else if (variable->type->id == TypeTableEntryIdStruct ||
variable->type->id == TypeTableEntryIdMaybe)
{
return variable->value_ref;
} else {
add_debug_source_node(g, node);
return LLVMBuildLoad(g->builder, variable->value_ref, "");
}
} else {
return variable->value_ref;
}
}
static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
switch (node->type) {
case NodeTypeBinOpExpr:
@ -1766,11 +1822,6 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
return gen_slice_expr(g, node);
case NodeTypeFieldAccessExpr:
return gen_field_access_expr(g, node, false);
case NodeTypeUnreachable:
add_debug_source_node(g, node);
return LLVMBuildUnreachable(g->builder);
case NodeTypeVoid:
return nullptr;
case NodeTypeBoolLiteral:
if (node->data.bool_literal.value)
return LLVMConstAllOnes(LLVMInt1Type());
@ -1802,29 +1853,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
case NodeTypeCharLiteral:
return LLVMConstInt(LLVMInt8Type(), node->data.char_literal.value, false);
case NodeTypeSymbol:
{
VariableTableEntry *variable = find_variable(
get_resolved_expr(node)->block_context,
&node->data.symbol_expr.symbol);
assert(variable);
if (variable->type->id == TypeTableEntryIdVoid) {
return nullptr;
} else if (variable->is_ptr) {
assert(variable->value_ref);
if (variable->type->id == TypeTableEntryIdArray) {
return variable->value_ref;
} else if (variable->type->id == TypeTableEntryIdStruct ||
variable->type->id == TypeTableEntryIdMaybe)
{
return variable->value_ref;
} else {
add_debug_source_node(g, node);
return LLVMBuildLoad(g->builder, variable->value_ref, "");
}
} else {
return variable->value_ref;
}
}
return gen_symbol(g, node);
case NodeTypeBlock:
return gen_block(g, node, nullptr);
case NodeTypeGoto:
@ -1846,24 +1875,21 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
LLVMPositionBuilderAtEnd(g->builder, basic_block);
return nullptr;
}
case NodeTypeStructValueExpr:
return gen_struct_val_expr(g, node);
case NodeTypeCompilerFnType:
return gen_compiler_fn_type(g, node);
case NodeTypeContainerInitExpr:
return gen_container_init_expr(g, node);
case NodeTypeRoot:
case NodeTypeRootExportDecl:
case NodeTypeFnProto:
case NodeTypeFnDef:
case NodeTypeFnDecl:
case NodeTypeParamDecl:
case NodeTypeType:
case NodeTypeExternBlock:
case NodeTypeDirective:
case NodeTypeUse:
case NodeTypeStructDecl:
case NodeTypeStructField:
case NodeTypeStructValueField:
case NodeTypeCompilerFnExpr:
case NodeTypeArrayType:
zig_unreachable();
}
zig_unreachable();
@ -1872,7 +1898,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
LLVMValueRef val = gen_expr_no_cast(g, node);
if (node->type == NodeTypeVoid) {
if (is_node_void_expr(node)) {
return val;
}
@ -1966,7 +1992,7 @@ static void do_code_gen(CodeGen *g) {
assert(proto_node->type == NodeTypeFnProto);
AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
LLVMTypeRef ret_type = get_type_for_type_node(g, fn_proto->return_type)->type_ref;
LLVMTypeRef ret_type = get_type_for_type_node(fn_proto->return_type)->type_ref;
int param_count = count_non_void_params(g, &fn_proto->params);
LLVMTypeRef *param_types = allocate<LLVMTypeRef>(param_count);
int gen_param_index = 0;
@ -2009,7 +2035,7 @@ static void do_code_gen(CodeGen *g) {
TypeTableEntry *param_type = fn_proto_type_from_type_node(g, type_node);
LLVMValueRef argument_val = LLVMGetParam(fn, gen_param_index);
if (param_type->id == TypeTableEntryIdPointer &&
param_type->data.pointer.is_noalias)
false) // TODO test if parameter is noalias
{
LLVMAddAttribute(argument_val, LLVMNoAliasAttribute);
} else if (param_type->id == TypeTableEntryIdPointer &&
@ -2267,7 +2293,7 @@ static void define_builtin_types(CodeGen *g) {
g->builtin_types.entry_u64 = entry;
g->primitive_type_table.put(&entry->name, entry);
}
g->builtin_types.entry_c_string_literal = get_pointer_to_type(g, g->builtin_types.entry_u8, true, false);
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 = LLVMInt8Type();
@ -2413,7 +2439,7 @@ static void define_builtin_fns_int(CodeGen *g, TypeTableEntry *type_entry) {
builtin_fn->param_types = allocate<TypeTableEntry *>(builtin_fn->param_count);
builtin_fn->param_types[0] = type_entry;
builtin_fn->param_types[1] = type_entry;
builtin_fn->param_types[2] = get_pointer_to_type(g, type_entry, false, false);
builtin_fn->param_types[2] = get_pointer_to_type(g, type_entry, false);
const char *signed_str = type_entry->data.integral.is_signed ?
@ -2437,6 +2463,23 @@ static void define_builtin_fns_int(CodeGen *g, TypeTableEntry *type_entry) {
}
}
static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char *name) {
BuiltinFnEntry *builtin_fn = allocate<BuiltinFnEntry>(1);
buf_init_from_str(&builtin_fn->name, name);
builtin_fn->id = id;
g->builtin_fn_table.put(&builtin_fn->name, builtin_fn);
return builtin_fn;
}
static BuiltinFnEntry *create_one_arg_builtin_fn(CodeGen *g, BuiltinFnId id, const char *name) {
BuiltinFnEntry *builtin_fn = create_builtin_fn(g, id, name);
builtin_fn->return_type = nullptr; // manually determined later
builtin_fn->param_count = 1;
builtin_fn->param_types = allocate<TypeTableEntry *>(builtin_fn->param_count);
builtin_fn->param_types[0] = nullptr; // manually checked later
return builtin_fn;
}
static void define_builtin_fns(CodeGen *g) {
define_builtin_fns_int(g, g->builtin_types.entry_u8);
define_builtin_fns_int(g, g->builtin_types.entry_u16);
@ -2447,9 +2490,7 @@ static void define_builtin_fns(CodeGen *g) {
define_builtin_fns_int(g, g->builtin_types.entry_i32);
define_builtin_fns_int(g, g->builtin_types.entry_i64);
{
BuiltinFnEntry *builtin_fn = allocate<BuiltinFnEntry>(1);
buf_init_from_str(&builtin_fn->name, "memcpy");
builtin_fn->id = BuiltinFnIdMemcpy;
BuiltinFnEntry *builtin_fn = create_builtin_fn(g, BuiltinFnIdMemcpy, "memcpy");
builtin_fn->return_type = g->builtin_types.entry_void;
builtin_fn->param_count = 3;
builtin_fn->param_types = allocate<TypeTableEntry *>(builtin_fn->param_count);
@ -2470,12 +2511,9 @@ static void define_builtin_fns(CodeGen *g) {
assert(LLVMGetIntrinsicID(builtin_fn->fn_val));
g->memcpy_fn_val = builtin_fn->fn_val;
g->builtin_fn_table.put(&builtin_fn->name, builtin_fn);
}
{
BuiltinFnEntry *builtin_fn = allocate<BuiltinFnEntry>(1);
buf_init_from_str(&builtin_fn->name, "memset");
builtin_fn->id = BuiltinFnIdMemset;
BuiltinFnEntry *builtin_fn = create_builtin_fn(g, BuiltinFnIdMemset, "memset");
builtin_fn->return_type = g->builtin_types.entry_void;
builtin_fn->param_count = 3;
builtin_fn->param_types = allocate<TypeTableEntry *>(builtin_fn->param_count);
@ -2496,8 +2534,12 @@ static void define_builtin_fns(CodeGen *g) {
assert(LLVMGetIntrinsicID(builtin_fn->fn_val));
g->memset_fn_val = builtin_fn->fn_val;
g->builtin_fn_table.put(&builtin_fn->name, builtin_fn);
}
create_one_arg_builtin_fn(g, BuiltinFnIdSizeof, "sizeof");
create_one_arg_builtin_fn(g, BuiltinFnIdMaxValue, "max_value");
create_one_arg_builtin_fn(g, BuiltinFnIdMinValue, "min_value");
create_one_arg_builtin_fn(g, BuiltinFnIdValueCount, "value_count");
create_one_arg_builtin_fn(g, BuiltinFnIdTypeof, "typeof");
}
@ -2780,9 +2822,8 @@ void codegen_add_root_code(CodeGen *g, Buf *src_dir, Buf *src_basename, Buf *sou
}
static void to_c_type(CodeGen *g, AstNode *type_node, Buf *out_buf) {
assert(type_node->type == NodeTypeType);
TypeTableEntry *type_entry = type_node->data.type.entry;
zig_panic("TODO this function needs some love");
TypeTableEntry *type_entry = get_resolved_expr(type_node)->type_entry;
assert(type_entry);
if (type_entry == g->builtin_types.entry_u8) {

File diff suppressed because it is too large Load Diff

View File

@ -207,8 +207,6 @@ static void end_token(Tokenize *t) {
t->cur_tok->id = TokenIdKeywordConst;
} else if (mem_eql_str(token_mem, token_len, "extern")) {
t->cur_tok->id = TokenIdKeywordExtern;
} else if (mem_eql_str(token_mem, token_len, "unreachable")) {
t->cur_tok->id = TokenIdKeywordUnreachable;
} else if (mem_eql_str(token_mem, token_len, "pub")) {
t->cur_tok->id = TokenIdKeywordPub;
} else if (mem_eql_str(token_mem, token_len, "export")) {
@ -217,8 +215,6 @@ static void end_token(Tokenize *t) {
t->cur_tok->id = TokenIdKeywordAs;
} else if (mem_eql_str(token_mem, token_len, "use")) {
t->cur_tok->id = TokenIdKeywordUse;
} else if (mem_eql_str(token_mem, token_len, "void")) {
t->cur_tok->id = TokenIdKeywordVoid;
} else if (mem_eql_str(token_mem, token_len, "true")) {
t->cur_tok->id = TokenIdKeywordTrue;
} else if (mem_eql_str(token_mem, token_len, "false")) {
@ -553,6 +549,11 @@ void tokenize(Buf *buf, Tokenization *out) {
end_token(&t);
t.state = TokenizeStateStart;
break;
case '>':
t.cur_tok->id = TokenIdFatArrow;
end_token(&t);
t.state = TokenizeStateStart;
break;
default:
t.pos -= 1;
end_token(&t);
@ -1009,12 +1010,10 @@ static const char * token_name(Token *token) {
case TokenIdKeywordVar: return "Var";
case TokenIdKeywordReturn: return "Return";
case TokenIdKeywordExtern: return "Extern";
case TokenIdKeywordUnreachable: return "Unreachable";
case TokenIdKeywordPub: return "Pub";
case TokenIdKeywordExport: return "Export";
case TokenIdKeywordAs: return "As";
case TokenIdKeywordUse: return "Use";
case TokenIdKeywordVoid: return "Void";
case TokenIdKeywordTrue: return "True";
case TokenIdKeywordFalse: return "False";
case TokenIdKeywordIf: return "If";
@ -1044,6 +1043,7 @@ static const char * token_name(Token *token) {
case TokenIdPlus: return "Plus";
case TokenIdColon: return "Colon";
case TokenIdArrow: return "Arrow";
case TokenIdFatArrow: return "FatArrow";
case TokenIdDash: return "Dash";
case TokenIdNumberSign: return "NumberSign";
case TokenIdBinOr: return "BinOr";

View File

@ -18,12 +18,10 @@ enum TokenId {
TokenIdKeywordVar,
TokenIdKeywordConst,
TokenIdKeywordExtern,
TokenIdKeywordUnreachable,
TokenIdKeywordPub,
TokenIdKeywordExport,
TokenIdKeywordAs,
TokenIdKeywordUse,
TokenIdKeywordVoid,
TokenIdKeywordTrue,
TokenIdKeywordFalse,
TokenIdKeywordIf,
@ -53,6 +51,7 @@ enum TokenId {
TokenIdPlus,
TokenIdColon,
TokenIdArrow,
TokenIdFatArrow,
TokenIdDash,
TokenIdNumberSign,
TokenIdBoolOr,

View File

@ -3,10 +3,35 @@ use "syscall.zig";
// The compiler treats this file special by implicitly importing the function `main`
// from the root source file.
var env: &&u8;
#attribute("naked")
export fn _start() -> unreachable {
const argc = asm("mov (%%rsp), %[argc]" : [argc] "=r" (-> isize));
const argv = asm("lea 0x8(%%rsp), %[argv]" : [argv] "=r" (-> &&u8));
const env = asm("lea 0x10(%%rsp,%%rdi,8), %[env]" : [env] "=r" (-> &&u8));
exit(main(argc, argv, env))
export fn _start() unreachable => {
const argc = asm("mov (%%rsp), %[argc]": [argc] "=r" (-> isize));
const argv = asm("lea 0x8(%%rsp), %[argv]": [argv] "=r" (-> &&u8));
env = asm("lea 0x10(%%rsp,%%rdi,8), %[env]": [env] "=r" (-> &&u8));
exit(main(argc, argv, env));
/*
var args = @alloca_array([]u8, argc);
var i : @typeof(argc) = 0;
// TODO for in loop over the array
while (i < argc) {
const ptr = argv[i];
args[i] = ptr[0...strlen(ptr)];
i += 1;
}
exit(main(args))
*/
}
/*
fn strlen(ptr: &u8) isize => {
var count: isize = 0;
while (ptr[count]) {
count += 1;
}
return count;
}
*/

View File

@ -1,8 +1,8 @@
// These functions are provided when not linking against libc because LLVM
// sometimes generates code that calls them.
export fn memset(dest: &u8, c: u8, n: usize) -> &u8 {
var index : #typeof(n) = 0;
export fn memset(dest: &u8, c: u8, n: usize) &u8 => {
var index : @typeof(n) = 0;
while (index != n) {
dest[index] = c;
index += 1;
@ -10,8 +10,8 @@ export fn memset(dest: &u8, c: u8, n: usize) -> &u8 {
return dest;
}
export fn memcpy(dest: &noalias u8, src: &const noalias u8, n: usize) -> &u8 {
var index : #typeof(n) = 0;
export fn memcpy(noalias dest: &u8, noalias src: &const u8, n: usize) &u8 => {
var index : @typeof(n) = 0;
while (index != n) {
dest[index] = src[index];
index += 1;

View File

@ -4,13 +4,13 @@ const ARRAY_SIZE : u16 = 624;
/// Use `rand_init` to initialize this state.
pub struct Rand {
array: [ARRAY_SIZE]u32,
index: #typeof(ARRAY_SIZE),
index: @typeof(ARRAY_SIZE),
/// Initialize random state with the given seed.
pub fn init(r: &Rand, seed: u32) {
pub fn init(r: &Rand, seed: u32) => {
r.index = 0;
r.array[0] = seed;
var i : #typeof(ARRAY_SIZE) = 1;
var i : @typeof(ARRAY_SIZE) = 1;
while (i < ARRAY_SIZE) {
const prev_value : u64 = r.array[i - 1];
r.array[i] = ((prev_value ^ (prev_value << 30)) * 0x6c078965 + i) as u32;
@ -20,7 +20,7 @@ pub struct Rand {
/// Get 32 bits of randomness.
pub fn get_u32(r: &Rand) -> u32 {
pub fn get_u32(r: &Rand) u32 => {
if (r.index == 0) {
r.generate_numbers();
}
@ -37,13 +37,13 @@ pub struct Rand {
}
/// Fill `buf` with randomness.
pub fn get_bytes(r: &Rand, buf: []u8) {
pub fn get_bytes(r: &Rand, buf: []u8) => {
var bytes_left = r.get_bytes_aligned(buf);
if (bytes_left > 0) {
var rand_val_array : [#sizeof(u32)]u8;
*(rand_val_array.ptr as &u32) = r.get_u32();
var rand_val_array : [@sizeof(u32)]u8;
*(rand_val_array.ptr as (&u32)) = r.get_u32();
while (bytes_left > 0) {
buf[buf.len - bytes_left] = rand_val_array[#sizeof(u32) - bytes_left];
buf[buf.len - bytes_left] = rand_val_array[@sizeof(u32) - bytes_left];
bytes_left -= 1;
}
}
@ -51,23 +51,23 @@ pub struct Rand {
/// Get a random unsigned integer with even distribution between `start`
/// inclusive and `end` exclusive.
pub fn range_u64(r: &Rand, start: u64, end: u64) -> u64 {
pub fn range_u64(r: &Rand, start: u64, end: u64) u64 => {
const range = end - start;
const leftover = #max_value(u64) % range;
const upper_bound = #max_value(u64) - leftover;
var rand_val_array : [#sizeof(u64)]u8;
const leftover = @max_value(u64) % range;
const upper_bound = @max_value(u64) - leftover;
var rand_val_array : [@sizeof(u64)]u8;
while (true) {
r.get_bytes_aligned(rand_val_array);
const rand_val = *(rand_val_array.ptr as &u64);
const rand_val = *(rand_val_array.ptr as (&u64));
if (rand_val < upper_bound) {
return start + (rand_val % range);
}
}
}
fn generate_numbers(r: &Rand) {
var i : #typeof(ARRAY_SIZE) = 0;
fn generate_numbers(r: &Rand) => {
var i : @typeof(ARRAY_SIZE) = 0;
while (i < ARRAY_SIZE) {
const y : u32 = (r.array[i] & 0x80000000) + (r.array[(i + 1) % ARRAY_SIZE] & 0x7fffffff);
const untempered : u32 = r.array[(i + 397) % ARRAY_SIZE] ^ (y >> 1);
@ -82,11 +82,11 @@ pub struct Rand {
}
// does not populate the remaining (buf.len % 4) bytes
fn get_bytes_aligned(r: &Rand, buf: []u8) -> usize {
fn get_bytes_aligned(r: &Rand, buf: []u8) usize => {
var bytes_left = buf.len;
while (bytes_left >= 4) {
*(&buf[buf.len - bytes_left] as &u32) = r.get_u32();
bytes_left -= #sizeof(u32);
*(&buf[buf.len - bytes_left] as (&u32)) = r.get_u32();
bytes_left -= @sizeof(u32);
}
return bytes_left;
}

View File

@ -5,25 +5,25 @@ pub const stdout_fileno : isize = 1;
pub const stderr_fileno : isize = 2;
// TODO error handling
pub fn os_get_random_bytes(buf: &u8, count: usize) -> isize {
pub fn os_get_random_bytes(buf: &u8, count: usize) isize => {
getrandom(buf, count, 0)
}
// TODO error handling
// TODO handle buffering and flushing (mutex protected)
pub fn print_str(str: []const u8) -> isize {
pub fn print_str(str: []const u8) isize => {
fprint_str(stdout_fileno, str)
}
// TODO error handling
// TODO handle buffering and flushing (mutex protected)
pub fn fprint_str(fd: isize, str: []const u8) -> isize {
pub fn fprint_str(fd: isize, str: []const u8) isize => {
write(fd, str.ptr, str.len)
}
// TODO handle buffering and flushing (mutex protected)
// TODO error handling
pub fn print_u64(x: u64) -> isize {
pub fn print_u64(x: u64) isize => {
var buf: [max_u64_base10_digits]u8;
const len = buf_print_u64(buf, x);
return write(stdout_fileno, buf.ptr, len);
@ -31,14 +31,14 @@ pub fn print_u64(x: u64) -> isize {
// TODO handle buffering and flushing (mutex protected)
// TODO error handling
pub fn print_i64(x: i64) -> isize {
pub fn print_i64(x: i64) isize => {
var buf: [max_u64_base10_digits]u8;
const len = buf_print_i64(buf, x);
return write(stdout_fileno, buf.ptr, len);
}
// TODO error handling
pub fn readline(buf: []u8, out_len: &usize) -> bool {
pub fn readline(buf: []u8, out_len: &usize) bool => {
const amt_read = read(stdin_fileno, buf.ptr, buf.len);
if (amt_read < 0) {
return true;
@ -48,10 +48,10 @@ pub fn readline(buf: []u8, out_len: &usize) -> bool {
}
// TODO return ?u64 when we support returning struct byval
pub fn parse_u64(buf: []u8, radix: u8, result: &u64) -> bool {
pub fn parse_u64(buf: []u8, radix: u8, result: &u64) bool => {
var x : u64 = 0;
var i : #typeof(buf.len) = 0;
var i : @typeof(buf.len) = 0;
while (i < buf.len) {
const c = buf[i];
const digit = char_to_digit(c);
@ -77,7 +77,7 @@ pub fn parse_u64(buf: []u8, radix: u8, result: &u64) -> bool {
return false;
}
fn char_to_digit(c: u8) -> u8 {
fn char_to_digit(c: u8) u8 => {
if ('0' <= c && c <= '9') {
c - '0'
} else if ('A' <= c && c <= 'Z') {
@ -85,13 +85,13 @@ fn char_to_digit(c: u8) -> u8 {
} else if ('a' <= c && c <= 'z') {
c - 'a' + 10
} else {
#max_value(u8)
@max_value(u8)
}
}
const max_u64_base10_digits: usize = 20;
fn buf_print_i64(out_buf: []u8, x: i64) -> usize {
fn buf_print_i64(out_buf: []u8, x: i64) usize => {
if (x < 0) {
out_buf[0] = '-';
return 1 + buf_print_u64(out_buf[1...], ((-(x + 1)) as u64) + 1);
@ -100,7 +100,7 @@ fn buf_print_i64(out_buf: []u8, x: i64) -> usize {
}
}
fn buf_print_u64(out_buf: []u8, x: u64) -> usize {
fn buf_print_u64(out_buf: []u8, x: u64) usize => {
var buf: [max_u64_base10_digits]u8;
var a = x;
var index = buf.len;

View File

@ -3,34 +3,34 @@ const SYS_write : usize = 1;
const SYS_exit : usize = 60;
const SYS_getrandom : usize = 318;
fn syscall1(number: usize, arg1: usize) -> usize {
fn syscall1(number: usize, arg1: usize) usize => {
asm volatile ("syscall"
: [ret] "={rax}" (-> usize)
: [number] "{rax}" (number), [arg1] "{rdi}" (arg1)
: "rcx", "r11")
}
fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) -> usize {
fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) usize => {
asm volatile ("syscall"
: [ret] "={rax}" (-> usize)
: [number] "{rax}" (number), [arg1] "{rdi}" (arg1), [arg2] "{rsi}" (arg2), [arg3] "{rdx}" (arg3)
: "rcx", "r11")
}
pub fn read(fd: isize, buf: &u8, count: usize) -> isize {
pub fn read(fd: isize, buf: &u8, count: usize) isize => {
syscall3(SYS_read, fd as usize, buf as usize, count) as isize
}
pub fn write(fd: isize, buf: &const u8, count: usize) -> isize {
pub fn write(fd: isize, buf: &const u8, count: usize) isize => {
syscall3(SYS_write, fd as usize, buf as usize, count) as isize
}
pub fn exit(status: i32) -> unreachable {
pub fn exit(status: i32) unreachable => {
syscall1(SYS_exit, status as usize);
unreachable
unreachable{}
}
pub fn getrandom(buf: &u8, count: usize, flags: u32) -> isize {
pub fn getrandom(buf: &u8, count: usize, flags: u32) isize => {
syscall3(SYS_getrandom, buf as usize, count, flags as usize) as isize
}

File diff suppressed because it is too large Load Diff