parent
cb46d0b5b0
commit
b28b7f63d1
@ -34,13 +34,13 @@ Root : many(TopLevelDecl) token(EOF)
|
||||
|
||||
TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | ContainerDecl | VariableDeclaration
|
||||
|
||||
VariableDeclaration : option(FnVisibleMod) (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) Type option(token(Eq) Expression))
|
||||
VariableDeclaration : option(FnVisibleMod) (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) UnwrapMaybeExpression option(token(Eq) Expression))
|
||||
|
||||
ContainerDecl : many(Directive) option(FnVisibleMod) (token(Struct) | token(Enum)) token(Symbol) token(LBrace) many(StructMember) token(RBrace)
|
||||
|
||||
StructMember: StructField | FnDecl
|
||||
|
||||
StructField : token(Symbol) option(token(Colon) Type token(Comma))
|
||||
StructField : token(Symbol) option(token(Colon) Expression) token(Comma))
|
||||
|
||||
Use : many(Directive) token(Use) token(String) token(Semicolon)
|
||||
|
||||
@ -48,7 +48,7 @@ RootExportDecl : many(Directive) token(Export) token(Symbol) token(String) token
|
||||
|
||||
ExternBlock : many(Directive) token(Extern) token(LBrace) many(FnDecl) token(RBrace)
|
||||
|
||||
FnProto : many(Directive) option(FnVisibleMod) token(Fn) token(Symbol) ParamDeclList option(token(Arrow) Type)
|
||||
FnProto : many(Directive) option(FnVisibleMod) token(Fn) token(Symbol) ParamDeclList option(Expression)
|
||||
|
||||
Directive : token(NumberSign) token(Symbol) token(LParen) token(String) token(RParen)
|
||||
|
||||
@ -56,23 +56,11 @@ FnVisibleMod : token(Pub) | token(Export)
|
||||
|
||||
FnDecl : FnProto token(Semicolon)
|
||||
|
||||
FnDef : FnProto Block
|
||||
FnDef : FnProto token(FatArrow) Block
|
||||
|
||||
ParamDeclList : token(LParen) list(ParamDecl, token(Comma)) token(RParen)
|
||||
|
||||
ParamDecl : token(Symbol) token(Colon) Type | token(Ellipsis)
|
||||
|
||||
Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType | MaybeType | CompilerFnExpr
|
||||
|
||||
CompilerFnExpr : token(NumberSign) token(Symbol) token(LParen) Expression token(RParen)
|
||||
|
||||
CompilerFnType : token(NumberSign) token(Symbol) token(LParen) Type token(RParen)
|
||||
|
||||
PointerType : token(Ampersand) option(token(Const)) option(token(NoAlias)) Type
|
||||
|
||||
MaybeType : token(Question) Type
|
||||
|
||||
ArrayType : token(LBracket) option(Expression) token(RBracket) option(token(Const)) option(token(NoAlias)) Type
|
||||
ParamDecl : option(token(NoAlias)) token(Symbol) token(Colon) UnwrapMaybeExpression | token(Ellipsis)
|
||||
|
||||
Block : token(LBrace) list(option(Statement), token(Semicolon)) token(RBrace)
|
||||
|
||||
@ -80,11 +68,9 @@ Statement : Label | VariableDeclaration token(Semicolon) | NonBlockExpression to
|
||||
|
||||
Label: token(Symbol) token(Colon)
|
||||
|
||||
VariableDeclaration : (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) Type option(token(Eq) Expression))
|
||||
|
||||
Expression : BlockExpression | NonBlockExpression
|
||||
|
||||
NonBlockExpression : ReturnExpression | AssignmentExpression | AsmExpression
|
||||
NonBlockExpression : ReturnExpression | AssignmentExpression
|
||||
|
||||
AsmExpression : token(Asm) option(token(Volatile)) token(LParen) token(String) option(AsmOutput) token(RParen)
|
||||
|
||||
@ -92,13 +78,13 @@ AsmOutput : token(Colon) list(AsmOutputItem, token(Comma)) option(AsmInput)
|
||||
|
||||
AsmInput : token(Colon) list(AsmInputItem, token(Comma)) option(AsmClobbers)
|
||||
|
||||
AsmOutputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) (token(Symbol) | token(Arrow) Type) token(RParen)
|
||||
AsmOutputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) (token(Symbol) | token(Arrow) Expression) token(RParen)
|
||||
|
||||
AsmInputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) Expression token(RParen)
|
||||
|
||||
AsmClobbers: token(Colon) list(token(String), token(Comma))
|
||||
|
||||
UnwrapMaybeExpression : BoolOrExpression token(DoubleQuestion) BoolOrExpression | BoolOrExpression
|
||||
UnwrapMaybeExpression : BoolOrExpression token(DoubleQuestionMark) BoolOrExpression | BoolOrExpression
|
||||
|
||||
AssignmentExpression : UnwrapMaybeExpression AssignmentOperator UnwrapMaybeExpression | UnwrapMaybeExpression
|
||||
|
||||
@ -116,7 +102,7 @@ IfExpression : IfVarExpression | IfBoolExpression
|
||||
|
||||
IfBoolExpression : token(If) token(LParen) Expression token(RParen) Expression option(Else)
|
||||
|
||||
IfVarExpression : token(If) token(LParen) (token(Const) | token(Var)) token(Symbol) option(token(Colon) Type) Token(MaybeAssign) Expression token(RParen) Expression Option(Else)
|
||||
IfVarExpression : token(If) token(LParen) (token(Const) | token(Var)) token(Symbol) option(token(Colon) Expression) Token(MaybeAssign) Expression token(RParen) Expression Option(Else)
|
||||
|
||||
Else : token(Else) Expression
|
||||
|
||||
@ -144,11 +130,11 @@ MultiplyExpression : CastExpression MultiplyOperator MultiplyExpression | CastEx
|
||||
|
||||
MultiplyOperator : token(Star) | token(Slash) | token(Percent)
|
||||
|
||||
CastExpression : CastExpression token(as) Type | PrefixOpExpression
|
||||
CastExpression : CastExpression token(as) PrimaryExpression | PrefixOpExpression
|
||||
|
||||
PrefixOpExpression : PrefixOp PrefixOpExpression | SuffixOpExpression
|
||||
|
||||
SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
|
||||
SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression | ContainerInitExpression)
|
||||
|
||||
FieldAccessExpression : token(Dot) token(Symbol)
|
||||
|
||||
@ -158,26 +144,30 @@ ArrayAccessExpression : token(LBracket) Expression token(RBracket)
|
||||
|
||||
SliceExpression : token(LBracket) Expression token(Ellipsis) option(Expression) token(RBracket) option(token(Const))
|
||||
|
||||
PrefixOp : token(Not) | token(Dash) | token(Tilde) | token(Star) | (token(Ampersand) option(token(Const)))
|
||||
ContainerInitExpression : token(LBrace) ContainerInitBody token(RBrace)
|
||||
|
||||
PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression | CompilerFnType | (token(AtSign) token(Symbol) FnCallExpression)
|
||||
ContainerInitBody : list(StructLiteralField, token(Comma)) | list(Expression, token(Comma))
|
||||
|
||||
StructValueExpression : token(Type) token(LBrace) list(StructValueExpressionField, token(Comma)) token(RBrace)
|
||||
StructLiteralField : token(Dot) token(Symbol) token(Eq) Expression
|
||||
|
||||
StructValueExpressionField : token(Dot) token(Symbol) token(Eq) Expression
|
||||
PrefixOp : token(Not) | token(Dash) | token(Tilde) | token(Star) | (token(Ampersand) option(token(Const))) | token(QuestionMark)
|
||||
|
||||
Goto: token(Goto) token(Symbol)
|
||||
PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | token(Symbol) | (token(AtSign) token(Symbol) FnCallExpression) | ArrayType | AsmExpression
|
||||
|
||||
ArrayType : token(LBracket) option(Expression) token(RBracket) option(token(Const)) Expression
|
||||
|
||||
GotoExpression: token(Goto) token(Symbol)
|
||||
|
||||
GroupedExpression : token(LParen) Expression token(RParen)
|
||||
|
||||
KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False) | token(Null)
|
||||
KeywordLiteral : token(True) | token(False) | token(Null) | token(Break) | token(Continue)
|
||||
```
|
||||
|
||||
## Operator Precedence
|
||||
|
||||
```
|
||||
x() x[] x.y
|
||||
!x -x ~x *x &x &const x
|
||||
x() x[] x{} x.y
|
||||
!x -x ~x *x &x
|
||||
as
|
||||
* / %
|
||||
+ -
|
||||
|
@ -15,8 +15,8 @@ syn keyword zigConditional if else switch
|
||||
syn keyword zigRepeat while for
|
||||
|
||||
syn keyword zigConstant null
|
||||
syn keyword zigKeyword fn unreachable use void
|
||||
syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 string
|
||||
syn keyword zigKeyword fn use
|
||||
syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 string void unreachable
|
||||
|
||||
syn keyword zigBoolean true false
|
||||
|
||||
|
@ -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 "rand.zig";
|
||||
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
print_str("Welcome to the Guess Number Game in Zig.\n");
|
||||
|
||||
var seed : u32;
|
||||
const err = os_get_random_bytes(&seed as &u8, #sizeof(u32));
|
||||
if (err != #sizeof(u32)) {
|
||||
const err = os_get_random_bytes(&seed as (&u8), @sizeof(u32));
|
||||
if (err != @sizeof(u32)) {
|
||||
// TODO full error message
|
||||
fprint_str(stderr_fileno, "unable to get random bytes\n");
|
||||
return 1;
|
||||
|
@ -2,7 +2,7 @@ export executable "hello";
|
||||
|
||||
use "std.zig";
|
||||
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
print_str("Hello, world!\n");
|
||||
return 0;
|
||||
}
|
||||
|
@ -2,11 +2,10 @@ export executable "hello";
|
||||
|
||||
#link("c")
|
||||
extern {
|
||||
fn printf(__format: &const u8, ...) -> i32;
|
||||
fn exit(__status: i32) -> unreachable;
|
||||
fn printf(__format: &const u8, ...) i32;
|
||||
}
|
||||
|
||||
export fn main(argc: i32, argv: &&u8, env: &&u8) -> i32 {
|
||||
export fn main(argc: i32, argv: &&u8, env: &&u8) i32 => {
|
||||
printf(c"Hello, world!\n");
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
pub struct List#(T: type) {
|
||||
items: ?&T,
|
||||
length: usize,
|
||||
capacity: usize,
|
||||
length: isize,
|
||||
capacity: isize,
|
||||
|
||||
pub fn (l: &List) deinit() {
|
||||
pub fn deinit(l: &List) {
|
||||
free(l.items);
|
||||
l.items = None;
|
||||
l.items = null;
|
||||
}
|
||||
|
||||
pub fn append(l: &List, item: T) -> error {
|
||||
const err = l.ensure_capacity(l.length + 1);
|
||||
if err != Error.None {
|
||||
if err != error.None {
|
||||
return err;
|
||||
}
|
||||
const raw_items = l.items ?? unreachable;
|
||||
@ -47,11 +47,11 @@ pub struct List#(T: type) {
|
||||
better_capacity *= 2;
|
||||
}
|
||||
if better_capacity != l.capacity {
|
||||
const new_items = realloc(l.items, better_capacity) ?? { return Error.NoMem };
|
||||
const new_items = realloc(l.items, better_capacity) ?? { return error.NoMem };
|
||||
l.items = new_items;
|
||||
l.capacity = better_capacity;
|
||||
}
|
||||
Error.None
|
||||
error.None
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,3 +64,41 @@ pub fn realloc#(T: type)(ptr: ?&T, new_count: usize) -> ?&T {
|
||||
pub fn free#(T: type)(ptr: ?&T) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
////////////////// alternate
|
||||
|
||||
// previously proposed, but with : instead of ->
|
||||
// `:` means "parser should expect a type now"
|
||||
fn max#(T :type)(a :T, b :T) :T {
|
||||
if (a > b) a else b
|
||||
}
|
||||
|
||||
// andy's new idea
|
||||
// parameters can talk about @typeof() for previous parameters.
|
||||
// using :T here is equivalent to @child_type(@typeof(T))
|
||||
fn max(T :type, a :T, b :T) :T {
|
||||
if (a > b) a else b
|
||||
}
|
||||
|
||||
fn f() {
|
||||
const x :i32 = 1234;
|
||||
const y :i32 = 5678;
|
||||
const z = max(@typeof(x), x, y);
|
||||
}
|
||||
|
||||
// So, type-generic functions don't need any fancy syntax. type-generic
|
||||
// containers still do, though:
|
||||
|
||||
pub struct List(T :type) {
|
||||
items :?&T,
|
||||
length :isize,
|
||||
capacity :isize,
|
||||
}
|
||||
|
||||
// Types are always marked with ':' so we don't need '#' to indicate type generic parameters.
|
||||
|
||||
fn f() {
|
||||
var list :List(:u8);
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@ export executable "maybe_type";
|
||||
|
||||
use "std.zig";
|
||||
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
const x : ?bool = true;
|
||||
|
||||
if (const y ?= x) {
|
||||
@ -25,7 +25,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
|
||||
|
||||
const final_x : ?i32 = 13;
|
||||
|
||||
const num = final_x ?? unreachable;
|
||||
const num = final_x ?? unreachable{};
|
||||
|
||||
if (num != 13) {
|
||||
print_str("BAD\n");
|
||||
|
@ -2,10 +2,10 @@ use "std.zig";
|
||||
|
||||
// purposefully conflicting function with main.zig
|
||||
// but it's private so it should be OK
|
||||
fn private_function() {
|
||||
fn private_function() => {
|
||||
print_str("OK 1\n");
|
||||
}
|
||||
|
||||
pub fn print_text() {
|
||||
pub fn print_text() => {
|
||||
private_function();
|
||||
}
|
||||
|
@ -3,12 +3,12 @@ export executable "test-multiple-files";
|
||||
use "std.zig";
|
||||
use "foo.zig";
|
||||
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
private_function();
|
||||
print_str("OK 2\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn private_function() {
|
||||
fn private_function() => {
|
||||
print_text();
|
||||
}
|
||||
|
@ -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,
|
||||
NodeTypeFnDecl,
|
||||
NodeTypeParamDecl,
|
||||
NodeTypeType,
|
||||
NodeTypeBlock,
|
||||
NodeTypeExternBlock,
|
||||
NodeTypeDirective,
|
||||
@ -111,7 +110,6 @@ enum NodeType {
|
||||
NodeTypeNumberLiteral,
|
||||
NodeTypeStringLiteral,
|
||||
NodeTypeCharLiteral,
|
||||
NodeTypeUnreachable,
|
||||
NodeTypeSymbol,
|
||||
NodeTypePrefixOpExpr,
|
||||
NodeTypeFnCallExpr,
|
||||
@ -119,7 +117,6 @@ enum NodeType {
|
||||
NodeTypeSliceExpr,
|
||||
NodeTypeFieldAccessExpr,
|
||||
NodeTypeUse,
|
||||
NodeTypeVoid,
|
||||
NodeTypeBoolLiteral,
|
||||
NodeTypeNullLiteral,
|
||||
NodeTypeIfBoolExpr,
|
||||
@ -132,10 +129,9 @@ enum NodeType {
|
||||
NodeTypeAsmExpr,
|
||||
NodeTypeStructDecl,
|
||||
NodeTypeStructField,
|
||||
NodeTypeStructValueExpr,
|
||||
NodeTypeContainerInitExpr,
|
||||
NodeTypeStructValueField,
|
||||
NodeTypeCompilerFnExpr,
|
||||
NodeTypeCompilerFnType,
|
||||
NodeTypeArrayType,
|
||||
};
|
||||
|
||||
struct AstNodeRoot {
|
||||
@ -185,32 +181,12 @@ struct AstNodeFnDecl {
|
||||
struct AstNodeParamDecl {
|
||||
Buf name;
|
||||
AstNode *type;
|
||||
bool is_noalias;
|
||||
|
||||
// populated by semantic analyzer
|
||||
VariableTableEntry *variable;
|
||||
};
|
||||
|
||||
enum AstNodeTypeType {
|
||||
AstNodeTypeTypePrimitive,
|
||||
AstNodeTypeTypePointer,
|
||||
AstNodeTypeTypeArray,
|
||||
AstNodeTypeTypeMaybe,
|
||||
AstNodeTypeTypeCompilerExpr,
|
||||
};
|
||||
|
||||
struct AstNodeType {
|
||||
AstNodeTypeType type;
|
||||
Buf primitive_name;
|
||||
AstNode *child_type;
|
||||
AstNode *array_size; // can be null
|
||||
bool is_const;
|
||||
bool is_noalias;
|
||||
AstNode *compiler_expr;
|
||||
|
||||
// populated by semantic analyzer
|
||||
TypeTableEntry *entry;
|
||||
};
|
||||
|
||||
struct AstNodeBlock {
|
||||
ZigList<AstNode *> statements;
|
||||
|
||||
@ -295,6 +271,7 @@ struct AstNodeFnCallExpr {
|
||||
// populated by semantic analyzer:
|
||||
BuiltinFnEntry *builtin_fn;
|
||||
Expr resolved_expr;
|
||||
NumLitCodeGen resolved_num_lit;
|
||||
};
|
||||
|
||||
struct AstNodeArrayAccessExpr {
|
||||
@ -360,6 +337,7 @@ enum PrefixOp {
|
||||
PrefixOpAddressOf,
|
||||
PrefixOpConstAddressOf,
|
||||
PrefixOpDereference,
|
||||
PrefixOpMaybe,
|
||||
};
|
||||
|
||||
struct AstNodePrefixOpExpr {
|
||||
@ -537,45 +515,24 @@ struct AstNodeStructValueField {
|
||||
TypeStructField *type_struct_field;
|
||||
};
|
||||
|
||||
struct AstNodeStructValueExpr {
|
||||
enum ContainerInitKind {
|
||||
ContainerInitKindStruct,
|
||||
ContainerInitKindArray,
|
||||
};
|
||||
|
||||
struct AstNodeContainerInitExpr {
|
||||
AstNode *type;
|
||||
ZigList<AstNode *> fields;
|
||||
ZigList<AstNode *> entries;
|
||||
ContainerInitKind kind;
|
||||
|
||||
// populated by semantic analyzer
|
||||
StructValExprCodeGen codegen;
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeCompilerFnExpr {
|
||||
Buf name;
|
||||
AstNode *expr;
|
||||
|
||||
// populated by semantic analyzer
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeCompilerFnType {
|
||||
Buf name;
|
||||
AstNode *type;
|
||||
|
||||
// populated by semantic analyzer
|
||||
Expr resolved_expr;
|
||||
NumLitCodeGen resolved_num_lit;
|
||||
};
|
||||
|
||||
struct AstNodeNullLiteral {
|
||||
// populated by semantic analyzer
|
||||
StructValExprCodeGen resolved_struct_val_expr;
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeVoidExpr {
|
||||
// populated by semantic analyzer
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeUnreachableExpr {
|
||||
struct AstNodeNullLiteral {
|
||||
// populated by semantic analyzer
|
||||
StructValExprCodeGen resolved_struct_val_expr;
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
@ -603,6 +560,15 @@ struct AstNodeContinueExpr {
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeArrayType {
|
||||
AstNode *size;
|
||||
AstNode *child_type;
|
||||
bool is_const;
|
||||
|
||||
// populated by semantic analyzer
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNode {
|
||||
enum NodeType type;
|
||||
int line;
|
||||
@ -615,7 +581,6 @@ struct AstNode {
|
||||
AstNodeFnDef fn_def;
|
||||
AstNodeFnDecl fn_decl;
|
||||
AstNodeFnProto fn_proto;
|
||||
AstNodeType type;
|
||||
AstNodeParamDecl param_decl;
|
||||
AstNodeBlock block;
|
||||
AstNodeReturnExpr return_expr;
|
||||
@ -641,17 +606,14 @@ struct AstNode {
|
||||
AstNodeStringLiteral string_literal;
|
||||
AstNodeCharLiteral char_literal;
|
||||
AstNodeNumberLiteral number_literal;
|
||||
AstNodeStructValueExpr struct_val_expr;
|
||||
AstNodeContainerInitExpr container_init_expr;
|
||||
AstNodeStructValueField struct_val_field;
|
||||
AstNodeCompilerFnExpr compiler_fn_expr;
|
||||
AstNodeCompilerFnType compiler_fn_type;
|
||||
AstNodeNullLiteral null_literal;
|
||||
AstNodeVoidExpr void_expr;
|
||||
AstNodeUnreachableExpr unreachable_expr;
|
||||
AstNodeSymbolExpr symbol_expr;
|
||||
AstNodeBoolLiteral bool_literal;
|
||||
AstNodeBreakExpr break_expr;
|
||||
AstNodeContinueExpr continue_expr;
|
||||
AstNodeArrayType array_type;
|
||||
} data;
|
||||
};
|
||||
|
||||
@ -670,7 +632,6 @@ struct AsmToken {
|
||||
struct TypeTableEntryPointer {
|
||||
TypeTableEntry *child_type;
|
||||
bool is_const;
|
||||
bool is_noalias;
|
||||
};
|
||||
|
||||
struct TypeTableEntryInt {
|
||||
@ -770,8 +731,8 @@ struct TypeTableEntry {
|
||||
} data;
|
||||
|
||||
// use these fields to make sure we don't duplicate type table entries for the same type
|
||||
TypeTableEntry *pointer_parent[2][2]; // 0 - const. 1 - noalias
|
||||
TypeTableEntry *unknown_size_array_parent[2][2]; // 0 - const. 1 - noalias
|
||||
TypeTableEntry *pointer_parent[2];
|
||||
TypeTableEntry *unknown_size_array_parent[2];
|
||||
HashMap<uint64_t, TypeTableEntry *, uint64_hash, uint64_eq> arrays_by_size;
|
||||
TypeTableEntry *maybe_parent;
|
||||
TypeTableEntry *meta_parent;
|
||||
@ -830,6 +791,11 @@ enum BuiltinFnId {
|
||||
BuiltinFnIdArithmeticWithOverflow,
|
||||
BuiltinFnIdMemcpy,
|
||||
BuiltinFnIdMemset,
|
||||
BuiltinFnIdSizeof,
|
||||
BuiltinFnIdMaxValue,
|
||||
BuiltinFnIdMinValue,
|
||||
BuiltinFnIdValueCount,
|
||||
BuiltinFnIdTypeof,
|
||||
};
|
||||
|
||||
struct BuiltinFnEntry {
|
||||
|
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 add_node_error(CodeGen *g, AstNode *node, Buf *msg);
|
||||
TypeTableEntry *new_type_table_entry(TypeTableEntryId id);
|
||||
TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const, bool is_noalias);
|
||||
TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
|
||||
VariableTableEntry *find_variable(BlockContext *context, Buf *name);
|
||||
TypeTableEntry *find_container(BlockContext *context, Buf *name);
|
||||
BlockContext *new_block_context(AstNode *node, BlockContext *parent);
|
||||
Expr *get_resolved_expr(AstNode *node);
|
||||
NumLitCodeGen *get_resolved_num_lit(AstNode *node);
|
||||
TopLevelDecl *get_resolved_top_level_decl(AstNode *node);
|
||||
bool is_node_void_expr(AstNode *node);
|
||||
|
||||
#endif
|
||||
|
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,
|
||||
TypeTableEntry *op1_type, TypeTableEntry *op2_type);
|
||||
|
||||
|
||||
static TypeTableEntry *get_type_for_type_node(CodeGen *g, AstNode *type_node) {
|
||||
assert(type_node->type == NodeTypeType);
|
||||
return type_node->data.type.entry;
|
||||
static TypeTableEntry *get_type_for_type_node(AstNode *node) {
|
||||
TypeTableEntry *meta_type_entry = get_resolved_expr(node)->type_entry;
|
||||
assert(meta_type_entry->id == TypeTableEntryIdMetaType);
|
||||
return meta_type_entry->data.meta_type.child_type;
|
||||
}
|
||||
|
||||
static TypeTableEntry *fn_proto_type_from_type_node(CodeGen *g, AstNode *type_node) {
|
||||
TypeTableEntry *type_entry = get_type_for_type_node(g, type_node);
|
||||
TypeTableEntry *type_entry = get_type_for_type_node(type_node);
|
||||
|
||||
if (type_entry->id == TypeTableEntryIdStruct || type_entry->id == TypeTableEntryIdArray) {
|
||||
return get_pointer_to_type(g, type_entry, true, true);
|
||||
return get_pointer_to_type(g, type_entry, true);
|
||||
} else {
|
||||
return type_entry;
|
||||
}
|
||||
}
|
||||
|
||||
static LLVMZigDIType *to_llvm_debug_type(CodeGen *g, AstNode *type_node) {
|
||||
TypeTableEntry *type_entry = get_type_for_type_node(g, type_node);
|
||||
TypeTableEntry *type_entry = get_type_for_type_node(type_node);
|
||||
return type_entry->di_type;
|
||||
}
|
||||
|
||||
|
||||
static bool type_is_unreachable(CodeGen *g, AstNode *type_node) {
|
||||
return get_type_for_type_node(g, type_node)->id == TypeTableEntryIdUnreachable;
|
||||
return get_type_for_type_node(type_node)->id == TypeTableEntryIdUnreachable;
|
||||
}
|
||||
|
||||
static bool is_param_decl_type_void(CodeGen *g, AstNode *param_decl_node) {
|
||||
assert(param_decl_node->type == NodeTypeParamDecl);
|
||||
return get_type_for_type_node(g, param_decl_node->data.param_decl.type)->id == TypeTableEntryIdVoid;
|
||||
return get_type_for_type_node(param_decl_node->data.param_decl.type)->id == TypeTableEntryIdVoid;
|
||||
}
|
||||
|
||||
static int count_non_void_params(CodeGen *g, ZigList<AstNode *> *params) {
|
||||
@ -146,6 +146,32 @@ static TypeTableEntry *get_expr_type(AstNode *node) {
|
||||
return expr->type_entry;
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_number_literal_raw(CodeGen *g, AstNode *source_node,
|
||||
NumLitCodeGen *codegen_num_lit, AstNodeNumberLiteral *num_lit_node)
|
||||
{
|
||||
TypeTableEntry *type_entry = codegen_num_lit->resolved_type;
|
||||
assert(type_entry);
|
||||
|
||||
// override the expression type for number literals
|
||||
get_resolved_expr(source_node)->type_entry = type_entry;
|
||||
|
||||
if (type_entry->id == TypeTableEntryIdInt) {
|
||||
// here the union has int64_t and uint64_t and we purposefully read
|
||||
// the uint64_t value in either case, because we want the twos
|
||||
// complement representation
|
||||
|
||||
return LLVMConstInt(type_entry->type_ref,
|
||||
num_lit_node->data.x_uint,
|
||||
type_entry->data.integral.is_signed);
|
||||
} else if (type_entry->id == TypeTableEntryIdFloat) {
|
||||
|
||||
return LLVMConstReal(type_entry->type_ref,
|
||||
num_lit_node->data.x_float);
|
||||
} else {
|
||||
zig_panic("bad number literal type");
|
||||
}
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
|
||||
assert(node->type == NodeTypeFnCallExpr);
|
||||
AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
|
||||
@ -154,6 +180,7 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
|
||||
|
||||
switch (builtin_fn->id) {
|
||||
case BuiltinFnIdInvalid:
|
||||
case BuiltinFnIdTypeof:
|
||||
zig_unreachable();
|
||||
case BuiltinFnIdArithmeticWithOverflow:
|
||||
{
|
||||
@ -238,6 +265,74 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
|
||||
LLVMBuildCall(g->builder, builtin_fn->fn_val, params, 5, "");
|
||||
return nullptr;
|
||||
}
|
||||
case BuiltinFnIdSizeof:
|
||||
{
|
||||
assert(node->data.fn_call_expr.params.length == 1);
|
||||
AstNode *type_node = node->data.fn_call_expr.params.at(0);
|
||||
TypeTableEntry *type_entry = get_type_for_type_node(type_node);
|
||||
|
||||
NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node);
|
||||
AstNodeNumberLiteral num_lit_node;
|
||||
num_lit_node.kind = NumLitU64; // this field isn't even read
|
||||
num_lit_node.overflow = false;
|
||||
num_lit_node.data.x_uint = type_entry->size_in_bits / 8;
|
||||
return gen_number_literal_raw(g, node, codegen_num_lit, &num_lit_node);
|
||||
}
|
||||
case BuiltinFnIdMinValue:
|
||||
{
|
||||
assert(node->data.fn_call_expr.params.length == 1);
|
||||
AstNode *type_node = node->data.fn_call_expr.params.at(0);
|
||||
TypeTableEntry *type_entry = get_type_for_type_node(type_node);
|
||||
|
||||
|
||||
if (type_entry->id == TypeTableEntryIdInt) {
|
||||
if (type_entry->data.integral.is_signed) {
|
||||
return LLVMConstInt(type_entry->type_ref, 1ULL << (type_entry->size_in_bits - 1), false);
|
||||
} else {
|
||||
return LLVMConstNull(type_entry->type_ref);
|
||||
}
|
||||
} else if (type_entry->id == TypeTableEntryIdFloat) {
|
||||
zig_panic("TODO codegen min_value float");
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
case BuiltinFnIdMaxValue:
|
||||
{
|
||||
assert(node->data.fn_call_expr.params.length == 1);
|
||||
AstNode *type_node = node->data.fn_call_expr.params.at(0);
|
||||
TypeTableEntry *type_entry = get_type_for_type_node(type_node);
|
||||
|
||||
|
||||
if (type_entry->id == TypeTableEntryIdInt) {
|
||||
if (type_entry->data.integral.is_signed) {
|
||||
return LLVMConstInt(type_entry->type_ref, (1ULL << (type_entry->size_in_bits - 1)) - 1, false);
|
||||
} else {
|
||||
return LLVMConstAllOnes(type_entry->type_ref);
|
||||
}
|
||||
} else if (type_entry->id == TypeTableEntryIdFloat) {
|
||||
zig_panic("TODO codegen max_value float");
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
case BuiltinFnIdValueCount:
|
||||
{
|
||||
assert(node->data.fn_call_expr.params.length == 1);
|
||||
AstNode *type_node = node->data.fn_call_expr.params.at(0);
|
||||
TypeTableEntry *type_entry = get_type_for_type_node(type_node);
|
||||
|
||||
if (type_entry->id == TypeTableEntryIdEnum) {
|
||||
NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node);
|
||||
AstNodeNumberLiteral num_lit_node;
|
||||
num_lit_node.kind = NumLitU64; // field ignored
|
||||
num_lit_node.overflow = false;
|
||||
num_lit_node.data.x_uint = type_entry->data.enumeration.field_count;
|
||||
return gen_number_literal_raw(g, node, codegen_num_lit, &num_lit_node);
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -692,6 +787,10 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
|
||||
add_debug_source_node(g, node);
|
||||
return LLVMBuildLoad(g->builder, expr, "");
|
||||
}
|
||||
case PrefixOpMaybe:
|
||||
{
|
||||
zig_panic("TODO codegen PrefixOpMaybe");
|
||||
}
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -1484,35 +1583,46 @@ static LLVMValueRef gen_null_literal(CodeGen *g, AstNode *node) {
|
||||
return tmp_struct_ptr;
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_struct_val_expr(CodeGen *g, AstNode *node) {
|
||||
assert(node->type == NodeTypeStructValueExpr);
|
||||
static LLVMValueRef gen_container_init_expr(CodeGen *g, AstNode *node) {
|
||||
assert(node->type == NodeTypeContainerInitExpr);
|
||||
|
||||
TypeTableEntry *type_entry = get_expr_type(node);
|
||||
|
||||
assert(type_entry->id == TypeTableEntryIdStruct);
|
||||
if (type_entry->id == TypeTableEntryIdStruct) {
|
||||
assert(node->data.container_init_expr.kind == ContainerInitKindStruct);
|
||||
|
||||
int field_count = type_entry->data.structure.field_count;
|
||||
assert(field_count == node->data.struct_val_expr.fields.length);
|
||||
int field_count = type_entry->data.structure.field_count;
|
||||
assert(field_count == node->data.container_init_expr.entries.length);
|
||||
|
||||
StructValExprCodeGen *struct_val_expr_node = &node->data.struct_val_expr.codegen;
|
||||
LLVMValueRef tmp_struct_ptr = struct_val_expr_node->ptr;
|
||||
StructValExprCodeGen *struct_val_expr_node = &node->data.container_init_expr.resolved_struct_val_expr;
|
||||
LLVMValueRef tmp_struct_ptr = struct_val_expr_node->ptr;
|
||||
|
||||
for (int i = 0; i < field_count; i += 1) {
|
||||
AstNode *field_node = node->data.struct_val_expr.fields.at(i);
|
||||
assert(field_node->type == NodeTypeStructValueField);
|
||||
TypeStructField *type_struct_field = field_node->data.struct_val_field.type_struct_field;
|
||||
if (type_struct_field->type_entry->id == TypeTableEntryIdVoid) {
|
||||
continue;
|
||||
for (int i = 0; i < field_count; i += 1) {
|
||||
AstNode *field_node = node->data.container_init_expr.entries.at(i);
|
||||
assert(field_node->type == NodeTypeStructValueField);
|
||||
TypeStructField *type_struct_field = field_node->data.struct_val_field.type_struct_field;
|
||||
if (type_struct_field->type_entry->id == TypeTableEntryIdVoid) {
|
||||
continue;
|
||||
}
|
||||
assert(buf_eql_buf(type_struct_field->name, &field_node->data.struct_val_field.name));
|
||||
|
||||
add_debug_source_node(g, field_node);
|
||||
LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, type_struct_field->gen_index, "");
|
||||
LLVMValueRef value = gen_expr(g, field_node->data.struct_val_field.expr);
|
||||
LLVMBuildStore(g->builder, value, field_ptr);
|
||||
}
|
||||
assert(buf_eql_buf(type_struct_field->name, &field_node->data.struct_val_field.name));
|
||||
|
||||
add_debug_source_node(g, field_node);
|
||||
LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, type_struct_field->gen_index, "");
|
||||
LLVMValueRef value = gen_expr(g, field_node->data.struct_val_field.expr);
|
||||
LLVMBuildStore(g->builder, value, field_ptr);
|
||||
return tmp_struct_ptr;
|
||||
} else if (type_entry->id == TypeTableEntryIdUnreachable) {
|
||||
assert(node->data.container_init_expr.entries.length == 0);
|
||||
add_debug_source_node(g, node);
|
||||
return LLVMBuildUnreachable(g->builder);
|
||||
} else if (type_entry->id == TypeTableEntryIdVoid) {
|
||||
assert(node->data.container_init_expr.entries.length == 0);
|
||||
return nullptr;
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
return tmp_struct_ptr;
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
|
||||
@ -1659,84 +1769,6 @@ static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) {
|
||||
get_resolved_expr(node)->block_context, false, &init_val);
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_number_literal_raw(CodeGen *g, AstNode *source_node,
|
||||
NumLitCodeGen *codegen_num_lit, AstNodeNumberLiteral *num_lit_node)
|
||||
{
|
||||
TypeTableEntry *type_entry = codegen_num_lit->resolved_type;
|
||||
assert(type_entry);
|
||||
|
||||
// override the expression type for number literals
|
||||
get_resolved_expr(source_node)->type_entry = type_entry;
|
||||
|
||||
if (type_entry->id == TypeTableEntryIdInt) {
|
||||
// here the union has int64_t and uint64_t and we purposefully read
|
||||
// the uint64_t value in either case, because we want the twos
|
||||
// complement representation
|
||||
|
||||
return LLVMConstInt(type_entry->type_ref,
|
||||
num_lit_node->data.x_uint,
|
||||
type_entry->data.integral.is_signed);
|
||||
} else if (type_entry->id == TypeTableEntryIdFloat) {
|
||||
|
||||
return LLVMConstReal(type_entry->type_ref,
|
||||
num_lit_node->data.x_float);
|
||||
} else {
|
||||
zig_panic("bad number literal type");
|
||||
}
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_compiler_fn_type(CodeGen *g, AstNode *node) {
|
||||
assert(node->type == NodeTypeCompilerFnType);
|
||||
|
||||
Buf *name = &node->data.compiler_fn_type.name;
|
||||
TypeTableEntry *type_entry = get_type_for_type_node(g, node->data.compiler_fn_type.type);
|
||||
if (buf_eql_str(name, "sizeof")) {
|
||||
NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node);
|
||||
AstNodeNumberLiteral num_lit_node;
|
||||
num_lit_node.kind = type_entry->data.num_lit.kind;
|
||||
num_lit_node.overflow = false;
|
||||
num_lit_node.data.x_uint = type_entry->size_in_bits / 8;
|
||||
return gen_number_literal_raw(g, node, codegen_num_lit, &num_lit_node);
|
||||
} else if (buf_eql_str(name, "min_value")) {
|
||||
if (type_entry->id == TypeTableEntryIdInt) {
|
||||
if (type_entry->data.integral.is_signed) {
|
||||
return LLVMConstInt(type_entry->type_ref, 1ULL << (type_entry->size_in_bits - 1), false);
|
||||
} else {
|
||||
return LLVMConstNull(type_entry->type_ref);
|
||||
}
|
||||
} else if (type_entry->id == TypeTableEntryIdFloat) {
|
||||
zig_panic("TODO codegen min_value float");
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
} else if (buf_eql_str(name, "max_value")) {
|
||||
if (type_entry->id == TypeTableEntryIdInt) {
|
||||
if (type_entry->data.integral.is_signed) {
|
||||
return LLVMConstInt(type_entry->type_ref, (1ULL << (type_entry->size_in_bits - 1)) - 1, false);
|
||||
} else {
|
||||
return LLVMConstAllOnes(type_entry->type_ref);
|
||||
}
|
||||
} else if (type_entry->id == TypeTableEntryIdFloat) {
|
||||
zig_panic("TODO codegen max_value float");
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
} else if (buf_eql_str(name, "value_count")) {
|
||||
if (type_entry->id == TypeTableEntryIdEnum) {
|
||||
NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node);
|
||||
AstNodeNumberLiteral num_lit_node;
|
||||
num_lit_node.kind = type_entry->data.num_lit.kind;
|
||||
num_lit_node.overflow = false;
|
||||
num_lit_node.data.x_uint = type_entry->data.enumeration.field_count;
|
||||
return gen_number_literal_raw(g, node, codegen_num_lit, &num_lit_node);
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_number_literal(CodeGen *g, AstNode *node) {
|
||||
assert(node->type == NodeTypeNumberLiteral);
|
||||
|
||||
@ -1746,6 +1778,30 @@ static LLVMValueRef gen_number_literal(CodeGen *g, AstNode *node) {
|
||||
return gen_number_literal_raw(g, node, codegen_num_lit, &node->data.number_literal);
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) {
|
||||
VariableTableEntry *variable = find_variable(
|
||||
get_resolved_expr(node)->block_context,
|
||||
&node->data.symbol_expr.symbol);
|
||||
assert(variable);
|
||||
if (variable->type->id == TypeTableEntryIdVoid) {
|
||||
return nullptr;
|
||||
} else if (variable->is_ptr) {
|
||||
assert(variable->value_ref);
|
||||
if (variable->type->id == TypeTableEntryIdArray) {
|
||||
return variable->value_ref;
|
||||
} else if (variable->type->id == TypeTableEntryIdStruct ||
|
||||
variable->type->id == TypeTableEntryIdMaybe)
|
||||
{
|
||||
return variable->value_ref;
|
||||
} else {
|
||||
add_debug_source_node(g, node);
|
||||
return LLVMBuildLoad(g->builder, variable->value_ref, "");
|
||||
}
|
||||
} else {
|
||||
return variable->value_ref;
|
||||
}
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
|
||||
switch (node->type) {
|
||||
case NodeTypeBinOpExpr:
|
||||
@ -1766,11 +1822,6 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
|
||||
return gen_slice_expr(g, node);
|
||||
case NodeTypeFieldAccessExpr:
|
||||
return gen_field_access_expr(g, node, false);
|
||||
case NodeTypeUnreachable:
|
||||
add_debug_source_node(g, node);
|
||||
return LLVMBuildUnreachable(g->builder);
|
||||
case NodeTypeVoid:
|
||||
return nullptr;
|
||||
case NodeTypeBoolLiteral:
|
||||
if (node->data.bool_literal.value)
|
||||
return LLVMConstAllOnes(LLVMInt1Type());
|
||||
@ -1802,29 +1853,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
|
||||
case NodeTypeCharLiteral:
|
||||
return LLVMConstInt(LLVMInt8Type(), node->data.char_literal.value, false);
|
||||
case NodeTypeSymbol:
|
||||
{
|
||||
VariableTableEntry *variable = find_variable(
|
||||
get_resolved_expr(node)->block_context,
|
||||
&node->data.symbol_expr.symbol);
|
||||
assert(variable);
|
||||
if (variable->type->id == TypeTableEntryIdVoid) {
|
||||
return nullptr;
|
||||
} else if (variable->is_ptr) {
|
||||
assert(variable->value_ref);
|
||||
if (variable->type->id == TypeTableEntryIdArray) {
|
||||
return variable->value_ref;
|
||||
} else if (variable->type->id == TypeTableEntryIdStruct ||
|
||||
variable->type->id == TypeTableEntryIdMaybe)
|
||||
{
|
||||
return variable->value_ref;
|
||||
} else {
|
||||
add_debug_source_node(g, node);
|
||||
return LLVMBuildLoad(g->builder, variable->value_ref, "");
|
||||
}
|
||||
} else {
|
||||
return variable->value_ref;
|
||||
}
|
||||
}
|
||||
return gen_symbol(g, node);
|
||||
case NodeTypeBlock:
|
||||
return gen_block(g, node, nullptr);
|
||||
case NodeTypeGoto:
|
||||
@ -1846,24 +1875,21 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
|
||||
LLVMPositionBuilderAtEnd(g->builder, basic_block);
|
||||
return nullptr;
|
||||
}
|
||||
case NodeTypeStructValueExpr:
|
||||
return gen_struct_val_expr(g, node);
|
||||
case NodeTypeCompilerFnType:
|
||||
return gen_compiler_fn_type(g, node);
|
||||
case NodeTypeContainerInitExpr:
|
||||
return gen_container_init_expr(g, node);
|
||||
case NodeTypeRoot:
|
||||
case NodeTypeRootExportDecl:
|
||||
case NodeTypeFnProto:
|
||||
case NodeTypeFnDef:
|
||||
case NodeTypeFnDecl:
|
||||
case NodeTypeParamDecl:
|
||||
case NodeTypeType:
|
||||
case NodeTypeExternBlock:
|
||||
case NodeTypeDirective:
|
||||
case NodeTypeUse:
|
||||
case NodeTypeStructDecl:
|
||||
case NodeTypeStructField:
|
||||
case NodeTypeStructValueField:
|
||||
case NodeTypeCompilerFnExpr:
|
||||
case NodeTypeArrayType:
|
||||
zig_unreachable();
|
||||
}
|
||||
zig_unreachable();
|
||||
@ -1872,7 +1898,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
|
||||
static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
|
||||
LLVMValueRef val = gen_expr_no_cast(g, node);
|
||||
|
||||
if (node->type == NodeTypeVoid) {
|
||||
if (is_node_void_expr(node)) {
|
||||
return val;
|
||||
}
|
||||
|
||||
@ -1966,7 +1992,7 @@ static void do_code_gen(CodeGen *g) {
|
||||
assert(proto_node->type == NodeTypeFnProto);
|
||||
AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
|
||||
|
||||
LLVMTypeRef ret_type = get_type_for_type_node(g, fn_proto->return_type)->type_ref;
|
||||
LLVMTypeRef ret_type = get_type_for_type_node(fn_proto->return_type)->type_ref;
|
||||
int param_count = count_non_void_params(g, &fn_proto->params);
|
||||
LLVMTypeRef *param_types = allocate<LLVMTypeRef>(param_count);
|
||||
int gen_param_index = 0;
|
||||
@ -2009,7 +2035,7 @@ static void do_code_gen(CodeGen *g) {
|
||||
TypeTableEntry *param_type = fn_proto_type_from_type_node(g, type_node);
|
||||
LLVMValueRef argument_val = LLVMGetParam(fn, gen_param_index);
|
||||
if (param_type->id == TypeTableEntryIdPointer &&
|
||||
param_type->data.pointer.is_noalias)
|
||||
false) // TODO test if parameter is noalias
|
||||
{
|
||||
LLVMAddAttribute(argument_val, LLVMNoAliasAttribute);
|
||||
} else if (param_type->id == TypeTableEntryIdPointer &&
|
||||
@ -2267,7 +2293,7 @@ static void define_builtin_types(CodeGen *g) {
|
||||
g->builtin_types.entry_u64 = entry;
|
||||
g->primitive_type_table.put(&entry->name, entry);
|
||||
}
|
||||
g->builtin_types.entry_c_string_literal = get_pointer_to_type(g, g->builtin_types.entry_u8, true, false);
|
||||
g->builtin_types.entry_c_string_literal = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
|
||||
entry->type_ref = LLVMInt8Type();
|
||||
@ -2413,7 +2439,7 @@ static void define_builtin_fns_int(CodeGen *g, TypeTableEntry *type_entry) {
|
||||
builtin_fn->param_types = allocate<TypeTableEntry *>(builtin_fn->param_count);
|
||||
builtin_fn->param_types[0] = type_entry;
|
||||
builtin_fn->param_types[1] = type_entry;
|
||||
builtin_fn->param_types[2] = get_pointer_to_type(g, type_entry, false, false);
|
||||
builtin_fn->param_types[2] = get_pointer_to_type(g, type_entry, false);
|
||||
|
||||
|
||||
const char *signed_str = type_entry->data.integral.is_signed ?
|
||||
@ -2437,6 +2463,23 @@ static void define_builtin_fns_int(CodeGen *g, TypeTableEntry *type_entry) {
|
||||
}
|
||||
}
|
||||
|
||||
static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char *name) {
|
||||
BuiltinFnEntry *builtin_fn = allocate<BuiltinFnEntry>(1);
|
||||
buf_init_from_str(&builtin_fn->name, name);
|
||||
builtin_fn->id = id;
|
||||
g->builtin_fn_table.put(&builtin_fn->name, builtin_fn);
|
||||
return builtin_fn;
|
||||
}
|
||||
|
||||
static BuiltinFnEntry *create_one_arg_builtin_fn(CodeGen *g, BuiltinFnId id, const char *name) {
|
||||
BuiltinFnEntry *builtin_fn = create_builtin_fn(g, id, name);
|
||||
builtin_fn->return_type = nullptr; // manually determined later
|
||||
builtin_fn->param_count = 1;
|
||||
builtin_fn->param_types = allocate<TypeTableEntry *>(builtin_fn->param_count);
|
||||
builtin_fn->param_types[0] = nullptr; // manually checked later
|
||||
return builtin_fn;
|
||||
}
|
||||
|
||||
static void define_builtin_fns(CodeGen *g) {
|
||||
define_builtin_fns_int(g, g->builtin_types.entry_u8);
|
||||
define_builtin_fns_int(g, g->builtin_types.entry_u16);
|
||||
@ -2447,9 +2490,7 @@ static void define_builtin_fns(CodeGen *g) {
|
||||
define_builtin_fns_int(g, g->builtin_types.entry_i32);
|
||||
define_builtin_fns_int(g, g->builtin_types.entry_i64);
|
||||
{
|
||||
BuiltinFnEntry *builtin_fn = allocate<BuiltinFnEntry>(1);
|
||||
buf_init_from_str(&builtin_fn->name, "memcpy");
|
||||
builtin_fn->id = BuiltinFnIdMemcpy;
|
||||
BuiltinFnEntry *builtin_fn = create_builtin_fn(g, BuiltinFnIdMemcpy, "memcpy");
|
||||
builtin_fn->return_type = g->builtin_types.entry_void;
|
||||
builtin_fn->param_count = 3;
|
||||
builtin_fn->param_types = allocate<TypeTableEntry *>(builtin_fn->param_count);
|
||||
@ -2470,12 +2511,9 @@ static void define_builtin_fns(CodeGen *g) {
|
||||
assert(LLVMGetIntrinsicID(builtin_fn->fn_val));
|
||||
|
||||
g->memcpy_fn_val = builtin_fn->fn_val;
|
||||
g->builtin_fn_table.put(&builtin_fn->name, builtin_fn);
|
||||
}
|
||||
{
|
||||
BuiltinFnEntry *builtin_fn = allocate<BuiltinFnEntry>(1);
|
||||
buf_init_from_str(&builtin_fn->name, "memset");
|
||||
builtin_fn->id = BuiltinFnIdMemset;
|
||||
BuiltinFnEntry *builtin_fn = create_builtin_fn(g, BuiltinFnIdMemset, "memset");
|
||||
builtin_fn->return_type = g->builtin_types.entry_void;
|
||||
builtin_fn->param_count = 3;
|
||||
builtin_fn->param_types = allocate<TypeTableEntry *>(builtin_fn->param_count);
|
||||
@ -2496,8 +2534,12 @@ static void define_builtin_fns(CodeGen *g) {
|
||||
assert(LLVMGetIntrinsicID(builtin_fn->fn_val));
|
||||
|
||||
g->memset_fn_val = builtin_fn->fn_val;
|
||||
g->builtin_fn_table.put(&builtin_fn->name, builtin_fn);
|
||||
}
|
||||
create_one_arg_builtin_fn(g, BuiltinFnIdSizeof, "sizeof");
|
||||
create_one_arg_builtin_fn(g, BuiltinFnIdMaxValue, "max_value");
|
||||
create_one_arg_builtin_fn(g, BuiltinFnIdMinValue, "min_value");
|
||||
create_one_arg_builtin_fn(g, BuiltinFnIdValueCount, "value_count");
|
||||
create_one_arg_builtin_fn(g, BuiltinFnIdTypeof, "typeof");
|
||||
}
|
||||
|
||||
|
||||
@ -2780,9 +2822,8 @@ void codegen_add_root_code(CodeGen *g, Buf *src_dir, Buf *src_basename, Buf *sou
|
||||
}
|
||||
|
||||
static void to_c_type(CodeGen *g, AstNode *type_node, Buf *out_buf) {
|
||||
assert(type_node->type == NodeTypeType);
|
||||
|
||||
TypeTableEntry *type_entry = type_node->data.type.entry;
|
||||
zig_panic("TODO this function needs some love");
|
||||
TypeTableEntry *type_entry = get_resolved_expr(type_node)->type_entry;
|
||||
assert(type_entry);
|
||||
|
||||
if (type_entry == g->builtin_types.entry_u8) {
|
||||
|
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;
|
||||
} else if (mem_eql_str(token_mem, token_len, "extern")) {
|
||||
t->cur_tok->id = TokenIdKeywordExtern;
|
||||
} else if (mem_eql_str(token_mem, token_len, "unreachable")) {
|
||||
t->cur_tok->id = TokenIdKeywordUnreachable;
|
||||
} else if (mem_eql_str(token_mem, token_len, "pub")) {
|
||||
t->cur_tok->id = TokenIdKeywordPub;
|
||||
} else if (mem_eql_str(token_mem, token_len, "export")) {
|
||||
@ -217,8 +215,6 @@ static void end_token(Tokenize *t) {
|
||||
t->cur_tok->id = TokenIdKeywordAs;
|
||||
} else if (mem_eql_str(token_mem, token_len, "use")) {
|
||||
t->cur_tok->id = TokenIdKeywordUse;
|
||||
} else if (mem_eql_str(token_mem, token_len, "void")) {
|
||||
t->cur_tok->id = TokenIdKeywordVoid;
|
||||
} else if (mem_eql_str(token_mem, token_len, "true")) {
|
||||
t->cur_tok->id = TokenIdKeywordTrue;
|
||||
} else if (mem_eql_str(token_mem, token_len, "false")) {
|
||||
@ -553,6 +549,11 @@ void tokenize(Buf *buf, Tokenization *out) {
|
||||
end_token(&t);
|
||||
t.state = TokenizeStateStart;
|
||||
break;
|
||||
case '>':
|
||||
t.cur_tok->id = TokenIdFatArrow;
|
||||
end_token(&t);
|
||||
t.state = TokenizeStateStart;
|
||||
break;
|
||||
default:
|
||||
t.pos -= 1;
|
||||
end_token(&t);
|
||||
@ -1009,12 +1010,10 @@ static const char * token_name(Token *token) {
|
||||
case TokenIdKeywordVar: return "Var";
|
||||
case TokenIdKeywordReturn: return "Return";
|
||||
case TokenIdKeywordExtern: return "Extern";
|
||||
case TokenIdKeywordUnreachable: return "Unreachable";
|
||||
case TokenIdKeywordPub: return "Pub";
|
||||
case TokenIdKeywordExport: return "Export";
|
||||
case TokenIdKeywordAs: return "As";
|
||||
case TokenIdKeywordUse: return "Use";
|
||||
case TokenIdKeywordVoid: return "Void";
|
||||
case TokenIdKeywordTrue: return "True";
|
||||
case TokenIdKeywordFalse: return "False";
|
||||
case TokenIdKeywordIf: return "If";
|
||||
@ -1044,6 +1043,7 @@ static const char * token_name(Token *token) {
|
||||
case TokenIdPlus: return "Plus";
|
||||
case TokenIdColon: return "Colon";
|
||||
case TokenIdArrow: return "Arrow";
|
||||
case TokenIdFatArrow: return "FatArrow";
|
||||
case TokenIdDash: return "Dash";
|
||||
case TokenIdNumberSign: return "NumberSign";
|
||||
case TokenIdBinOr: return "BinOr";
|
||||
|
@ -18,12 +18,10 @@ enum TokenId {
|
||||
TokenIdKeywordVar,
|
||||
TokenIdKeywordConst,
|
||||
TokenIdKeywordExtern,
|
||||
TokenIdKeywordUnreachable,
|
||||
TokenIdKeywordPub,
|
||||
TokenIdKeywordExport,
|
||||
TokenIdKeywordAs,
|
||||
TokenIdKeywordUse,
|
||||
TokenIdKeywordVoid,
|
||||
TokenIdKeywordTrue,
|
||||
TokenIdKeywordFalse,
|
||||
TokenIdKeywordIf,
|
||||
@ -53,6 +51,7 @@ enum TokenId {
|
||||
TokenIdPlus,
|
||||
TokenIdColon,
|
||||
TokenIdArrow,
|
||||
TokenIdFatArrow,
|
||||
TokenIdDash,
|
||||
TokenIdNumberSign,
|
||||
TokenIdBoolOr,
|
||||
|
@ -3,10 +3,35 @@ use "syscall.zig";
|
||||
// The compiler treats this file special by implicitly importing the function `main`
|
||||
// from the root source file.
|
||||
|
||||
var env: &&u8;
|
||||
|
||||
#attribute("naked")
|
||||
export fn _start() -> unreachable {
|
||||
const argc = asm("mov (%%rsp), %[argc]" : [argc] "=r" (-> isize));
|
||||
const argv = asm("lea 0x8(%%rsp), %[argv]" : [argv] "=r" (-> &&u8));
|
||||
const env = asm("lea 0x10(%%rsp,%%rdi,8), %[env]" : [env] "=r" (-> &&u8));
|
||||
exit(main(argc, argv, env))
|
||||
export fn _start() unreachable => {
|
||||
const argc = asm("mov (%%rsp), %[argc]": [argc] "=r" (-> isize));
|
||||
const argv = asm("lea 0x8(%%rsp), %[argv]": [argv] "=r" (-> &&u8));
|
||||
env = asm("lea 0x10(%%rsp,%%rdi,8), %[env]": [env] "=r" (-> &&u8));
|
||||
|
||||
exit(main(argc, argv, env));
|
||||
|
||||
/*
|
||||
var args = @alloca_array([]u8, argc);
|
||||
var i : @typeof(argc) = 0;
|
||||
// TODO for in loop over the array
|
||||
while (i < argc) {
|
||||
const ptr = argv[i];
|
||||
args[i] = ptr[0...strlen(ptr)];
|
||||
i += 1;
|
||||
}
|
||||
exit(main(args))
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
fn strlen(ptr: &u8) isize => {
|
||||
var count: isize = 0;
|
||||
while (ptr[count]) {
|
||||
count += 1;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
*/
|
||||
|
@ -1,8 +1,8 @@
|
||||
// These functions are provided when not linking against libc because LLVM
|
||||
// sometimes generates code that calls them.
|
||||
|
||||
export fn memset(dest: &u8, c: u8, n: usize) -> &u8 {
|
||||
var index : #typeof(n) = 0;
|
||||
export fn memset(dest: &u8, c: u8, n: usize) &u8 => {
|
||||
var index : @typeof(n) = 0;
|
||||
while (index != n) {
|
||||
dest[index] = c;
|
||||
index += 1;
|
||||
@ -10,8 +10,8 @@ export fn memset(dest: &u8, c: u8, n: usize) -> &u8 {
|
||||
return dest;
|
||||
}
|
||||
|
||||
export fn memcpy(dest: &noalias u8, src: &const noalias u8, n: usize) -> &u8 {
|
||||
var index : #typeof(n) = 0;
|
||||
export fn memcpy(noalias dest: &u8, noalias src: &const u8, n: usize) &u8 => {
|
||||
var index : @typeof(n) = 0;
|
||||
while (index != n) {
|
||||
dest[index] = src[index];
|
||||
index += 1;
|
||||
|
36
std/rand.zig
36
std/rand.zig
@ -4,13 +4,13 @@ const ARRAY_SIZE : u16 = 624;
|
||||
/// Use `rand_init` to initialize this state.
|
||||
pub struct Rand {
|
||||
array: [ARRAY_SIZE]u32,
|
||||
index: #typeof(ARRAY_SIZE),
|
||||
index: @typeof(ARRAY_SIZE),
|
||||
|
||||
/// Initialize random state with the given seed.
|
||||
pub fn init(r: &Rand, seed: u32) {
|
||||
pub fn init(r: &Rand, seed: u32) => {
|
||||
r.index = 0;
|
||||
r.array[0] = seed;
|
||||
var i : #typeof(ARRAY_SIZE) = 1;
|
||||
var i : @typeof(ARRAY_SIZE) = 1;
|
||||
while (i < ARRAY_SIZE) {
|
||||
const prev_value : u64 = r.array[i - 1];
|
||||
r.array[i] = ((prev_value ^ (prev_value << 30)) * 0x6c078965 + i) as u32;
|
||||
@ -20,7 +20,7 @@ pub struct Rand {
|
||||
|
||||
|
||||
/// Get 32 bits of randomness.
|
||||
pub fn get_u32(r: &Rand) -> u32 {
|
||||
pub fn get_u32(r: &Rand) u32 => {
|
||||
if (r.index == 0) {
|
||||
r.generate_numbers();
|
||||
}
|
||||
@ -37,13 +37,13 @@ pub struct Rand {
|
||||
}
|
||||
|
||||
/// Fill `buf` with randomness.
|
||||
pub fn get_bytes(r: &Rand, buf: []u8) {
|
||||
pub fn get_bytes(r: &Rand, buf: []u8) => {
|
||||
var bytes_left = r.get_bytes_aligned(buf);
|
||||
if (bytes_left > 0) {
|
||||
var rand_val_array : [#sizeof(u32)]u8;
|
||||
*(rand_val_array.ptr as &u32) = r.get_u32();
|
||||
var rand_val_array : [@sizeof(u32)]u8;
|
||||
*(rand_val_array.ptr as (&u32)) = r.get_u32();
|
||||
while (bytes_left > 0) {
|
||||
buf[buf.len - bytes_left] = rand_val_array[#sizeof(u32) - bytes_left];
|
||||
buf[buf.len - bytes_left] = rand_val_array[@sizeof(u32) - bytes_left];
|
||||
bytes_left -= 1;
|
||||
}
|
||||
}
|
||||
@ -51,23 +51,23 @@ pub struct Rand {
|
||||
|
||||
/// Get a random unsigned integer with even distribution between `start`
|
||||
/// inclusive and `end` exclusive.
|
||||
pub fn range_u64(r: &Rand, start: u64, end: u64) -> u64 {
|
||||
pub fn range_u64(r: &Rand, start: u64, end: u64) u64 => {
|
||||
const range = end - start;
|
||||
const leftover = #max_value(u64) % range;
|
||||
const upper_bound = #max_value(u64) - leftover;
|
||||
var rand_val_array : [#sizeof(u64)]u8;
|
||||
const leftover = @max_value(u64) % range;
|
||||
const upper_bound = @max_value(u64) - leftover;
|
||||
var rand_val_array : [@sizeof(u64)]u8;
|
||||
|
||||
while (true) {
|
||||
r.get_bytes_aligned(rand_val_array);
|
||||
const rand_val = *(rand_val_array.ptr as &u64);
|
||||
const rand_val = *(rand_val_array.ptr as (&u64));
|
||||
if (rand_val < upper_bound) {
|
||||
return start + (rand_val % range);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_numbers(r: &Rand) {
|
||||
var i : #typeof(ARRAY_SIZE) = 0;
|
||||
fn generate_numbers(r: &Rand) => {
|
||||
var i : @typeof(ARRAY_SIZE) = 0;
|
||||
while (i < ARRAY_SIZE) {
|
||||
const y : u32 = (r.array[i] & 0x80000000) + (r.array[(i + 1) % ARRAY_SIZE] & 0x7fffffff);
|
||||
const untempered : u32 = r.array[(i + 397) % ARRAY_SIZE] ^ (y >> 1);
|
||||
@ -82,11 +82,11 @@ pub struct Rand {
|
||||
}
|
||||
|
||||
// does not populate the remaining (buf.len % 4) bytes
|
||||
fn get_bytes_aligned(r: &Rand, buf: []u8) -> usize {
|
||||
fn get_bytes_aligned(r: &Rand, buf: []u8) usize => {
|
||||
var bytes_left = buf.len;
|
||||
while (bytes_left >= 4) {
|
||||
*(&buf[buf.len - bytes_left] as &u32) = r.get_u32();
|
||||
bytes_left -= #sizeof(u32);
|
||||
*(&buf[buf.len - bytes_left] as (&u32)) = r.get_u32();
|
||||
bytes_left -= @sizeof(u32);
|
||||
}
|
||||
return bytes_left;
|
||||
}
|
||||
|
24
std/std.zig
24
std/std.zig
@ -5,25 +5,25 @@ pub const stdout_fileno : isize = 1;
|
||||
pub const stderr_fileno : isize = 2;
|
||||
|
||||
// TODO error handling
|
||||
pub fn os_get_random_bytes(buf: &u8, count: usize) -> isize {
|
||||
pub fn os_get_random_bytes(buf: &u8, count: usize) isize => {
|
||||
getrandom(buf, count, 0)
|
||||
}
|
||||
|
||||
// TODO error handling
|
||||
// TODO handle buffering and flushing (mutex protected)
|
||||
pub fn print_str(str: []const u8) -> isize {
|
||||
pub fn print_str(str: []const u8) isize => {
|
||||
fprint_str(stdout_fileno, str)
|
||||
}
|
||||
|
||||
// TODO error handling
|
||||
// TODO handle buffering and flushing (mutex protected)
|
||||
pub fn fprint_str(fd: isize, str: []const u8) -> isize {
|
||||
pub fn fprint_str(fd: isize, str: []const u8) isize => {
|
||||
write(fd, str.ptr, str.len)
|
||||
}
|
||||
|
||||
// TODO handle buffering and flushing (mutex protected)
|
||||
// TODO error handling
|
||||
pub fn print_u64(x: u64) -> isize {
|
||||
pub fn print_u64(x: u64) isize => {
|
||||
var buf: [max_u64_base10_digits]u8;
|
||||
const len = buf_print_u64(buf, x);
|
||||
return write(stdout_fileno, buf.ptr, len);
|
||||
@ -31,14 +31,14 @@ pub fn print_u64(x: u64) -> isize {
|
||||
|
||||
// TODO handle buffering and flushing (mutex protected)
|
||||
// TODO error handling
|
||||
pub fn print_i64(x: i64) -> isize {
|
||||
pub fn print_i64(x: i64) isize => {
|
||||
var buf: [max_u64_base10_digits]u8;
|
||||
const len = buf_print_i64(buf, x);
|
||||
return write(stdout_fileno, buf.ptr, len);
|
||||
}
|
||||
|
||||
// TODO error handling
|
||||
pub fn readline(buf: []u8, out_len: &usize) -> bool {
|
||||
pub fn readline(buf: []u8, out_len: &usize) bool => {
|
||||
const amt_read = read(stdin_fileno, buf.ptr, buf.len);
|
||||
if (amt_read < 0) {
|
||||
return true;
|
||||
@ -48,10 +48,10 @@ pub fn readline(buf: []u8, out_len: &usize) -> bool {
|
||||
}
|
||||
|
||||
// TODO return ?u64 when we support returning struct byval
|
||||
pub fn parse_u64(buf: []u8, radix: u8, result: &u64) -> bool {
|
||||
pub fn parse_u64(buf: []u8, radix: u8, result: &u64) bool => {
|
||||
var x : u64 = 0;
|
||||
|
||||
var i : #typeof(buf.len) = 0;
|
||||
var i : @typeof(buf.len) = 0;
|
||||
while (i < buf.len) {
|
||||
const c = buf[i];
|
||||
const digit = char_to_digit(c);
|
||||
@ -77,7 +77,7 @@ pub fn parse_u64(buf: []u8, radix: u8, result: &u64) -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
fn char_to_digit(c: u8) -> u8 {
|
||||
fn char_to_digit(c: u8) u8 => {
|
||||
if ('0' <= c && c <= '9') {
|
||||
c - '0'
|
||||
} else if ('A' <= c && c <= 'Z') {
|
||||
@ -85,13 +85,13 @@ fn char_to_digit(c: u8) -> u8 {
|
||||
} else if ('a' <= c && c <= 'z') {
|
||||
c - 'a' + 10
|
||||
} else {
|
||||
#max_value(u8)
|
||||
@max_value(u8)
|
||||
}
|
||||
}
|
||||
|
||||
const max_u64_base10_digits: usize = 20;
|
||||
|
||||
fn buf_print_i64(out_buf: []u8, x: i64) -> usize {
|
||||
fn buf_print_i64(out_buf: []u8, x: i64) usize => {
|
||||
if (x < 0) {
|
||||
out_buf[0] = '-';
|
||||
return 1 + buf_print_u64(out_buf[1...], ((-(x + 1)) as u64) + 1);
|
||||
@ -100,7 +100,7 @@ fn buf_print_i64(out_buf: []u8, x: i64) -> usize {
|
||||
}
|
||||
}
|
||||
|
||||
fn buf_print_u64(out_buf: []u8, x: u64) -> usize {
|
||||
fn buf_print_u64(out_buf: []u8, x: u64) usize => {
|
||||
var buf: [max_u64_base10_digits]u8;
|
||||
var a = x;
|
||||
var index = buf.len;
|
||||
|
@ -3,34 +3,34 @@ const SYS_write : usize = 1;
|
||||
const SYS_exit : usize = 60;
|
||||
const SYS_getrandom : usize = 318;
|
||||
|
||||
fn syscall1(number: usize, arg1: usize) -> usize {
|
||||
fn syscall1(number: usize, arg1: usize) usize => {
|
||||
asm volatile ("syscall"
|
||||
: [ret] "={rax}" (-> usize)
|
||||
: [number] "{rax}" (number), [arg1] "{rdi}" (arg1)
|
||||
: "rcx", "r11")
|
||||
}
|
||||
|
||||
fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) -> usize {
|
||||
fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) usize => {
|
||||
asm volatile ("syscall"
|
||||
: [ret] "={rax}" (-> usize)
|
||||
: [number] "{rax}" (number), [arg1] "{rdi}" (arg1), [arg2] "{rsi}" (arg2), [arg3] "{rdx}" (arg3)
|
||||
: "rcx", "r11")
|
||||
}
|
||||
|
||||
pub fn read(fd: isize, buf: &u8, count: usize) -> isize {
|
||||
pub fn read(fd: isize, buf: &u8, count: usize) isize => {
|
||||
syscall3(SYS_read, fd as usize, buf as usize, count) as isize
|
||||
}
|
||||
|
||||
pub fn write(fd: isize, buf: &const u8, count: usize) -> isize {
|
||||
pub fn write(fd: isize, buf: &const u8, count: usize) isize => {
|
||||
syscall3(SYS_write, fd as usize, buf as usize, count) as isize
|
||||
}
|
||||
|
||||
pub fn exit(status: i32) -> unreachable {
|
||||
pub fn exit(status: i32) unreachable => {
|
||||
syscall1(SYS_exit, status as usize);
|
||||
unreachable
|
||||
unreachable{}
|
||||
}
|
||||
|
||||
pub fn getrandom(buf: &u8, count: usize, flags: u32) -> isize {
|
||||
pub fn getrandom(buf: &u8, count: usize, flags: u32) isize => {
|
||||
syscall3(SYS_getrandom, buf as usize, count, flags as usize) as isize
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user