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 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) ContainerDecl : many(Directive) option(FnVisibleMod) (token(Struct) | token(Enum)) token(Symbol) token(LBrace) many(StructMember) token(RBrace)
StructMember: StructField | FnDecl 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) 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) 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) Directive : token(NumberSign) token(Symbol) token(LParen) token(String) token(RParen)
@ -56,23 +56,11 @@ FnVisibleMod : token(Pub) | token(Export)
FnDecl : FnProto token(Semicolon) FnDecl : FnProto token(Semicolon)
FnDef : FnProto Block FnDef : FnProto token(FatArrow) Block
ParamDeclList : token(LParen) list(ParamDecl, token(Comma)) token(RParen) ParamDeclList : token(LParen) list(ParamDecl, token(Comma)) token(RParen)
ParamDecl : token(Symbol) token(Colon) Type | token(Ellipsis) ParamDecl : option(token(NoAlias)) token(Symbol) token(Colon) UnwrapMaybeExpression | 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
Block : token(LBrace) list(option(Statement), token(Semicolon)) token(RBrace) 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) 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 Expression : BlockExpression | NonBlockExpression
NonBlockExpression : ReturnExpression | AssignmentExpression | AsmExpression NonBlockExpression : ReturnExpression | AssignmentExpression
AsmExpression : token(Asm) option(token(Volatile)) token(LParen) token(String) option(AsmOutput) token(RParen) 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) 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) AsmInputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) Expression token(RParen)
AsmClobbers: token(Colon) list(token(String), token(Comma)) 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 AssignmentExpression : UnwrapMaybeExpression AssignmentOperator UnwrapMaybeExpression | UnwrapMaybeExpression
@ -116,7 +102,7 @@ IfExpression : IfVarExpression | IfBoolExpression
IfBoolExpression : token(If) token(LParen) Expression token(RParen) Expression option(Else) 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 Else : token(Else) Expression
@ -144,11 +130,11 @@ MultiplyExpression : CastExpression MultiplyOperator MultiplyExpression | CastEx
MultiplyOperator : token(Star) | token(Slash) | token(Percent) MultiplyOperator : token(Star) | token(Slash) | token(Percent)
CastExpression : CastExpression token(as) Type | PrefixOpExpression CastExpression : CastExpression token(as) PrimaryExpression | PrefixOpExpression
PrefixOpExpression : PrefixOp PrefixOpExpression | SuffixOpExpression PrefixOpExpression : PrefixOp PrefixOpExpression | SuffixOpExpression
SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression) SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression | ContainerInitExpression)
FieldAccessExpression : token(Dot) token(Symbol) 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)) 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) 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 ## Operator Precedence
``` ```
x() x[] x.y x() x[] x{} x.y
!x -x ~x *x &x &const x !x -x ~x *x &x
as as
* / % * / %
+ - + -

View File

@ -15,8 +15,8 @@ syn keyword zigConditional if else switch
syn keyword zigRepeat while for syn keyword zigRepeat while for
syn keyword zigConstant null syn keyword zigConstant null
syn keyword zigKeyword fn unreachable use void syn keyword zigKeyword fn use
syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 string 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 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 "std.zig";
use "rand.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"); print_str("Welcome to the Guess Number Game in Zig.\n");
var seed : u32; var seed : u32;
const err = os_get_random_bytes(&seed as &u8, #sizeof(u32)); const err = os_get_random_bytes(&seed as (&u8), @sizeof(u32));
if (err != #sizeof(u32)) { if (err != @sizeof(u32)) {
// TODO full error message // TODO full error message
fprint_str(stderr_fileno, "unable to get random bytes\n"); fprint_str(stderr_fileno, "unable to get random bytes\n");
return 1; return 1;

View File

@ -2,7 +2,7 @@ export executable "hello";
use "std.zig"; 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"); print_str("Hello, world!\n");
return 0; return 0;
} }

View File

@ -2,11 +2,10 @@ export executable "hello";
#link("c") #link("c")
extern { extern {
fn printf(__format: &const u8, ...) -> i32; fn printf(__format: &const u8, ...) i32;
fn exit(__status: i32) -> unreachable;
} }
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"); printf(c"Hello, world!\n");
return 0; return 0;
} }

