parent
cb46d0b5b0
commit
b28b7f63d1
@ -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
|
||||||
* / %
|
* / %
|
||||||
+ -
|
+ -
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
7
example/cat/main.zig
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export executable "cat";
|
||||||
|
|
||||||
|
pub main(argv: [][]u8) -> i32 {
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -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:
|
|
||||||
}
|
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -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");
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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"); }
|
|
||||||
}
|
|
@ -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 {
|
||||||
|
1234
src/analyze.cpp
1234
src/analyze.cpp
File diff suppressed because it is too large
Load Diff
@ -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
|
||||||
|
355
src/codegen.cpp
355
src/codegen.cpp
@ -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) {
|
||||||
|
955
src/parser.cpp
955
src/parser.cpp
File diff suppressed because it is too large
Load Diff
@ -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";
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
@ -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;
|
||||||
|
36
std/rand.zig
36
std/rand.zig
@ -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;
|
||||||
}
|
}
|
||||||
|
24
std/std.zig
24
std/std.zig
@ -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;
|
||||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user