View File

@ -1,16 +1,16 @@
pub struct List#(T: type) { pub struct List#(T: type) {
items: ?&T, items: ?&T,
length: usize, length: isize,
capacity: usize, capacity: isize,
pub fn (l: &List) deinit() { pub fn deinit(l: &List) {
free(l.items); free(l.items);
l.items = None; l.items = null;
} }
pub fn append(l: &List, item: T) -> error { pub fn append(l: &List, item: T) -> error {
const err = l.ensure_capacity(l.length + 1); const err = l.ensure_capacity(l.length + 1);
if err != Error.None { if err != error.None {
return err; return err;
} }
const raw_items = l.items ?? unreachable; const raw_items = l.items ?? unreachable;
@ -47,11 +47,11 @@ pub struct List#(T: type) {
better_capacity *= 2; better_capacity *= 2;
} }
if better_capacity != l.capacity { 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.items = new_items;
l.capacity = better_capacity; 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) { 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"; 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; const x : ?bool = true;
if (const y ?= x) { if (const y ?= x) {
@ -25,7 +25,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
const final_x : ?i32 = 13; const final_x : ?i32 = 13;
const num = final_x ?? unreachable; const num = final_x ?? unreachable{};
if (num != 13) { if (num != 13) {
print_str("BAD\n"); print_str("BAD\n");

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -13,12 +13,13 @@
void semantic_analyze(CodeGen *g); void semantic_analyze(CodeGen *g);
void add_node_error(CodeGen *g, AstNode *node, Buf *msg); void add_node_error(CodeGen *g, AstNode *node, Buf *msg);
TypeTableEntry *new_type_table_entry(TypeTableEntryId id); 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); VariableTableEntry *find_variable(BlockContext *context, Buf *name);
TypeTableEntry *find_container(BlockContext *context, Buf *name); TypeTableEntry *find_container(BlockContext *context, Buf *name);
BlockContext *new_block_context(AstNode *node, BlockContext *parent); BlockContext *new_block_context(AstNode *node, BlockContext *parent);
Expr *get_resolved_expr(AstNode *node); Expr *get_resolved_expr(AstNode *node);
NumLitCodeGen *get_resolved_num_lit(AstNode *node); NumLitCodeGen *get_resolved_num_lit(AstNode *node);
TopLevelDecl *get_resolved_top_level_decl(AstNode *node); TopLevelDecl *get_resolved_top_level_decl(AstNode *node);
bool is_node_void_expr(AstNode *node);
#endif #endif

View File

@ -72,35 +72,35 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType b
LLVMValueRef target_ref, LLVMValueRef value, LLVMValueRef target_ref, LLVMValueRef value,
TypeTableEntry *op1_type, TypeTableEntry *op2_type); TypeTableEntry *op1_type, TypeTableEntry *op2_type);
static TypeTableEntry *get_type_for_type_node(AstNode *node) {
static TypeTableEntry *get_type_for_type_node(CodeGen *g, AstNode *type_node) { TypeTableEntry *meta_type_entry = get_resolved_expr(node)->type_entry;
assert(type_node->type == NodeTypeType); assert(meta_type_entry->id == TypeTableEntryIdMetaType);
return type_node->data.type.entry; return meta_type_entry->data.meta_type.child_type;
} }
static TypeTableEntry *fn_proto_type_from_type_node(CodeGen *g, AstNode *type_node) { 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) { 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 { } else {
return type_entry; return type_entry;
} }
} }
static LLVMZigDIType *to_llvm_debug_type(CodeGen *g, AstNode *type_node) { 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; return type_entry->di_type;
} }
static bool type_is_unreachable(CodeGen *g, AstNode *type_node) { 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) { static bool is_param_decl_type_void(CodeGen *g, AstNode *param_decl_node) {
assert(param_decl_node->type == NodeTypeParamDecl); 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) { 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; 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) { static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeFnCallExpr); assert(node->type == NodeTypeFnCallExpr);
AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; 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) { switch (builtin_fn->id) {
case BuiltinFnIdInvalid: case BuiltinFnIdInvalid:
case BuiltinFnIdTypeof:
zig_unreachable(); zig_unreachable();
case BuiltinFnIdArithmeticWithOverflow: 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, ""); LLVMBuildCall(g->builder, builtin_fn->fn_val, params, 5, "");
return nullptr; 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(); zig_unreachable();
} }
@ -692,6 +787,10 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
add_debug_source_node(g, node); add_debug_source_node(g, node);
return LLVMBuildLoad(g->builder, expr, ""); return LLVMBuildLoad(g->builder, expr, "");
} }
case PrefixOpMaybe:
{
zig_panic("TODO codegen PrefixOpMaybe");
}
} }
zig_unreachable(); zig_unreachable();
} }
@ -1484,35 +1583,46 @@ static LLVMValueRef gen_null_literal(CodeGen *g, AstNode *node) {
return tmp_struct_ptr; return tmp_struct_ptr;
} }
static LLVMValueRef gen_struct_val_expr(CodeGen *g, AstNode *node) { static LLVMValueRef gen_container_init_expr(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeStructValueExpr); assert(node->type == NodeTypeContainerInitExpr);
TypeTableEntry *type_entry = get_expr_type(node); 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; int field_count = type_entry->data.structure.field_count;
assert(field_count == node->data.struct_val_expr.fields.length); assert(field_count == node->data.container_init_expr.entries.length);
StructValExprCodeGen *struct_val_expr_node = &node->data.struct_val_expr.codegen; StructValExprCodeGen *struct_val_expr_node = &node->data.container_init_expr.resolved_struct_val_expr;
LLVMValueRef tmp_struct_ptr = struct_val_expr_node->ptr; LLVMValueRef tmp_struct_ptr = struct_val_expr_node->ptr;
for (int i = 0; i < field_count; i += 1) { for (int i = 0; i < field_count; i += 1) {
AstNode *field_node = node->data.struct_val_expr.fields.at(i); AstNode *field_node = node->data.container_init_expr.entries.at(i);
assert(field_node->type == NodeTypeStructValueField); assert(field_node->type == NodeTypeStructValueField);
TypeStructField *type_struct_field = field_node->data.struct_val_field.type_struct_field; TypeStructField *type_struct_field = field_node->data.struct_val_field.type_struct_field;
if (type_struct_field->type_entry->id == TypeTableEntryIdVoid) { if (type_struct_field->type_entry->id == TypeTableEntryIdVoid) {
continue; 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); return tmp_struct_ptr;
LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, type_struct_field->gen_index, ""); } else if (type_entry->id == TypeTableEntryIdUnreachable) {
LLVMValueRef value = gen_expr(g, field_node->data.struct_val_field.expr); assert(node->data.container_init_expr.entries.length == 0);
LLVMBuildStore(g->builder, value, field_ptr); 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) { 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); 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) { static LLVMValueRef gen_number_literal(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeNumberLiteral); 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); 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) { static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
switch (node->type) { switch (node->type) {
case NodeTypeBinOpExpr: case NodeTypeBinOpExpr:
@ -1766,11 +1822,6 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
return gen_slice_expr(g, node); return gen_slice_expr(g, node);
case NodeTypeFieldAccessExpr: case NodeTypeFieldAccessExpr:
return gen_field_access_expr(g, node, false); 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: case NodeTypeBoolLiteral:
if (node->data.bool_literal.value) if (node->data.bool_literal.value)
return LLVMConstAllOnes(LLVMInt1Type()); return LLVMConstAllOnes(LLVMInt1Type());
@ -1802,29 +1853,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
case NodeTypeCharLiteral: case NodeTypeCharLiteral:
return LLVMConstInt(LLVMInt8Type(), node->data.char_literal.value, false); return LLVMConstInt(LLVMInt8Type(), node->data.char_literal.value, false);
case NodeTypeSymbol: case NodeTypeSymbol:
{ return gen_symbol(g, 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;
}
}
case NodeTypeBlock: case NodeTypeBlock:
return gen_block(g, node, nullptr); return gen_block(g, node, nullptr);
case NodeTypeGoto: case NodeTypeGoto:
@ -1846,24 +1875,21 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
LLVMPositionBuilderAtEnd(g->builder, basic_block); LLVMPositionBuilderAtEnd(g->builder, basic_block);
return nullptr; return nullptr;
} }
case NodeTypeStructValueExpr: case NodeTypeContainerInitExpr:
return gen_struct_val_expr(g, node); return gen_container_init_expr(g, node);
case NodeTypeCompilerFnType:
return gen_compiler_fn_type(g, node);
case NodeTypeRoot: case NodeTypeRoot:
case NodeTypeRootExportDecl: case NodeTypeRootExportDecl:
case NodeTypeFnProto: case NodeTypeFnProto:
case NodeTypeFnDef: case NodeTypeFnDef:
case NodeTypeFnDecl: case NodeTypeFnDecl:
case NodeTypeParamDecl: case NodeTypeParamDecl:
case NodeTypeType:
case NodeTypeExternBlock: case NodeTypeExternBlock:
case NodeTypeDirective: case NodeTypeDirective:
case NodeTypeUse: case NodeTypeUse:
case NodeTypeStructDecl: case NodeTypeStructDecl:
case NodeTypeStructField: case NodeTypeStructField:
case NodeTypeStructValueField: case NodeTypeStructValueField:
case NodeTypeCompilerFnExpr: case NodeTypeArrayType:
zig_unreachable(); zig_unreachable();
} }
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) { static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
LLVMValueRef val = gen_expr_no_cast(g, node); LLVMValueRef val = gen_expr_no_cast(g, node);
if (node->type == NodeTypeVoid) { if (is_node_void_expr(node)) {
return val; return val;
} }
@ -1966,7 +1992,7 @@ static void do_code_gen(CodeGen *g) {
assert(proto_node->type == NodeTypeFnProto); assert(proto_node->type == NodeTypeFnProto);
AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; 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); int param_count = count_non_void_params(g, &fn_proto->params);
LLVMTypeRef *param_types = allocate<LLVMTypeRef>(param_count); LLVMTypeRef *param_types = allocate<LLVMTypeRef>(param_count);
int gen_param_index = 0; 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); TypeTableEntry *param_type = fn_proto_type_from_type_node(g, type_node);
LLVMValueRef argument_val = LLVMGetParam(fn, gen_param_index); LLVMValueRef argument_val = LLVMGetParam(fn, gen_param_index);
if (param_type->id == TypeTableEntryIdPointer && if (param_type->id == TypeTableEntryIdPointer &&
param_type->data.pointer.is_noalias) false) // TODO test if parameter is noalias
{ {
LLVMAddAttribute(argument_val, LLVMNoAliasAttribute); LLVMAddAttribute(argument_val, LLVMNoAliasAttribute);
} else if (param_type->id == TypeTableEntryIdPointer && } else if (param_type->id == TypeTableEntryIdPointer &&
@ -2267,7 +2293,7 @@ static void define_builtin_types(CodeGen *g) {
g->builtin_types.entry_u64 = entry; g->builtin_types.entry_u64 = entry;
g->primitive_type_table.put(&entry->name, 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); TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
entry->type_ref = LLVMInt8Type(); 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 = allocate<TypeTableEntry *>(builtin_fn->param_count);
builtin_fn->param_types[0] = type_entry; builtin_fn->param_types[0] = type_entry;
builtin_fn->param_types[1] = 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 ? 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) { 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_u8);
define_builtin_fns_int(g, g->builtin_types.entry_u16); 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_i32);
define_builtin_fns_int(g, g->builtin_types.entry_i64); define_builtin_fns_int(g, g->builtin_types.entry_i64);
{ {
BuiltinFnEntry *builtin_fn = allocate<BuiltinFnEntry>(1); BuiltinFnEntry *builtin_fn = create_builtin_fn(g, BuiltinFnIdMemcpy, "memcpy");
buf_init_from_str(&builtin_fn->name, "memcpy");
builtin_fn->id = BuiltinFnIdMemcpy;
builtin_fn->return_type = g->builtin_types.entry_void; builtin_fn->return_type = g->builtin_types.entry_void;
builtin_fn->param_count = 3; builtin_fn->param_count = 3;
builtin_fn->param_types = allocate<TypeTableEntry *>(builtin_fn->param_count); 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)); assert(LLVMGetIntrinsicID(builtin_fn->fn_val));
g->memcpy_fn_val = 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); BuiltinFnEntry *builtin_fn = create_builtin_fn(g, BuiltinFnIdMemset, "memset");
buf_init_from_str(&builtin_fn->name, "memset");
builtin_fn->id = BuiltinFnIdMemset;
builtin_fn->return_type = g->builtin_types.entry_void; builtin_fn->return_type = g->builtin_types.entry_void;
builtin_fn->param_count = 3; builtin_fn->param_count = 3;
builtin_fn->param_types = allocate<TypeTableEntry *>(builtin_fn->param_count); 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)); assert(LLVMGetIntrinsicID(builtin_fn->fn_val));
g->memset_fn_val = 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) { static void to_c_type(CodeGen *g, AstNode *type_node, Buf *out_buf) {
assert(type_node->type == NodeTypeType); zig_panic("TODO this function needs some love");
TypeTableEntry *type_entry = get_resolved_expr(type_node)->type_entry;
TypeTableEntry *type_entry = type_node->data.type.entry;
assert(type_entry); assert(type_entry);
if (type_entry == g->builtin_types.entry_u8) { 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; t->cur_tok->id = TokenIdKeywordConst;
} else if (mem_eql_str(token_mem, token_len, "extern")) { } else if (mem_eql_str(token_mem, token_len, "extern")) {
t->cur_tok->id = TokenIdKeywordExtern; 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")) { } else if (mem_eql_str(token_mem, token_len, "pub")) {
t->cur_tok->id = TokenIdKeywordPub; t->cur_tok->id = TokenIdKeywordPub;
} else if (mem_eql_str(token_mem, token_len, "export")) { } 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; t->cur_tok->id = TokenIdKeywordAs;
} else if (mem_eql_str(token_mem, token_len, "use")) { } else if (mem_eql_str(token_mem, token_len, "use")) {
t->cur_tok->id = TokenIdKeywordUse; 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")) { } else if (mem_eql_str(token_mem, token_len, "true")) {
t->cur_tok->id = TokenIdKeywordTrue; t->cur_tok->id = TokenIdKeywordTrue;
} else if (mem_eql_str(token_mem, token_len, "false")) { } else if (mem_eql_str(token_mem, token_len, "false")) {
@ -553,6 +549,11 @@ void tokenize(Buf *buf, Tokenization *out) {
end_token(&t); end_token(&t);
t.state = TokenizeStateStart; t.state = TokenizeStateStart;
break; break;
case '>':
t.cur_tok->id = TokenIdFatArrow;
end_token(&t);
t.state = TokenizeStateStart;
break;
default: default:
t.pos -= 1; t.pos -= 1;
end_token(&t); end_token(&t);
@ -1009,12 +1010,10 @@ static const char * token_name(Token *token) {
case TokenIdKeywordVar: return "Var"; case TokenIdKeywordVar: return "Var";
case TokenIdKeywordReturn: return "Return"; case TokenIdKeywordReturn: return "Return";
case TokenIdKeywordExtern: return "Extern"; case TokenIdKeywordExtern: return "Extern";
case TokenIdKeywordUnreachable: return "Unreachable";
case TokenIdKeywordPub: return "Pub"; case TokenIdKeywordPub: return "Pub";
case TokenIdKeywordExport: return "Export"; case TokenIdKeywordExport: return "Export";
case TokenIdKeywordAs: return "As"; case TokenIdKeywordAs: return "As";
case TokenIdKeywordUse: return "Use"; case TokenIdKeywordUse: return "Use";
case TokenIdKeywordVoid: return "Void";
case TokenIdKeywordTrue: return "True"; case TokenIdKeywordTrue: return "True";
case TokenIdKeywordFalse: return "False"; case TokenIdKeywordFalse: return "False";
case TokenIdKeywordIf: return "If"; case TokenIdKeywordIf: return "If";
@ -1044,6 +1043,7 @@ static const char * token_name(Token *token) {
case TokenIdPlus: return "Plus"; case TokenIdPlus: return "Plus";
case TokenIdColon: return "Colon"; case TokenIdColon: return "Colon";
case TokenIdArrow: return "Arrow"; case TokenIdArrow: return "Arrow";
case TokenIdFatArrow: return "FatArrow";
case TokenIdDash: return "Dash"; case TokenIdDash: return "Dash";
case TokenIdNumberSign: return "NumberSign"; case TokenIdNumberSign: return "NumberSign";
case TokenIdBinOr: return "BinOr"; case TokenIdBinOr: return "BinOr";

View File

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

View File

@ -3,10 +3,35 @@ use "syscall.zig";
// The compiler treats this file special by implicitly importing the function `main` // The compiler treats this file special by implicitly importing the function `main`
// from the root source file. // from the root source file.
var env: &&u8;
#attribute("naked") #attribute("naked")
export fn _start() -> unreachable { export fn _start() unreachable => {
const argc = asm("mov (%%rsp), %[argc]" : [argc] "=r" (-> isize)); const argc = asm("mov (%%rsp), %[argc]": [argc] "=r" (-> isize));
const argv = asm("lea 0x8(%%rsp), %[argv]" : [argv] "=r" (-> &&u8)); const argv = asm("lea 0x8(%%rsp), %[argv]": [argv] "=r" (-> &&u8));
const env = asm("lea 0x10(%%rsp,%%rdi,8), %[env]" : [env] "=r" (-> &&u8)); env = asm("lea 0x10(%%rsp,%%rdi,8), %[env]": [env] "=r" (-> &&u8));
exit(main(argc, argv, env))
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 // These functions are provided when not linking against libc because LLVM
// sometimes generates code that calls them. // sometimes generates code that calls them.
export fn memset(dest: &u8, c: u8, n: usize) -> &u8 { export fn memset(dest: &u8, c: u8, n: usize) &u8 => {
var index : #typeof(n) = 0; var index : @typeof(n) = 0;
while (index != n) { while (index != n) {
dest[index] = c; dest[index] = c;
index += 1; index += 1;
@ -10,8 +10,8 @@ export fn memset(dest: &u8, c: u8, n: usize) -> &u8 {
return dest; return dest;
} }
export fn memcpy(dest: &noalias u8, src: &const noalias u8, n: usize) -> &u8 { export fn memcpy(noalias dest: &u8, noalias src: &const u8, n: usize) &u8 => {
var index : #typeof(n) = 0; var index : @typeof(n) = 0;
while (index != n) { while (index != n) {
dest[index] = src[index]; dest[index] = src[index];
index += 1; index += 1;

View File

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

View File

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

View File

@ -3,34 +3,34 @@ const SYS_write : usize = 1;
const SYS_exit : usize = 60; const SYS_exit : usize = 60;
const SYS_getrandom : usize = 318; const SYS_getrandom : usize = 318;
fn syscall1(number: usize, arg1: usize) -> usize { fn syscall1(number: usize, arg1: usize) usize => {
asm volatile ("syscall" asm volatile ("syscall"
: [ret] "={rax}" (-> usize) : [ret] "={rax}" (-> usize)
: [number] "{rax}" (number), [arg1] "{rdi}" (arg1) : [number] "{rax}" (number), [arg1] "{rdi}" (arg1)
: "rcx", "r11") : "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" asm volatile ("syscall"
: [ret] "={rax}" (-> usize) : [ret] "={rax}" (-> usize)
: [number] "{rax}" (number), [arg1] "{rdi}" (arg1), [arg2] "{rsi}" (arg2), [arg3] "{rdx}" (arg3) : [number] "{rax}" (number), [arg1] "{rdi}" (arg1), [arg2] "{rsi}" (arg2), [arg3] "{rdx}" (arg3)
: "rcx", "r11") : "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 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 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); 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 syscall3(SYS_getrandom, buf as usize, count, flags as usize) as isize
} }

File diff suppressed because it is too large Load Diff