| author | |
| committer | |
| log | b28b7f63d15ab0fdd9064c6c58e6339705edbc27 |
| tree | 8139f31b749a6838bb92d16053e371f826224d32 |
| parent | cb46d0b5b0d1d83856adab34b461049f5cfac019 |
See #2226 files changed, 1570 insertions(+), 1818 deletions(-)
doc/langref.md+23-33| ... | @@ -34,13 +34,13 @@ Root : many(TopLevelDecl) token(EOF) | ... | @@ -34,13 +34,13 @@ Root : many(TopLevelDecl) token(EOF) |
| 34 | 34 | ||
| 35 | TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | ContainerDecl | VariableDeclaration | 35 | TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | ContainerDecl | VariableDeclaration |
| 36 | 36 | ||
| 37 | VariableDeclaration : option(FnVisibleMod) (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) Type option(token(Eq) Expression)) | 37 | VariableDeclaration : option(FnVisibleMod) (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) UnwrapMaybeExpression option(token(Eq) Expression)) |
| 38 | 38 | ||
| 39 | ContainerDecl : many(Directive) option(FnVisibleMod) (token(Struct) | token(Enum)) token(Symbol) token(LBrace) many(StructMember) token(RBrace) | 39 | ContainerDecl : many(Directive) option(FnVisibleMod) (token(Struct) | token(Enum)) token(Symbol) token(LBrace) many(StructMember) token(RBrace) |
| 40 | 40 | ||
| 41 | StructMember: StructField | FnDecl | 41 | StructMember: StructField | FnDecl |
| 42 | 42 | ||
| 43 | StructField : token(Symbol) option(token(Colon) Type token(Comma)) | 43 | StructField : token(Symbol) option(token(Colon) Expression) token(Comma)) |
| 44 | 44 | ||
| 45 | Use : many(Directive) token(Use) token(String) token(Semicolon) | 45 | Use : many(Directive) token(Use) token(String) token(Semicolon) |
| 46 | 46 | ||
| ... | @@ -48,7 +48,7 @@ RootExportDecl : many(Directive) token(Export) token(Symbol) token(String) token | ... | @@ -48,7 +48,7 @@ RootExportDecl : many(Directive) token(Export) token(Symbol) token(String) token |
| 48 | 48 | ||
| 49 | ExternBlock : many(Directive) token(Extern) token(LBrace) many(FnDecl) token(RBrace) | 49 | ExternBlock : many(Directive) token(Extern) token(LBrace) many(FnDecl) token(RBrace) |
| 50 | 50 | ||
| 51 | FnProto : many(Directive) option(FnVisibleMod) token(Fn) token(Symbol) ParamDeclList option(token(Arrow) Type) | 51 | FnProto : many(Directive) option(FnVisibleMod) token(Fn) token(Symbol) ParamDeclList option(Expression) |
| 52 | 52 | ||
| 53 | Directive : token(NumberSign) token(Symbol) token(LParen) token(String) token(RParen) | 53 | Directive : token(NumberSign) token(Symbol) token(LParen) token(String) token(RParen) |
| 54 | 54 | ||
| ... | @@ -56,23 +56,11 @@ FnVisibleMod : token(Pub) | token(Export) | ... | @@ -56,23 +56,11 @@ FnVisibleMod : token(Pub) | token(Export) |
| 56 | 56 | ||
| 57 | FnDecl : FnProto token(Semicolon) | 57 | FnDecl : FnProto token(Semicolon) |
| 58 | 58 | ||
| 59 | FnDef : FnProto Block | 59 | FnDef : FnProto token(FatArrow) Block |
| 60 | 60 | ||
| 61 | ParamDeclList : token(LParen) list(ParamDecl, token(Comma)) token(RParen) | 61 | ParamDeclList : token(LParen) list(ParamDecl, token(Comma)) token(RParen) |
| 62 | 62 | ||
| 63 | ParamDecl : token(Symbol) token(Colon) Type | token(Ellipsis) | 63 | ParamDecl : option(token(NoAlias)) token(Symbol) token(Colon) UnwrapMaybeExpression | token(Ellipsis) |
| 64 | |||
| 65 | Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType | MaybeType | CompilerFnExpr | ||
| 66 | |||
| 67 | CompilerFnExpr : token(NumberSign) token(Symbol) token(LParen) Expression token(RParen) | ||
| 68 | |||
| 69 | CompilerFnType : token(NumberSign) token(Symbol) token(LParen) Type token(RParen) | ||
| 70 | |||
| 71 | PointerType : token(Ampersand) option(token(Const)) option(token(NoAlias)) Type | ||
| 72 | |||
| 73 | MaybeType : token(Question) Type | ||
| 74 | |||
| 75 | ArrayType : token(LBracket) option(Expression) token(RBracket) option(token(Const)) option(token(NoAlias)) Type | ||
| 76 | 64 | ||
| 77 | Block : token(LBrace) list(option(Statement), token(Semicolon)) token(RBrace) | 65 | Block : token(LBrace) list(option(Statement), token(Semicolon)) token(RBrace) |
| 78 | 66 | ||
| ... | @@ -80,11 +68,9 @@ Statement : Label | VariableDeclaration token(Semicolon) | NonBlockExpression to | ... | @@ -80,11 +68,9 @@ Statement : Label | VariableDeclaration token(Semicolon) | NonBlockExpression to |
| 80 | 68 | ||
| 81 | Label: token(Symbol) token(Colon) | 69 | Label: token(Symbol) token(Colon) |
| 82 | 70 | ||
| 83 | VariableDeclaration : (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) Type option(token(Eq) Expression)) | ||
| 84 | |||
| 85 | Expression : BlockExpression | NonBlockExpression | 71 | Expression : BlockExpression | NonBlockExpression |
| 86 | 72 | ||
| 87 | NonBlockExpression : ReturnExpression | AssignmentExpression | AsmExpression | 73 | NonBlockExpression : ReturnExpression | AssignmentExpression |
| 88 | 74 | ||
| 89 | AsmExpression : token(Asm) option(token(Volatile)) token(LParen) token(String) option(AsmOutput) token(RParen) | 75 | AsmExpression : token(Asm) option(token(Volatile)) token(LParen) token(String) option(AsmOutput) token(RParen) |
| 90 | 76 | ||
| ... | @@ -92,13 +78,13 @@ AsmOutput : token(Colon) list(AsmOutputItem, token(Comma)) option(AsmInput) | ... | @@ -92,13 +78,13 @@ AsmOutput : token(Colon) list(AsmOutputItem, token(Comma)) option(AsmInput) |
| 92 | 78 | ||
| 93 | AsmInput : token(Colon) list(AsmInputItem, token(Comma)) option(AsmClobbers) | 79 | AsmInput : token(Colon) list(AsmInputItem, token(Comma)) option(AsmClobbers) |
| 94 | 80 | ||
| 95 | AsmOutputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) (token(Symbol) | token(Arrow) Type) token(RParen) | 81 | AsmOutputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) (token(Symbol) | token(Arrow) Expression) token(RParen) |
| 96 | 82 | ||
| 97 | AsmInputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) Expression token(RParen) | 83 | AsmInputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) Expression token(RParen) |
| 98 | 84 | ||
| 99 | AsmClobbers: token(Colon) list(token(String), token(Comma)) | 85 | AsmClobbers: token(Colon) list(token(String), token(Comma)) |
| 100 | 86 | ||
| 101 | UnwrapMaybeExpression : BoolOrExpression token(DoubleQuestion) BoolOrExpression | BoolOrExpression | 87 | UnwrapMaybeExpression : BoolOrExpression token(DoubleQuestionMark) BoolOrExpression | BoolOrExpression |
| 102 | 88 | ||
| 103 | AssignmentExpression : UnwrapMaybeExpression AssignmentOperator UnwrapMaybeExpression | UnwrapMaybeExpression | 89 | AssignmentExpression : UnwrapMaybeExpression AssignmentOperator UnwrapMaybeExpression | UnwrapMaybeExpression |
| 104 | 90 | ||
| ... | @@ -116,7 +102,7 @@ IfExpression : IfVarExpression | IfBoolExpression | ... | @@ -116,7 +102,7 @@ IfExpression : IfVarExpression | IfBoolExpression |
| 116 | 102 | ||
| 117 | IfBoolExpression : token(If) token(LParen) Expression token(RParen) Expression option(Else) | 103 | IfBoolExpression : token(If) token(LParen) Expression token(RParen) Expression option(Else) |
| 118 | 104 | ||
| 119 | IfVarExpression : token(If) token(LParen) (token(Const) | token(Var)) token(Symbol) option(token(Colon) Type) Token(MaybeAssign) Expression token(RParen) Expression Option(Else) | 105 | IfVarExpression : token(If) token(LParen) (token(Const) | token(Var)) token(Symbol) option(token(Colon) Expression) Token(MaybeAssign) Expression token(RParen) Expression Option(Else) |
| 120 | 106 | ||
| 121 | Else : token(Else) Expression | 107 | Else : token(Else) Expression |
| 122 | 108 | ||
| ... | @@ -144,11 +130,11 @@ MultiplyExpression : CastExpression MultiplyOperator MultiplyExpression | CastEx | ... | @@ -144,11 +130,11 @@ MultiplyExpression : CastExpression MultiplyOperator MultiplyExpression | CastEx |
| 144 | 130 | ||
| 145 | MultiplyOperator : token(Star) | token(Slash) | token(Percent) | 131 | MultiplyOperator : token(Star) | token(Slash) | token(Percent) |
| 146 | 132 | ||
| 147 | CastExpression : CastExpression token(as) Type | PrefixOpExpression | 133 | CastExpression : CastExpression token(as) PrimaryExpression | PrefixOpExpression |
| 148 | 134 | ||
| 149 | PrefixOpExpression : PrefixOp PrefixOpExpression | SuffixOpExpression | 135 | PrefixOpExpression : PrefixOp PrefixOpExpression | SuffixOpExpression |
| 150 | 136 | ||
| 151 | SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression) | 137 | SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression | ContainerInitExpression) |
| 152 | 138 | ||
| 153 | FieldAccessExpression : token(Dot) token(Symbol) | 139 | FieldAccessExpression : token(Dot) token(Symbol) |
| 154 | 140 | ||
| ... | @@ -158,26 +144,30 @@ ArrayAccessExpression : token(LBracket) Expression token(RBracket) | ... | @@ -158,26 +144,30 @@ ArrayAccessExpression : token(LBracket) Expression token(RBracket) |
| 158 | 144 | ||
| 159 | SliceExpression : token(LBracket) Expression token(Ellipsis) option(Expression) token(RBracket) option(token(Const)) | 145 | SliceExpression : token(LBracket) Expression token(Ellipsis) option(Expression) token(RBracket) option(token(Const)) |
| 160 | 146 | ||
| 161 | PrefixOp : token(Not) | token(Dash) | token(Tilde) | token(Star) | (token(Ampersand) option(token(Const))) | 147 | ContainerInitExpression : token(LBrace) ContainerInitBody token(RBrace) |
| 148 | |||
| 149 | ContainerInitBody : list(StructLiteralField, token(Comma)) | list(Expression, token(Comma)) | ||
| 150 | |||
| 151 | StructLiteralField : token(Dot) token(Symbol) token(Eq) Expression | ||
| 162 | 152 | ||
| 163 | PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression | CompilerFnType | (token(AtSign) token(Symbol) FnCallExpression) | 153 | PrefixOp : token(Not) | token(Dash) | token(Tilde) | token(Star) | (token(Ampersand) option(token(Const))) | token(QuestionMark) |
| 164 | 154 | ||
| 165 | StructValueExpression : token(Type) token(LBrace) list(StructValueExpressionField, token(Comma)) token(RBrace) | 155 | PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | token(Symbol) | (token(AtSign) token(Symbol) FnCallExpression) | ArrayType | AsmExpression |
| 166 | 156 | ||
| 167 | StructValueExpressionField : token(Dot) token(Symbol) token(Eq) Expression | 157 | ArrayType : token(LBracket) option(Expression) token(RBracket) option(token(Const)) Expression |
| 168 | 158 | ||
| 169 | Goto: token(Goto) token(Symbol) | 159 | GotoExpression: token(Goto) token(Symbol) |
| 170 | 160 | ||
| 171 | GroupedExpression : token(LParen) Expression token(RParen) | 161 | GroupedExpression : token(LParen) Expression token(RParen) |
| 172 | 162 | ||
| 173 | KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False) | token(Null) | 163 | KeywordLiteral : token(True) | token(False) | token(Null) | token(Break) | token(Continue) |
| 174 | ``` | 164 | ``` |
| 175 | 165 | ||
| 176 | ## Operator Precedence | 166 | ## Operator Precedence |
| 177 | 167 | ||
| 178 | ``` | 168 | ``` |
| 179 | x() x[] x.y | 169 | x() x[] x{} x.y |
| 180 | !x -x ~x *x &x &const x | 170 | !x -x ~x *x &x |
| 181 | as | 171 | as |
| 182 | * / % | 172 | * / % |
| 183 | + - | 173 | + - |
doc/vim/syntax/zig.vim+2-2| ... | @@ -15,8 +15,8 @@ syn keyword zigConditional if else switch | ... | @@ -15,8 +15,8 @@ syn keyword zigConditional if else switch |
| 15 | syn keyword zigRepeat while for | 15 | syn keyword zigRepeat while for |
| 16 | 16 | ||
| 17 | syn keyword zigConstant null | 17 | syn keyword zigConstant null |
| 18 | syn keyword zigKeyword fn unreachable use void | 18 | syn keyword zigKeyword fn use |
| 19 | syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 string | 19 | syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 string void unreachable |
| 20 | 20 | ||
| 21 | syn keyword zigBoolean true false | 21 | syn keyword zigBoolean true false |
| 22 | 22 |
example/arrays/arrays.zig deleted-36| ... | @@ -1,36 +0,0 @@ | ||
| 1 | export executable "arrays"; | ||
| 2 | |||
| 3 | use "std.zig"; | ||
| 4 | |||
| 5 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | ||
| 6 | var array : [5]u32; | ||
| 7 | |||
| 8 | var i : u32 = 0; | ||
| 9 | while (i < 5) { | ||
| 10 | array[i] = i + 1; | ||
| 11 | i = array[i]; | ||
| 12 | } | ||
| 13 | |||
| 14 | i = 0; | ||
| 15 | var accumulator : u32 = 0; | ||
| 16 | while (i < 5) { | ||
| 17 | accumulator += array[i]; | ||
| 18 | |||
| 19 | i += 1; | ||
| 20 | } | ||
| 21 | |||
| 22 | if (accumulator != 15) { | ||
| 23 | print_str("BAD\n"); | ||
| 24 | } | ||
| 25 | |||
| 26 | if (get_array_len(array) != 5) { | ||
| 27 | print_str("BAD\n"); | ||
| 28 | } | ||
| 29 | |||
| 30 | print_str("OK\n"); | ||
| 31 | return 0; | ||
| 32 | } | ||
| 33 | |||
| 34 | fn get_array_len(a: []u32) -> usize { | ||
| 35 | a.len | ||
| 36 | } | ||
example/cat/main.zig created+7| ... | @@ -0,0 +1,7 @@ | ||
| 1 | export executable "cat"; | ||
| 2 | |||
| 3 | pub main(argv: [][]u8) -> i32 { | ||
| 4 | |||
| 5 | |||
| 6 | return 0; | ||
| 7 | } | ||
example/expressions/expressions.zig deleted-52| ... | @@ -1,52 +0,0 @@ | ||
| 1 | export executable "expressions"; | ||
| 2 | |||
| 3 | use "std.zig"; | ||
| 4 | |||
| 5 | fn other_exit() -> unreachable { | ||
| 6 | if (true) { exit(0); } | ||
| 7 | // the unreachable statement is the programmer assuring the compiler that this code is impossible to execute. | ||
| 8 | unreachable; | ||
| 9 | } | ||
| 10 | |||
| 11 | export fn main(argc: isize, argv: &&u8, env: &&u8) -> unreachable { | ||
| 12 | const a : i32 = 1; | ||
| 13 | const b = 2 as i32; | ||
| 14 | // const c : i32; // not yet support for const variables | ||
| 15 | // const d; // parse error | ||
| 16 | if (a + b == 3) { | ||
| 17 | const no_conflict : i32 = 5; | ||
| 18 | if (no_conflict == 5) { print_str("OK 1\n" as string); } | ||
| 19 | } | ||
| 20 | |||
| 21 | const c = { | ||
| 22 | const no_conflict : i32 = 10; | ||
| 23 | no_conflict | ||
| 24 | }; | ||
| 25 | if (c == 10) { print_str("OK 2\n" as string); } | ||
| 26 | |||
| 27 | void_fun(1, void, 2); | ||
| 28 | |||
| 29 | test_mutable_vars(); | ||
| 30 | |||
| 31 | other_exit(); | ||
| 32 | } | ||
| 33 | |||
| 34 | fn void_fun(a : i32, b : void, c : i32) -> void { | ||
| 35 | const x = a + 1; // i32 | ||
| 36 | const y = c + 1; // i32 | ||
| 37 | const z = b; // void | ||
| 38 | const w : void = z; // void | ||
| 39 | if (x + y == 4) { return w; } | ||
| 40 | } | ||
| 41 | |||
| 42 | fn test_mutable_vars() { | ||
| 43 | var i : i32 = 0; | ||
| 44 | loop_start: | ||
| 45 | if i == 3 { | ||
| 46 | goto done; | ||
| 47 | } | ||
| 48 | print_str("loop\n" as string); | ||
| 49 | i = i + 1; | ||
| 50 | goto loop_start; | ||
| 51 | done: | ||
| 52 | } | ||
example/guess_number/main.zig+3-3| ... | @@ -3,12 +3,12 @@ export executable "guess_number"; | ... | @@ -3,12 +3,12 @@ export executable "guess_number"; |
| 3 | use "std.zig"; | 3 | use "std.zig"; |
| 4 | use "rand.zig"; | 4 | use "rand.zig"; |
| 5 | 5 | ||
| 6 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 6 | pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { |
| 7 | print_str("Welcome to the Guess Number Game in Zig.\n"); | 7 | print_str("Welcome to the Guess Number Game in Zig.\n"); |
| 8 | 8 | ||
| 9 | var seed : u32; | 9 | var seed : u32; |
| 10 | const err = os_get_random_bytes(&seed as &u8, #sizeof(u32)); | 10 | const err = os_get_random_bytes(&seed as (&u8), @sizeof(u32)); |
| 11 | if (err != #sizeof(u32)) { | 11 | if (err != @sizeof(u32)) { |
| 12 | // TODO full error message | 12 | // TODO full error message |
| 13 | fprint_str(stderr_fileno, "unable to get random bytes\n"); | 13 | fprint_str(stderr_fileno, "unable to get random bytes\n"); |
| 14 | return 1; | 14 | return 1; |
example/hello_world/hello.zig+1-1| ... | @@ -2,7 +2,7 @@ export executable "hello"; | ... | @@ -2,7 +2,7 @@ export executable "hello"; |
| 2 | 2 | ||
| 3 | use "std.zig"; | 3 | use "std.zig"; |
| 4 | 4 | ||
| 5 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 5 | pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { |
| 6 | print_str("Hello, world!\n"); | 6 | print_str("Hello, world!\n"); |
| 7 | return 0; | 7 | return 0; |
| 8 | } | 8 | } |
example/hello_world/hello_libc.zig+2-3| ... | @@ -2,11 +2,10 @@ export executable "hello"; | ... | @@ -2,11 +2,10 @@ export executable "hello"; |
| 2 | 2 | ||
| 3 | #link("c") | 3 | #link("c") |
| 4 | extern { | 4 | extern { |
| 5 | fn printf(__format: &const u8, ...) -> i32; | 5 | fn printf(__format: &const u8, ...) i32; |
| 6 | fn exit(__status: i32) -> unreachable; | ||
| 7 | } | 6 | } |
| 8 | 7 | ||
| 9 | export fn main(argc: i32, argv: &&u8, env: &&u8) -> i32 { | 8 | export fn main(argc: i32, argv: &&u8, env: &&u8) i32 => { |
| 10 | printf(c"Hello, world!\n"); | 9 | printf(c"Hello, world!\n"); |
| 11 | return 0; | 10 | return 0; |
| 12 | } | 11 | } |
example/list/list.zig+45-7| ... | @@ -1,16 +1,16 @@ | ... | @@ -1,16 +1,16 @@ |
| 1 | pub struct List#(T: type) { | 1 | pub struct List#(T: type) { |
| 2 | items: ?&T, | 2 | items: ?&T, |
| 3 | length: usize, | 3 | length: isize, |
| 4 | capacity: usize, | 4 | capacity: isize, |
| 5 | 5 | ||
| 6 | pub fn (l: &List) deinit() { | 6 | pub fn deinit(l: &List) { |
| 7 | free(l.items); | 7 | free(l.items); |
| 8 | l.items = None; | 8 | l.items = null; |
| 9 | } | 9 | } |
| 10 | 10 | ||
| 11 | pub fn append(l: &List, item: T) -> error { | 11 | pub fn append(l: &List, item: T) -> error { |
| 12 | const err = l.ensure_capacity(l.length + 1); | 12 | const err = l.ensure_capacity(l.length + 1); |
| 13 | if err != Error.None { | 13 | if err != error.None { |
| 14 | return err; | 14 | return err; |
| 15 | } | 15 | } |
| 16 | const raw_items = l.items ?? unreachable; | 16 | const raw_items = l.items ?? unreachable; |
| ... | @@ -47,11 +47,11 @@ pub struct List#(T: type) { | ... | @@ -47,11 +47,11 @@ pub struct List#(T: type) { |
| 47 | better_capacity *= 2; | 47 | better_capacity *= 2; |
| 48 | } | 48 | } |
| 49 | if better_capacity != l.capacity { | 49 | if better_capacity != l.capacity { |
| 50 | const new_items = realloc(l.items, better_capacity) ?? { return Error.NoMem }; | 50 | const new_items = realloc(l.items, better_capacity) ?? { return error.NoMem }; |
| 51 | l.items = new_items; | 51 | l.items = new_items; |
| 52 | l.capacity = better_capacity; | 52 | l.capacity = better_capacity; |
| 53 | } | 53 | } |
| 54 | Error.None | 54 | error.None |
| 55 | } | 55 | } |
| 56 | } | 56 | } |
| 57 | 57 | ||
| ... | @@ -64,3 +64,41 @@ pub fn realloc#(T: type)(ptr: ?&T, new_count: usize) -> ?&T { | ... | @@ -64,3 +64,41 @@ pub fn realloc#(T: type)(ptr: ?&T, new_count: usize) -> ?&T { |
| 64 | pub fn free#(T: type)(ptr: ?&T) { | 64 | pub fn free#(T: type)(ptr: ?&T) { |
| 65 | 65 | ||
| 66 | } | 66 | } |
| 67 | |||
| 68 | |||
| 69 | ////////////////// alternate | ||
| 70 | |||
| 71 | // previously proposed, but with : instead of -> | ||
| 72 | // `:` means "parser should expect a type now" | ||
| 73 | fn max#(T :type)(a :T, b :T) :T { | ||
| 74 | if (a > b) a else b | ||
| 75 | } | ||
| 76 | |||
| 77 | // andy's new idea | ||
| 78 | // parameters can talk about @typeof() for previous parameters. | ||
| 79 | // using :T here is equivalent to @child_type(@typeof(T)) | ||
| 80 | fn max(T :type, a :T, b :T) :T { | ||
| 81 | if (a > b) a else b | ||
| 82 | } | ||
| 83 | |||
| 84 | fn f() { | ||
| 85 | const x :i32 = 1234; | ||
| 86 | const y :i32 = 5678; | ||
| 87 | const z = max(@typeof(x), x, y); | ||
| 88 | } | ||
| 89 | |||
| 90 | // So, type-generic functions don't need any fancy syntax. type-generic | ||
| 91 | // containers still do, though: | ||
| 92 | |||
| 93 | pub struct List(T :type) { | ||
| 94 | items :?&T, | ||
| 95 | length :isize, | ||
| 96 | capacity :isize, | ||
| 97 | } | ||
| 98 | |||
| 99 | // Types are always marked with ':' so we don't need '#' to indicate type generic parameters. | ||
| 100 | |||
| 101 | fn f() { | ||
| 102 | var list :List(:u8); | ||
| 103 | } | ||
| 104 |
example/maybe_type/main.zig+2-2| ... | @@ -2,7 +2,7 @@ export executable "maybe_type"; | ... | @@ -2,7 +2,7 @@ export executable "maybe_type"; |
| 2 | 2 | ||
| 3 | use "std.zig"; | 3 | use "std.zig"; |
| 4 | 4 | ||
| 5 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 5 | pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { |
| 6 | const x : ?bool = true; | 6 | const x : ?bool = true; |
| 7 | 7 | ||
| 8 | if (const y ?= x) { | 8 | if (const y ?= x) { |
| ... | @@ -25,7 +25,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | ... | @@ -25,7 +25,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { |
| 25 | 25 | ||
| 26 | const final_x : ?i32 = 13; | 26 | const final_x : ?i32 = 13; |
| 27 | 27 | ||
| 28 | const num = final_x ?? unreachable; | 28 | const num = final_x ?? unreachable{}; |
| 29 | 29 | ||
| 30 | if (num != 13) { | 30 | if (num != 13) { |
| 31 | print_str("BAD\n"); | 31 | print_str("BAD\n"); |
example/multiple_files/foo.zig+2-2| ... | @@ -2,10 +2,10 @@ use "std.zig"; | ... | @@ -2,10 +2,10 @@ use "std.zig"; |
| 2 | 2 | ||
| 3 | // purposefully conflicting function with main.zig | 3 | // purposefully conflicting function with main.zig |
| 4 | // but it's private so it should be OK | 4 | // but it's private so it should be OK |
| 5 | fn private_function() { | 5 | fn private_function() => { |
| 6 | print_str("OK 1\n"); | 6 | print_str("OK 1\n"); |
| 7 | } | 7 | } |
| 8 | 8 | ||
| 9 | pub fn print_text() { | 9 | pub fn print_text() => { |
| 10 | private_function(); | 10 | private_function(); |
| 11 | } | 11 | } |
example/multiple_files/main.zig+2-2| ... | @@ -3,12 +3,12 @@ export executable "test-multiple-files"; | ... | @@ -3,12 +3,12 @@ export executable "test-multiple-files"; |
| 3 | use "std.zig"; | 3 | use "std.zig"; |
| 4 | use "foo.zig"; | 4 | use "foo.zig"; |
| 5 | 5 | ||
| 6 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 6 | pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { |
| 7 | private_function(); | 7 | private_function(); |
| 8 | print_str("OK 2\n"); | 8 | print_str("OK 2\n"); |
| 9 | return 0; | 9 | return 0; |
| 10 | } | 10 | } |
| 11 | 11 | ||
| 12 | fn private_function() { | 12 | fn private_function() => { |
| 13 | print_text(); | 13 | print_text(); |
| 14 | } | 14 | } |
example/structs/structs.zig deleted-87| ... | @@ -1,87 +0,0 @@ | ||
| 1 | export executable "structs"; | ||
| 2 | |||
| 3 | use "std.zig"; | ||
| 4 | |||
| 5 | pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { | ||
| 6 | var foo : Foo; | ||
| 7 | |||
| 8 | foo.a = foo.a + 1; | ||
| 9 | |||
| 10 | foo.b = foo.a == 1; | ||
| 11 | |||
| 12 | test_foo(foo); | ||
| 13 | |||
| 14 | modify_foo(&foo); | ||
| 15 | |||
| 16 | if foo.c != 100 { | ||
| 17 | print_str("BAD\n"); | ||
| 18 | } | ||
| 19 | |||
| 20 | test_point_to_self(); | ||
| 21 | |||
| 22 | test_byval_assign(); | ||
| 23 | |||
| 24 | test_initializer(); | ||
| 25 | |||
| 26 | print_str("OK\n"); | ||
| 27 | return 0; | ||
| 28 | } | ||
| 29 | |||
| 30 | struct Foo { | ||
| 31 | a : i32, | ||
| 32 | b : bool, | ||
| 33 | c : f32, | ||
| 34 | } | ||
| 35 | |||
| 36 | struct Node { | ||
| 37 | val: Val, | ||
| 38 | next: &Node, | ||
| 39 | } | ||
| 40 | |||
| 41 | struct Val { | ||
| 42 | x: i32, | ||
| 43 | } | ||
| 44 | |||
| 45 | fn test_foo(foo : Foo) { | ||
| 46 | if !foo.b { | ||
| 47 | print_str("BAD\n"); | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | fn modify_foo(foo : &Foo) { | ||
| 52 | foo.c = 100; | ||
| 53 | } | ||
| 54 | |||
| 55 | fn test_point_to_self() { | ||
| 56 | var root : Node; | ||
| 57 | root.val.x = 1; | ||
| 58 | |||
| 59 | var node : Node; | ||
| 60 | node.next = &root; | ||
| 61 | node.val.x = 2; | ||
| 62 | |||
| 63 | root.next = &node; | ||
| 64 | |||
| 65 | if node.next.next.next.val.x != 1 { | ||
| 66 | print_str("BAD\n"); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | fn test_byval_assign() { | ||
| 71 | var foo1 : Foo; | ||
| 72 | var foo2 : Foo; | ||
| 73 | |||
| 74 | foo1.a = 1234; | ||
| 75 | |||
| 76 | if foo2.a != 0 { print_str("BAD\n"); } | ||
| 77 | |||
| 78 | foo2 = foo1; | ||
| 79 | |||
| 80 | if foo2.a != 1234 { print_str("BAD - byval assignment failed\n"); } | ||
| 81 | |||
| 82 | } | ||
| 83 | |||
| 84 | fn test_initializer() { | ||
| 85 | const val = Val { .x = 42 }; | ||
| 86 | if val.x != 42 { print_str("BAD\n"); } | ||
| 87 | } | ||
src/all_types.hpp+30-64| ... | @@ -100,7 +100,6 @@ enum NodeType { | ... | @@ -100,7 +100,6 @@ enum NodeType { |
| 100 | NodeTypeFnDef, | 100 | NodeTypeFnDef, |
| 101 | NodeTypeFnDecl, | 101 | NodeTypeFnDecl, |
| 102 | NodeTypeParamDecl, | 102 | NodeTypeParamDecl, |
| 103 | NodeTypeType, | ||
| 104 | NodeTypeBlock, | 103 | NodeTypeBlock, |
| 105 | NodeTypeExternBlock, | 104 | NodeTypeExternBlock, |
| 106 | NodeTypeDirective, | 105 | NodeTypeDirective, |
| ... | @@ -111,7 +110,6 @@ enum NodeType { | ... | @@ -111,7 +110,6 @@ enum NodeType { |
| 111 | NodeTypeNumberLiteral, | 110 | NodeTypeNumberLiteral, |
| 112 | NodeTypeStringLiteral, | 111 | NodeTypeStringLiteral, |
| 113 | NodeTypeCharLiteral, | 112 | NodeTypeCharLiteral, |
| 114 | NodeTypeUnreachable, | ||
| 115 | NodeTypeSymbol, | 113 | NodeTypeSymbol, |
| 116 | NodeTypePrefixOpExpr, | 114 | NodeTypePrefixOpExpr, |
| 117 | NodeTypeFnCallExpr, | 115 | NodeTypeFnCallExpr, |
| ... | @@ -119,7 +117,6 @@ enum NodeType { | ... | @@ -119,7 +117,6 @@ enum NodeType { |
| 119 | NodeTypeSliceExpr, | 117 | NodeTypeSliceExpr, |
| 120 | NodeTypeFieldAccessExpr, | 118 | NodeTypeFieldAccessExpr, |
| 121 | NodeTypeUse, | 119 | NodeTypeUse, |
| 122 | NodeTypeVoid, | ||
| 123 | NodeTypeBoolLiteral, | 120 | NodeTypeBoolLiteral, |
| 124 | NodeTypeNullLiteral, | 121 | NodeTypeNullLiteral, |
| 125 | NodeTypeIfBoolExpr, | 122 | NodeTypeIfBoolExpr, |
| ... | @@ -132,10 +129,9 @@ enum NodeType { | ... | @@ -132,10 +129,9 @@ enum NodeType { |
| 132 | NodeTypeAsmExpr, | 129 | NodeTypeAsmExpr, |
| 133 | NodeTypeStructDecl, | 130 | NodeTypeStructDecl, |
| 134 | NodeTypeStructField, | 131 | NodeTypeStructField, |
| 135 | NodeTypeStructValueExpr, | 132 | NodeTypeContainerInitExpr, |
| 136 | NodeTypeStructValueField, | 133 | NodeTypeStructValueField, |
| 137 | NodeTypeCompilerFnExpr, | 134 | NodeTypeArrayType, |
| 138 | NodeTypeCompilerFnType, | ||
| 139 | }; | 135 | }; |
| 140 | 136 | ||
| 141 | struct AstNodeRoot { | 137 | struct AstNodeRoot { |
| ... | @@ -185,30 +181,10 @@ struct AstNodeFnDecl { | ... | @@ -185,30 +181,10 @@ struct AstNodeFnDecl { |
| 185 | struct AstNodeParamDecl { | 181 | struct AstNodeParamDecl { |
| 186 | Buf name; | 182 | Buf name; |
| 187 | AstNode *type; | 183 | AstNode *type; |
| 188 | |||
| 189 | // populated by semantic analyzer | ||
| 190 | VariableTableEntry *variable; | ||
| 191 | }; | ||
| 192 | |||
| 193 | enum AstNodeTypeType { | ||
| 194 | AstNodeTypeTypePrimitive, | ||
| 195 | AstNodeTypeTypePointer, | ||
| 196 | AstNodeTypeTypeArray, | ||
| 197 | AstNodeTypeTypeMaybe, | ||
| 198 | AstNodeTypeTypeCompilerExpr, | ||
| 199 | }; | ||
| 200 | |||
| 201 | struct AstNodeType { | ||
| 202 | AstNodeTypeType type; | ||
| 203 | Buf primitive_name; | ||
| 204 | AstNode *child_type; | ||
| 205 | AstNode *array_size; // can be null | ||
| 206 | bool is_const; | ||
| 207 | bool is_noalias; | 184 | bool is_noalias; |
| 208 | AstNode *compiler_expr; | ||
| 209 | 185 | ||
| 210 | // populated by semantic analyzer | 186 | // populated by semantic analyzer |
| 211 | TypeTableEntry *entry; | 187 | VariableTableEntry *variable; |
| 212 | }; | 188 | }; |
| 213 | 189 | ||
| 214 | struct AstNodeBlock { | 190 | struct AstNodeBlock { |
| ... | @@ -295,6 +271,7 @@ struct AstNodeFnCallExpr { | ... | @@ -295,6 +271,7 @@ struct AstNodeFnCallExpr { |
| 295 | // populated by semantic analyzer: | 271 | // populated by semantic analyzer: |
| 296 | BuiltinFnEntry *builtin_fn; | 272 | BuiltinFnEntry *builtin_fn; |
| 297 | Expr resolved_expr; | 273 | Expr resolved_expr; |
| 274 | NumLitCodeGen resolved_num_lit; | ||
| 298 | }; | 275 | }; |
| 299 | 276 | ||
| 300 | struct AstNodeArrayAccessExpr { | 277 | struct AstNodeArrayAccessExpr { |
| ... | @@ -360,6 +337,7 @@ enum PrefixOp { | ... | @@ -360,6 +337,7 @@ enum PrefixOp { |
| 360 | PrefixOpAddressOf, | 337 | PrefixOpAddressOf, |
| 361 | PrefixOpConstAddressOf, | 338 | PrefixOpConstAddressOf, |
| 362 | PrefixOpDereference, | 339 | PrefixOpDereference, |
| 340 | PrefixOpMaybe, | ||
| 363 | }; | 341 | }; |
| 364 | 342 | ||
| 365 | struct AstNodePrefixOpExpr { | 343 | struct AstNodePrefixOpExpr { |
| ... | @@ -537,30 +515,19 @@ struct AstNodeStructValueField { | ... | @@ -537,30 +515,19 @@ struct AstNodeStructValueField { |
| 537 | TypeStructField *type_struct_field; | 515 | TypeStructField *type_struct_field; |
| 538 | }; | 516 | }; |
| 539 | 517 | ||
| 540 | struct AstNodeStructValueExpr { | 518 | enum ContainerInitKind { |
| 541 | AstNode *type; | 519 | ContainerInitKindStruct, |
| 542 | ZigList<AstNode *> fields; | 520 | ContainerInitKindArray, |
| 543 | |||
| 544 | // populated by semantic analyzer | ||
| 545 | StructValExprCodeGen codegen; | ||
| 546 | Expr resolved_expr; | ||
| 547 | }; | ||
| 548 | |||
| 549 | struct AstNodeCompilerFnExpr { | ||
| 550 | Buf name; | ||
| 551 | AstNode *expr; | ||
| 552 | |||
| 553 | // populated by semantic analyzer | ||
| 554 | Expr resolved_expr; | ||
| 555 | }; | 521 | }; |
| 556 | 522 | ||
| 557 | struct AstNodeCompilerFnType { | 523 | struct AstNodeContainerInitExpr { |
| 558 | Buf name; | ||
| 559 | AstNode *type; | 524 | AstNode *type; |
| 525 | ZigList<AstNode *> entries; | ||
| 526 | ContainerInitKind kind; | ||
| 560 | 527 | ||
| 561 | // populated by semantic analyzer | 528 | // populated by semantic analyzer |
| 529 | StructValExprCodeGen resolved_struct_val_expr; | ||
| 562 | Expr resolved_expr; | 530 | Expr resolved_expr; |
| 563 | NumLitCodeGen resolved_num_lit; | ||
| 564 | }; | 531 | }; |
| 565 | 532 | ||
| 566 | struct AstNodeNullLiteral { | 533 | struct AstNodeNullLiteral { |
| ... | @@ -569,16 +536,6 @@ struct AstNodeNullLiteral { | ... | @@ -569,16 +536,6 @@ struct AstNodeNullLiteral { |
| 569 | Expr resolved_expr; | 536 | Expr resolved_expr; |
| 570 | }; | 537 | }; |
| 571 | 538 | ||
| 572 | struct AstNodeVoidExpr { | ||
| 573 | // populated by semantic analyzer | ||
| 574 | Expr resolved_expr; | ||
| 575 | }; | ||
| 576 | |||
| 577 | struct AstNodeUnreachableExpr { | ||
| 578 | // populated by semantic analyzer | ||
| 579 | Expr resolved_expr; | ||
| 580 | }; | ||
| 581 | |||
| 582 | struct AstNodeSymbolExpr { | 539 | struct AstNodeSymbolExpr { |
| 583 | Buf symbol; | 540 | Buf symbol; |
| 584 | 541 | ||
| ... | @@ -603,6 +560,15 @@ struct AstNodeContinueExpr { | ... | @@ -603,6 +560,15 @@ struct AstNodeContinueExpr { |
| 603 | Expr resolved_expr; | 560 | Expr resolved_expr; |
| 604 | }; | 561 | }; |
| 605 | 562 | ||
| 563 | struct AstNodeArrayType { | ||
| 564 | AstNode *size; | ||
| 565 | AstNode *child_type; | ||
| 566 | bool is_const; | ||
| 567 | |||
| 568 | // populated by semantic analyzer | ||
| 569 | Expr resolved_expr; | ||
| 570 | }; | ||
| 571 | |||
| 606 | struct AstNode { | 572 | struct AstNode { |
| 607 | enum NodeType type; | 573 | enum NodeType type; |
| 608 | int line; | 574 | int line; |
| ... | @@ -615,7 +581,6 @@ struct AstNode { | ... | @@ -615,7 +581,6 @@ struct AstNode { |
| 615 | AstNodeFnDef fn_def; | 581 | AstNodeFnDef fn_def; |
| 616 | AstNodeFnDecl fn_decl; | 582 | AstNodeFnDecl fn_decl; |
| 617 | AstNodeFnProto fn_proto; | 583 | AstNodeFnProto fn_proto; |
| 618 | AstNodeType type; | ||
| 619 | AstNodeParamDecl param_decl; | 584 | AstNodeParamDecl param_decl; |
| 620 | AstNodeBlock block; | 585 | AstNodeBlock block; |
| 621 | AstNodeReturnExpr return_expr; | 586 | AstNodeReturnExpr return_expr; |
| ... | @@ -641,17 +606,14 @@ struct AstNode { | ... | @@ -641,17 +606,14 @@ struct AstNode { |
| 641 | AstNodeStringLiteral string_literal; | 606 | AstNodeStringLiteral string_literal; |
| 642 | AstNodeCharLiteral char_literal; | 607 | AstNodeCharLiteral char_literal; |
| 643 | AstNodeNumberLiteral number_literal; | 608 | AstNodeNumberLiteral number_literal; |
| 644 | AstNodeStructValueExpr struct_val_expr; | 609 | AstNodeContainerInitExpr container_init_expr; |
| 645 | AstNodeStructValueField struct_val_field; | 610 | AstNodeStructValueField struct_val_field; |
| 646 | AstNodeCompilerFnExpr compiler_fn_expr; | ||
| 647 | AstNodeCompilerFnType compiler_fn_type; | ||
| 648 | AstNodeNullLiteral null_literal; | 611 | AstNodeNullLiteral null_literal; |
| 649 | AstNodeVoidExpr void_expr; | ||
| 650 | AstNodeUnreachableExpr unreachable_expr; | ||
| 651 | AstNodeSymbolExpr symbol_expr; | 612 | AstNodeSymbolExpr symbol_expr; |
| 652 | AstNodeBoolLiteral bool_literal; | 613 | AstNodeBoolLiteral bool_literal; |
| 653 | AstNodeBreakExpr break_expr; | 614 | AstNodeBreakExpr break_expr; |
| 654 | AstNodeContinueExpr continue_expr; | 615 | AstNodeContinueExpr continue_expr; |
| 616 | AstNodeArrayType array_type; | ||
| 655 | } data; | 617 | } data; |
| 656 | }; | 618 | }; |
| 657 | 619 | ||
| ... | @@ -670,7 +632,6 @@ struct AsmToken { | ... | @@ -670,7 +632,6 @@ struct AsmToken { |
| 670 | struct TypeTableEntryPointer { | 632 | struct TypeTableEntryPointer { |
| 671 | TypeTableEntry *child_type; | 633 | TypeTableEntry *child_type; |
| 672 | bool is_const; | 634 | bool is_const; |
| 673 | bool is_noalias; | ||
| 674 | }; | 635 | }; |
| 675 | 636 | ||
| 676 | struct TypeTableEntryInt { | 637 | struct TypeTableEntryInt { |
| ... | @@ -770,8 +731,8 @@ struct TypeTableEntry { | ... | @@ -770,8 +731,8 @@ struct TypeTableEntry { |
| 770 | } data; | 731 | } data; |
| 771 | 732 | ||
| 772 | // use these fields to make sure we don't duplicate type table entries for the same type | 733 | // use these fields to make sure we don't duplicate type table entries for the same type |
| 773 | TypeTableEntry *pointer_parent[2][2]; // 0 - const. 1 - noalias | 734 | TypeTableEntry *pointer_parent[2]; |
| 774 | TypeTableEntry *unknown_size_array_parent[2][2]; // 0 - const. 1 - noalias | 735 | TypeTableEntry *unknown_size_array_parent[2]; |
| 775 | HashMap<uint64_t, TypeTableEntry *, uint64_hash, uint64_eq> arrays_by_size; | 736 | HashMap<uint64_t, TypeTableEntry *, uint64_hash, uint64_eq> arrays_by_size; |
| 776 | TypeTableEntry *maybe_parent; | 737 | TypeTableEntry *maybe_parent; |
| 777 | TypeTableEntry *meta_parent; | 738 | TypeTableEntry *meta_parent; |
| ... | @@ -830,6 +791,11 @@ enum BuiltinFnId { | ... | @@ -830,6 +791,11 @@ enum BuiltinFnId { |
| 830 | BuiltinFnIdArithmeticWithOverflow, | 791 | BuiltinFnIdArithmeticWithOverflow, |
| 831 | BuiltinFnIdMemcpy, | 792 | BuiltinFnIdMemcpy, |
| 832 | BuiltinFnIdMemset, | 793 | BuiltinFnIdMemset, |
| 794 | BuiltinFnIdSizeof, | ||
| 795 | BuiltinFnIdMaxValue, | ||
| 796 | BuiltinFnIdMinValue, | ||
| 797 | BuiltinFnIdValueCount, | ||
| 798 | BuiltinFnIdTypeof, | ||
| 833 | }; | 799 | }; |
| 834 | 800 | ||
| 835 | struct BuiltinFnEntry { | 801 | struct BuiltinFnEntry { |
src/analyze.cpp+570-576| ... | @@ -15,10 +15,10 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -15,10 +15,10 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 15 | TypeTableEntry *expected_type, AstNode *node); | 15 | TypeTableEntry *expected_type, AstNode *node); |
| 16 | static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context, | 16 | static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context, |
| 17 | AstNode *node, AstNodeNumberLiteral *out_number_literal); | 17 | AstNode *node, AstNodeNumberLiteral *out_number_literal); |
| 18 | static void collect_type_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *type_node, TopLevelDecl *decl_node); | ||
| 19 | static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import, | 18 | static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import, |
| 20 | BlockContext *context, TypeTableEntry *expected_type, AstNode *node); | 19 | BlockContext *context, TypeTableEntry *expected_type, AstNode *node); |
| 21 | static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *struct_type); | 20 | static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *struct_type); |
| 21 | static TypeTableEntry *unwrapped_node_type(AstNode *node); | ||
| 22 | 22 | ||
| 23 | static AstNode *first_executing_node(AstNode *node) { | 23 | static AstNode *first_executing_node(AstNode *node) { |
| 24 | switch (node->type) { | 24 | switch (node->type) { |
| ... | @@ -40,7 +40,6 @@ static AstNode *first_executing_node(AstNode *node) { | ... | @@ -40,7 +40,6 @@ static AstNode *first_executing_node(AstNode *node) { |
| 40 | case NodeTypeFnDef: | 40 | case NodeTypeFnDef: |
| 41 | case NodeTypeFnDecl: | 41 | case NodeTypeFnDecl: |
| 42 | case NodeTypeParamDecl: | 42 | case NodeTypeParamDecl: |
| 43 | case NodeTypeType: | ||
| 44 | case NodeTypeBlock: | 43 | case NodeTypeBlock: |
| 45 | case NodeTypeExternBlock: | 44 | case NodeTypeExternBlock: |
| 46 | case NodeTypeDirective: | 45 | case NodeTypeDirective: |
| ... | @@ -49,11 +48,9 @@ static AstNode *first_executing_node(AstNode *node) { | ... | @@ -49,11 +48,9 @@ static AstNode *first_executing_node(AstNode *node) { |
| 49 | case NodeTypeNumberLiteral: | 48 | case NodeTypeNumberLiteral: |
| 50 | case NodeTypeStringLiteral: | 49 | case NodeTypeStringLiteral: |
| 51 | case NodeTypeCharLiteral: | 50 | case NodeTypeCharLiteral: |
| 52 | case NodeTypeUnreachable: | ||
| 53 | case NodeTypeSymbol: | 51 | case NodeTypeSymbol: |
| 54 | case NodeTypePrefixOpExpr: | 52 | case NodeTypePrefixOpExpr: |
| 55 | case NodeTypeUse: | 53 | case NodeTypeUse: |
| 56 | case NodeTypeVoid: | ||
| 57 | case NodeTypeBoolLiteral: | 54 | case NodeTypeBoolLiteral: |
| 58 | case NodeTypeNullLiteral: | 55 | case NodeTypeNullLiteral: |
| 59 | case NodeTypeIfBoolExpr: | 56 | case NodeTypeIfBoolExpr: |
| ... | @@ -65,11 +62,10 @@ static AstNode *first_executing_node(AstNode *node) { | ... | @@ -65,11 +62,10 @@ static AstNode *first_executing_node(AstNode *node) { |
| 65 | case NodeTypeAsmExpr: | 62 | case NodeTypeAsmExpr: |
| 66 | case NodeTypeStructDecl: | 63 | case NodeTypeStructDecl: |
| 67 | case NodeTypeStructField: | 64 | case NodeTypeStructField: |
| 68 | case NodeTypeStructValueExpr: | ||
| 69 | case NodeTypeStructValueField: | 65 | case NodeTypeStructValueField: |
| 70 | case NodeTypeWhileExpr: | 66 | case NodeTypeWhileExpr: |
| 71 | case NodeTypeCompilerFnExpr: | 67 | case NodeTypeContainerInitExpr: |
| 72 | case NodeTypeCompilerFnType: | 68 | case NodeTypeArrayType: |
| 73 | return node; | 69 | return node; |
| 74 | } | 70 | } |
| 75 | zig_panic("unreachable"); | 71 | zig_panic("unreachable"); |
| ... | @@ -188,8 +184,9 @@ static TypeTableEntry *get_meta_type(CodeGen *g, TypeTableEntry *child_type) { | ... | @@ -188,8 +184,9 @@ static TypeTableEntry *get_meta_type(CodeGen *g, TypeTableEntry *child_type) { |
| 188 | } | 184 | } |
| 189 | } | 185 | } |
| 190 | 186 | ||
| 191 | TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const, bool is_noalias) { | 187 | TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) { |
| 192 | TypeTableEntry **parent_pointer = &child_type->pointer_parent[(is_const ? 1 : 0)][(is_noalias ? 1 : 0)]; | 188 | assert(child_type->id != TypeTableEntryIdInvalid); |
| 189 | TypeTableEntry **parent_pointer = &child_type->pointer_parent[(is_const ? 1 : 0)]; | ||
| 193 | if (*parent_pointer) { | 190 | if (*parent_pointer) { |
| 194 | return *parent_pointer; | 191 | return *parent_pointer; |
| 195 | } else { | 192 | } else { |
| ... | @@ -197,9 +194,8 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool | ... | @@ -197,9 +194,8 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool |
| 197 | entry->type_ref = LLVMPointerType(child_type->type_ref, 0); | 194 | entry->type_ref = LLVMPointerType(child_type->type_ref, 0); |
| 198 | 195 | ||
| 199 | const char *const_str = is_const ? "const " : ""; | 196 | const char *const_str = is_const ? "const " : ""; |
| 200 | const char *noalias_str = is_noalias ? "noalias " : ""; | ||
| 201 | buf_resize(&entry->name, 0); | 197 | buf_resize(&entry->name, 0); |
| 202 | buf_appendf(&entry->name, "&%s%s%s", const_str, noalias_str, buf_ptr(&child_type->name)); | 198 | buf_appendf(&entry->name, "&%s%s", const_str, buf_ptr(&child_type->name)); |
| 203 | 199 | ||
| 204 | entry->size_in_bits = g->pointer_size_bytes * 8; | 200 | entry->size_in_bits = g->pointer_size_bytes * 8; |
| 205 | entry->align_in_bits = g->pointer_size_bytes * 8; | 201 | entry->align_in_bits = g->pointer_size_bytes * 8; |
| ... | @@ -208,14 +204,13 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool | ... | @@ -208,14 +204,13 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool |
| 208 | entry->size_in_bits, entry->align_in_bits, buf_ptr(&entry->name)); | 204 | entry->size_in_bits, entry->align_in_bits, buf_ptr(&entry->name)); |
| 209 | entry->data.pointer.child_type = child_type; | 205 | entry->data.pointer.child_type = child_type; |
| 210 | entry->data.pointer.is_const = is_const; | 206 | entry->data.pointer.is_const = is_const; |
| 211 | entry->data.pointer.is_noalias = is_noalias; | ||
| 212 | 207 | ||
| 213 | *parent_pointer = entry; | 208 | *parent_pointer = entry; |
| 214 | return entry; | 209 | return entry; |
| 215 | } | 210 | } |
| 216 | } | 211 | } |
| 217 | 212 | ||
| 218 | static TypeTableEntry *get_maybe_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *child_type) { | 213 | static TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) { |
| 219 | if (child_type->maybe_parent) { | 214 | if (child_type->maybe_parent) { |
| 220 | TypeTableEntry *entry = child_type->maybe_parent; | 215 | TypeTableEntry *entry = child_type->maybe_parent; |
| 221 | return entry; | 216 | return entry; |
| ... | @@ -293,9 +288,10 @@ static TypeTableEntry *get_array_type(CodeGen *g, ImportTableEntry *import, | ... | @@ -293,9 +288,10 @@ static TypeTableEntry *get_array_type(CodeGen *g, ImportTableEntry *import, |
| 293 | } | 288 | } |
| 294 | 289 | ||
| 295 | static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, ImportTableEntry *import, | 290 | static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, ImportTableEntry *import, |
| 296 | TypeTableEntry *child_type, bool is_const, bool is_noalias) | 291 | TypeTableEntry *child_type, bool is_const) |
| 297 | { | 292 | { |
| 298 | TypeTableEntry **parent_pointer = &child_type->unknown_size_array_parent[(is_const ? 1 : 0)][(is_noalias ? 1 : 0)]; | 293 | assert(child_type->id != TypeTableEntryIdInvalid); |
| 294 | TypeTableEntry **parent_pointer = &child_type->unknown_size_array_parent[(is_const ? 1 : 0)]; | ||
| 299 | if (*parent_pointer) { | 295 | if (*parent_pointer) { |
| 300 | return *parent_pointer; | 296 | return *parent_pointer; |
| 301 | } else { | 297 | } else { |
| ... | @@ -305,7 +301,7 @@ static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, ImportTableEntry | ... | @@ -305,7 +301,7 @@ static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, ImportTableEntry |
| 305 | buf_appendf(&entry->name, "[]%s", buf_ptr(&child_type->name)); | 301 | buf_appendf(&entry->name, "[]%s", buf_ptr(&child_type->name)); |
| 306 | entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&entry->name)); | 302 | entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&entry->name)); |
| 307 | 303 | ||
| 308 | TypeTableEntry *pointer_type = get_pointer_to_type(g, child_type, is_const, is_noalias); | 304 | TypeTableEntry *pointer_type = get_pointer_to_type(g, child_type, is_const); |
| 309 | 305 | ||
| 310 | unsigned element_count = 2; | 306 | unsigned element_count = 2; |
| 311 | LLVMTypeRef element_types[] = { | 307 | LLVMTypeRef element_types[] = { |
| ... | @@ -343,6 +339,25 @@ static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, ImportTableEntry | ... | @@ -343,6 +339,25 @@ static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, ImportTableEntry |
| 343 | } | 339 | } |
| 344 | } | 340 | } |
| 345 | 341 | ||
| 342 | // like analyze expression, but expects a type. creates an error if resulting type is | ||
| 343 | // not a meta type. unwraps it if it is. | ||
| 344 | static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | ||
| 345 | AstNode *node) | ||
| 346 | { | ||
| 347 | TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, node); | ||
| 348 | if (type_entry->id == TypeTableEntryIdInvalid) { | ||
| 349 | return type_entry; | ||
| 350 | } else if (type_entry->id == TypeTableEntryIdMetaType) { | ||
| 351 | return type_entry->data.meta_type.child_type; | ||
| 352 | } else { | ||
| 353 | add_node_error(g, first_executing_node(node), | ||
| 354 | buf_sprintf("expected type, found expression")); | ||
| 355 | get_resolved_expr(node)->type_entry = g->builtin_types.entry_invalid; | ||
| 356 | return g->builtin_types.entry_invalid; | ||
| 357 | } | ||
| 358 | } | ||
| 359 | |||
| 360 | |||
| 346 | static TypeTableEntry *eval_const_expr_bin_op(CodeGen *g, BlockContext *context, | 361 | static TypeTableEntry *eval_const_expr_bin_op(CodeGen *g, BlockContext *context, |
| 347 | AstNode *node, AstNodeNumberLiteral *out_number_literal) | 362 | AstNode *node, AstNodeNumberLiteral *out_number_literal) |
| 348 | { | 363 | { |
| ... | @@ -436,6 +451,40 @@ static TypeTableEntry *eval_const_expr_bin_op(CodeGen *g, BlockContext *context, | ... | @@ -436,6 +451,40 @@ static TypeTableEntry *eval_const_expr_bin_op(CodeGen *g, BlockContext *context, |
| 436 | zig_unreachable(); | 451 | zig_unreachable(); |
| 437 | } | 452 | } |
| 438 | 453 | ||
| 454 | static TypeTableEntry *eval_const_expr_fn_call(CodeGen *g, BlockContext *context, | ||
| 455 | AstNode *node, AstNodeNumberLiteral *out_number_literal) | ||
| 456 | { | ||
| 457 | if (!node->data.fn_call_expr.is_builtin) { | ||
| 458 | return g->builtin_types.entry_invalid; | ||
| 459 | } | ||
| 460 | |||
| 461 | switch (node->data.fn_call_expr.builtin_fn->id) { | ||
| 462 | case BuiltinFnIdInvalid: | ||
| 463 | zig_unreachable(); | ||
| 464 | case BuiltinFnIdArithmeticWithOverflow: | ||
| 465 | case BuiltinFnIdMemcpy: | ||
| 466 | case BuiltinFnIdMemset: | ||
| 467 | return g->builtin_types.entry_invalid; | ||
| 468 | case BuiltinFnIdSizeof: | ||
| 469 | { | ||
| 470 | AstNode *type_node = node->data.fn_call_expr.params.at(0); | ||
| 471 | TypeTableEntry *target_type = unwrapped_node_type(type_node); | ||
| 472 | out_number_literal->overflow = false; | ||
| 473 | out_number_literal->data.x_uint = target_type->size_in_bits / 8; | ||
| 474 | out_number_literal->kind = get_number_literal_kind_unsigned(out_number_literal->data.x_uint); | ||
| 475 | return get_resolved_expr(node)->type_entry; | ||
| 476 | } | ||
| 477 | case BuiltinFnIdMaxValue: | ||
| 478 | case BuiltinFnIdMinValue: | ||
| 479 | zig_panic("TODO eval_const_expr_fn_call max/min value"); | ||
| 480 | case BuiltinFnIdValueCount: | ||
| 481 | zig_panic("TODO eval_const_expr_fn_call value_count"); | ||
| 482 | case BuiltinFnIdTypeof: | ||
| 483 | return get_resolved_expr(node)->type_entry; | ||
| 484 | } | ||
| 485 | zig_unreachable(); | ||
| 486 | } | ||
| 487 | |||
| 439 | static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context, | 488 | static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context, |
| 440 | AstNode *node, AstNodeNumberLiteral *out_number_literal) | 489 | AstNode *node, AstNodeNumberLiteral *out_number_literal) |
| 441 | { | 490 | { |
| ... | @@ -450,175 +499,25 @@ static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context, | ... | @@ -450,175 +499,25 @@ static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context, |
| 450 | return get_resolved_expr(node)->type_entry; | 499 | return get_resolved_expr(node)->type_entry; |
| 451 | case NodeTypeBinOpExpr: | 500 | case NodeTypeBinOpExpr: |
| 452 | return eval_const_expr_bin_op(g, context, node, out_number_literal); | 501 | return eval_const_expr_bin_op(g, context, node, out_number_literal); |
| 453 | case NodeTypeCompilerFnType: | ||
| 454 | { | ||
| 455 | Buf *name = &node->data.compiler_fn_type.name; | ||
| 456 | TypeTableEntry *expr_type = get_resolved_expr(node)->type_entry; | ||
| 457 | if (buf_eql_str(name, "sizeof")) { | ||
| 458 | TypeTableEntry *target_type = node->data.compiler_fn_type.type->data.type.entry; | ||
| 459 | out_number_literal->overflow = false; | ||
| 460 | out_number_literal->data.x_uint = target_type->size_in_bits / 8; | ||
| 461 | out_number_literal->kind = get_number_literal_kind_unsigned(out_number_literal->data.x_uint); | ||
| 462 | |||
| 463 | return expr_type; | ||
| 464 | } else if (buf_eql_str(name, "max_value")) { | ||
| 465 | zig_panic("TODO eval_const_expr max_value"); | ||
| 466 | } else if (buf_eql_str(name, "min_value")) { | ||
| 467 | zig_panic("TODO eval_const_expr min_value"); | ||
| 468 | } else if (buf_eql_str(name, "value_count")) { | ||
| 469 | zig_panic("TODO eval_const_expr value_count"); | ||
| 470 | } else { | ||
| 471 | return g->builtin_types.entry_invalid; | ||
| 472 | } | ||
| 473 | break; | ||
| 474 | } | ||
| 475 | case NodeTypeSymbol: | 502 | case NodeTypeSymbol: |
| 476 | { | 503 | { |
| 477 | VariableTableEntry *var = find_variable(context, &node->data.symbol_expr.symbol); | 504 | VariableTableEntry *var = find_variable(context, &node->data.symbol_expr.symbol); |
| 478 | assert(var); | 505 | assert(var); |
| 479 | AstNode *decl_node = var->decl_node; | 506 | AstNode *decl_node = var->decl_node; |
| 480 | AstNode *expr_node = decl_node->data.variable_declaration.expr; | 507 | AstNode *expr_node = decl_node->data.variable_declaration.expr; |
| 481 | BlockContext *next_context = get_resolved_expr(expr_node)->block_context; | 508 | if (expr_node) { |
| 482 | return eval_const_expr(g, next_context, expr_node, out_number_literal); | 509 | BlockContext *next_context = get_resolved_expr(expr_node)->block_context; |
| 483 | } | 510 | return eval_const_expr(g, next_context, expr_node, out_number_literal); |
| 484 | default: | ||
| 485 | return g->builtin_types.entry_invalid; | ||
| 486 | } | ||
| 487 | } | ||
| 488 | |||
| 489 | static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry *import, | ||
| 490 | BlockContext *context, bool noalias_allowed) | ||
| 491 | { | ||
| 492 | assert(node->type == NodeTypeType); | ||
| 493 | switch (node->data.type.type) { | ||
| 494 | case AstNodeTypeTypePrimitive: | ||
| 495 | { | ||
| 496 | Buf *name = &node->data.type.primitive_name; | ||
| 497 | auto table_entry = import->block_context->type_table.maybe_get(name); | ||
| 498 | if (!table_entry) { | ||
| 499 | table_entry = g->primitive_type_table.maybe_get(name); | ||
| 500 | } | ||
| 501 | if (table_entry) { | ||
| 502 | node->data.type.entry = table_entry->value; | ||
| 503 | } else { | ||
| 504 | add_node_error(g, node, | ||
| 505 | buf_sprintf("invalid type name: '%s'", buf_ptr(name))); | ||
| 506 | node->data.type.entry = g->builtin_types.entry_invalid; | ||
| 507 | } | ||
| 508 | return node->data.type.entry; | ||
| 509 | } | ||
| 510 | case AstNodeTypeTypePointer: | ||
| 511 | { | ||
| 512 | bool use_noalias = false; | ||
| 513 | if (node->data.type.is_noalias) { | ||
| 514 | if (!noalias_allowed) { | ||
| 515 | add_node_error(g, node, | ||
| 516 | buf_create_from_str("invalid noalias qualifier")); | ||
| 517 | } else { | ||
| 518 | use_noalias = true; | ||
| 519 | } | ||
| 520 | } | ||
| 521 | |||
| 522 | resolve_type(g, node->data.type.child_type, import, context, false); | ||
| 523 | TypeTableEntry *child_type = node->data.type.child_type->data.type.entry; | ||
| 524 | assert(child_type); | ||
| 525 | if (child_type->id == TypeTableEntryIdUnreachable) { | ||
| 526 | add_node_error(g, node, | ||
| 527 | buf_create_from_str("pointer to unreachable not allowed")); | ||
| 528 | node->data.type.entry = g->builtin_types.entry_invalid; | ||
| 529 | return node->data.type.entry; | ||
| 530 | } else if (child_type->id == TypeTableEntryIdInvalid) { | ||
| 531 | node->data.type.entry = child_type; | ||
| 532 | return child_type; | ||
| 533 | } else { | ||
| 534 | node->data.type.entry = get_pointer_to_type(g, child_type, node->data.type.is_const, use_noalias); | ||
| 535 | return node->data.type.entry; | ||
| 536 | } | ||
| 537 | } | ||
| 538 | case AstNodeTypeTypeArray: | ||
| 539 | { | ||
| 540 | AstNode *size_node = node->data.type.array_size; | ||
| 541 | |||
| 542 | bool use_noalias = false; | ||
| 543 | if (node->data.type.is_noalias) { | ||
| 544 | if (!noalias_allowed || size_node) { | ||
| 545 | add_node_error(g, node, | ||
| 546 | buf_create_from_str("invalid noalias qualifier")); | ||
| 547 | } else { | ||
| 548 | use_noalias = true; | ||
| 549 | } | ||
| 550 | } | ||
| 551 | |||
| 552 | TypeTableEntry *child_type = resolve_type(g, node->data.type.child_type, import, context, false); | ||
| 553 | if (child_type->id == TypeTableEntryIdUnreachable) { | ||
| 554 | add_node_error(g, node, | ||
| 555 | buf_create_from_str("array of unreachable not allowed")); | ||
| 556 | node->data.type.entry = g->builtin_types.entry_invalid; | ||
| 557 | return node->data.type.entry; | ||
| 558 | } | ||
| 559 | |||
| 560 | if (size_node) { | ||
| 561 | TypeTableEntry *size_type = analyze_expression(g, import, context, | ||
| 562 | g->builtin_types.entry_usize, size_node); | ||
| 563 | if (size_type->id == TypeTableEntryIdInvalid) { | ||
| 564 | node->data.type.entry = g->builtin_types.entry_invalid; | ||
| 565 | return node->data.type.entry; | ||
| 566 | } | ||
| 567 | |||
| 568 | AstNodeNumberLiteral number_literal; | ||
| 569 | TypeTableEntry *resolved_type = eval_const_expr(g, context, size_node, &number_literal); | ||
| 570 | |||
| 571 | if (resolved_type->id == TypeTableEntryIdInt) { | ||
| 572 | if (resolved_type->data.integral.is_signed) { | ||
| 573 | add_node_error(g, size_node, | ||
| 574 | buf_create_from_str("array size must be unsigned integer")); | ||
| 575 | node->data.type.entry = g->builtin_types.entry_invalid; | ||
| 576 | } else { | ||
| 577 | node->data.type.entry = get_array_type(g, import, child_type, number_literal.data.x_uint); | ||
| 578 | } | ||
| 579 | } else { | ||
| 580 | add_node_error(g, size_node, | ||
| 581 | buf_create_from_str("unable to resolve constant expression")); | ||
| 582 | node->data.type.entry = g->builtin_types.entry_invalid; | ||
| 583 | } | ||
| 584 | return node->data.type.entry; | ||
| 585 | } else { | ||
| 586 | node->data.type.entry = get_unknown_size_array_type(g, import, child_type, | ||
| 587 | node->data.type.is_const, use_noalias); | ||
| 588 | return node->data.type.entry; | ||
| 589 | } | ||
| 590 | |||
| 591 | } | ||
| 592 | case AstNodeTypeTypeMaybe: | ||
| 593 | { | ||
| 594 | resolve_type(g, node->data.type.child_type, import, context, false); | ||
| 595 | TypeTableEntry *child_type = node->data.type.child_type->data.type.entry; | ||
| 596 | assert(child_type); | ||
| 597 | if (child_type->id == TypeTableEntryIdUnreachable) { | ||
| 598 | add_node_error(g, node, | ||
| 599 | buf_create_from_str("maybe unreachable type not allowed")); | ||
| 600 | } else if (child_type->id == TypeTableEntryIdInvalid) { | ||
| 601 | return child_type; | ||
| 602 | } | ||
| 603 | node->data.type.entry = get_maybe_type(g, import, child_type); | ||
| 604 | return node->data.type.entry; | ||
| 605 | } | ||
| 606 | case AstNodeTypeTypeCompilerExpr: | ||
| 607 | { | ||
| 608 | AstNode *compiler_expr_node = node->data.type.compiler_expr; | ||
| 609 | Buf *fn_name = &compiler_expr_node->data.compiler_fn_expr.name; | ||
| 610 | if (buf_eql_str(fn_name, "typeof")) { | ||
| 611 | node->data.type.entry = analyze_expression(g, import, context, nullptr, | ||
| 612 | compiler_expr_node->data.compiler_fn_expr.expr); | ||
| 613 | } else { | 511 | } else { |
| 614 | add_node_error(g, node, | 512 | // can't eval it |
| 615 | buf_sprintf("invalid compiler function: '%s'", buf_ptr(fn_name))); | 513 | return g->builtin_types.entry_invalid; |
| 616 | node->data.type.entry = g->builtin_types.entry_invalid; | ||
| 617 | } | 514 | } |
| 618 | return node->data.type.entry; | ||
| 619 | } | 515 | } |
| 516 | case NodeTypeFnCallExpr: | ||
| 517 | return eval_const_expr_fn_call(g, context, node, out_number_literal); | ||
| 518 | default: | ||
| 519 | return g->builtin_types.entry_invalid; | ||
| 620 | } | 520 | } |
| 621 | zig_unreachable(); | ||
| 622 | } | 521 | } |
| 623 | 522 | ||
| 624 | static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry, | 523 | static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry, |
| ... | @@ -654,8 +553,9 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t | ... | @@ -654,8 +553,9 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 654 | for (int i = 0; i < node->data.fn_proto.params.length; i += 1) { | 553 | for (int i = 0; i < node->data.fn_proto.params.length; i += 1) { |
| 655 | AstNode *child = node->data.fn_proto.params.at(i); | 554 | AstNode *child = node->data.fn_proto.params.at(i); |
| 656 | assert(child->type == NodeTypeParamDecl); | 555 | assert(child->type == NodeTypeParamDecl); |
| 657 | TypeTableEntry *type_entry = resolve_type(g, child->data.param_decl.type, | 556 | TypeTableEntry *type_entry = analyze_type_expr(g, import, import->block_context, |
| 658 | import, import->block_context, true); | 557 | child->data.param_decl.type); |
| 558 | |||
| 659 | if (type_entry->id == TypeTableEntryIdUnreachable) { | 559 | if (type_entry->id == TypeTableEntryIdUnreachable) { |
| 660 | add_node_error(g, child->data.param_decl.type, | 560 | add_node_error(g, child->data.param_decl.type, |
| 661 | buf_sprintf("parameter of type 'unreachable' not allowed")); | 561 | buf_sprintf("parameter of type 'unreachable' not allowed")); |
| ... | @@ -667,7 +567,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t | ... | @@ -667,7 +567,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 667 | } | 567 | } |
| 668 | } | 568 | } |
| 669 | 569 | ||
| 670 | resolve_type(g, node->data.fn_proto.return_type, import, import->block_context, true); | 570 | analyze_type_expr(g, import, import->block_context, node->data.fn_proto.return_type); |
| 671 | } | 571 | } |
| 672 | 572 | ||
| 673 | static void preview_function_labels(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry) { | 573 | static void preview_function_labels(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry) { |
| ... | @@ -729,8 +629,8 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt | ... | @@ -729,8 +629,8 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt |
| 729 | AstNode *field_node = decl_node->data.struct_decl.fields.at(i); | 629 | AstNode *field_node = decl_node->data.struct_decl.fields.at(i); |
| 730 | TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i]; | 630 | TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i]; |
| 731 | type_enum_field->name = &field_node->data.struct_field.name; | 631 | type_enum_field->name = &field_node->data.struct_field.name; |
| 732 | type_enum_field->type_entry = resolve_type(g, field_node->data.struct_field.type, | 632 | type_enum_field->type_entry = analyze_type_expr(g, import, import->block_context, |
| 733 | import, import->block_context, false); | 633 | field_node->data.struct_field.type); |
| 734 | type_enum_field->value = i; | 634 | type_enum_field->value = i; |
| 735 | 635 | ||
| 736 | di_enumerators[i] = LLVMZigCreateDebugEnumerator(g->dbuilder, buf_ptr(type_enum_field->name), i); | 636 | di_enumerators[i] = LLVMZigCreateDebugEnumerator(g->dbuilder, buf_ptr(type_enum_field->name), i); |
| ... | @@ -815,7 +715,7 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt | ... | @@ -815,7 +715,7 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt |
| 815 | biggest_align_in_bits, | 715 | biggest_align_in_bits, |
| 816 | tag_type_entry->size_in_bits, 0, union_di_type); | 716 | tag_type_entry->size_in_bits, 0, union_di_type); |
| 817 | 717 | ||
| 818 | // create debug type for root struct | 718 | // create debug type for root struct |
| 819 | LLVMZigDIType *di_root_members[] = { | 719 | LLVMZigDIType *di_root_members[] = { |
| 820 | tag_member_di_type, | 720 | tag_member_di_type, |
| 821 | union_member_di_type, | 721 | union_member_di_type, |
| ... | @@ -893,8 +793,8 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE | ... | @@ -893,8 +793,8 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE |
| 893 | AstNode *field_node = decl_node->data.struct_decl.fields.at(i); | 793 | AstNode *field_node = decl_node->data.struct_decl.fields.at(i); |
| 894 | TypeStructField *type_struct_field = &struct_type->data.structure.fields[i]; | 794 | TypeStructField *type_struct_field = &struct_type->data.structure.fields[i]; |
| 895 | type_struct_field->name = &field_node->data.struct_field.name; | 795 | type_struct_field->name = &field_node->data.struct_field.name; |
| 896 | type_struct_field->type_entry = resolve_type(g, field_node->data.struct_field.type, | 796 | type_struct_field->type_entry = analyze_type_expr(g, import, import->block_context, |
| 897 | import, import->block_context, false); | 797 | field_node->data.struct_field.type); |
| 898 | type_struct_field->src_index = i; | 798 | type_struct_field->src_index = i; |
| 899 | type_struct_field->gen_index = -1; | 799 | type_struct_field->gen_index = -1; |
| 900 | 800 | ||
| ... | @@ -1144,7 +1044,6 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode | ... | @@ -1144,7 +1044,6 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode |
| 1144 | case NodeTypeFnDef: | 1044 | case NodeTypeFnDef: |
| 1145 | case NodeTypeDirective: | 1045 | case NodeTypeDirective: |
| 1146 | case NodeTypeParamDecl: | 1046 | case NodeTypeParamDecl: |
| 1147 | case NodeTypeType: | ||
| 1148 | case NodeTypeFnDecl: | 1047 | case NodeTypeFnDecl: |
| 1149 | case NodeTypeReturnExpr: | 1048 | case NodeTypeReturnExpr: |
| 1150 | case NodeTypeRoot: | 1049 | case NodeTypeRoot: |
| ... | @@ -1156,8 +1055,6 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode | ... | @@ -1156,8 +1055,6 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode |
| 1156 | case NodeTypeNumberLiteral: | 1055 | case NodeTypeNumberLiteral: |
| 1157 | case NodeTypeStringLiteral: | 1056 | case NodeTypeStringLiteral: |
| 1158 | case NodeTypeCharLiteral: | 1057 | case NodeTypeCharLiteral: |
| 1159 | case NodeTypeUnreachable: | ||
| 1160 | case NodeTypeVoid: | ||
| 1161 | case NodeTypeBoolLiteral: | 1058 | case NodeTypeBoolLiteral: |
| 1162 | case NodeTypeNullLiteral: | 1059 | case NodeTypeNullLiteral: |
| 1163 | case NodeTypeSymbol: | 1060 | case NodeTypeSymbol: |
| ... | @@ -1173,10 +1070,9 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode | ... | @@ -1173,10 +1070,9 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode |
| 1173 | case NodeTypeAsmExpr: | 1070 | case NodeTypeAsmExpr: |
| 1174 | case NodeTypeFieldAccessExpr: | 1071 | case NodeTypeFieldAccessExpr: |
| 1175 | case NodeTypeStructField: | 1072 | case NodeTypeStructField: |
| 1176 | case NodeTypeStructValueExpr: | ||
| 1177 | case NodeTypeStructValueField: | 1073 | case NodeTypeStructValueField: |
| 1178 | case NodeTypeCompilerFnExpr: | 1074 | case NodeTypeContainerInitExpr: |
| 1179 | case NodeTypeCompilerFnType: | 1075 | case NodeTypeArrayType: |
| 1180 | zig_unreachable(); | 1076 | zig_unreachable(); |
| 1181 | } | 1077 | } |
| 1182 | } | 1078 | } |
| ... | @@ -1186,13 +1082,22 @@ static FnTableEntry *get_context_fn_entry(BlockContext *context) { | ... | @@ -1186,13 +1082,22 @@ static FnTableEntry *get_context_fn_entry(BlockContext *context) { |
| 1186 | return context->fn_entry; | 1082 | return context->fn_entry; |
| 1187 | } | 1083 | } |
| 1188 | 1084 | ||
| 1085 | static TypeTableEntry *unwrapped_node_type(AstNode *node) { | ||
| 1086 | TypeTableEntry *meta_type_entry = get_resolved_expr(node)->type_entry; | ||
| 1087 | if (meta_type_entry->id == TypeTableEntryIdInvalid) { | ||
| 1088 | return meta_type_entry; | ||
| 1089 | } else { | ||
| 1090 | assert(meta_type_entry->id == TypeTableEntryIdMetaType); | ||
| 1091 | return meta_type_entry->data.meta_type.child_type; | ||
| 1092 | } | ||
| 1093 | } | ||
| 1094 | |||
| 1189 | static TypeTableEntry *get_return_type(BlockContext *context) { | 1095 | static TypeTableEntry *get_return_type(BlockContext *context) { |
| 1190 | FnTableEntry *fn_entry = get_context_fn_entry(context); | 1096 | FnTableEntry *fn_entry = get_context_fn_entry(context); |
| 1191 | AstNode *fn_proto_node = fn_entry->proto_node; | 1097 | AstNode *fn_proto_node = fn_entry->proto_node; |
| 1192 | assert(fn_proto_node->type == NodeTypeFnProto); | 1098 | assert(fn_proto_node->type == NodeTypeFnProto); |
| 1193 | AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type; | 1099 | AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type; |
| 1194 | assert(return_type_node->type == NodeTypeType); | 1100 | return unwrapped_node_type(return_type_node); |
| 1195 | return return_type_node->data.type.entry; | ||
| 1196 | } | 1101 | } |
| 1197 | 1102 | ||
| 1198 | static bool num_lit_fits_in_other_type(CodeGen *g, TypeTableEntry *literal_type, TypeTableEntry *other_type) { | 1103 | static bool num_lit_fits_in_other_type(CodeGen *g, TypeTableEntry *literal_type, TypeTableEntry *other_type) { |
| ... | @@ -1553,6 +1458,114 @@ static TypeTableEntry *analyze_enum_value_expr(CodeGen *g, ImportTableEntry *imp | ... | @@ -1553,6 +1458,114 @@ static TypeTableEntry *analyze_enum_value_expr(CodeGen *g, ImportTableEntry *imp |
| 1553 | return enum_type; | 1458 | return enum_type; |
| 1554 | } | 1459 | } |
| 1555 | 1460 | ||
| 1461 | static TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name, int *index) { | ||
| 1462 | assert(type_entry->id == TypeTableEntryIdStruct); | ||
| 1463 | for (int i = 0; i < type_entry->data.structure.field_count; i += 1) { | ||
| 1464 | TypeStructField *field = &type_entry->data.structure.fields[i]; | ||
| 1465 | if (buf_eql_buf(field->name, name)) { | ||
| 1466 | *index = i; | ||
| 1467 | return field; | ||
| 1468 | } | ||
| 1469 | } | ||
| 1470 | return nullptr; | ||
| 1471 | } | ||
| 1472 | |||
| 1473 | static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | ||
| 1474 | AstNode *node) | ||
| 1475 | { | ||
| 1476 | assert(node->type == NodeTypeContainerInitExpr); | ||
| 1477 | |||
| 1478 | AstNodeContainerInitExpr *container_init_expr = &node->data.container_init_expr; | ||
| 1479 | |||
| 1480 | ContainerInitKind kind = container_init_expr->kind; | ||
| 1481 | |||
| 1482 | TypeTableEntry *container_type = analyze_type_expr(g, import, context, container_init_expr->type); | ||
| 1483 | |||
| 1484 | if (container_type->id == TypeTableEntryIdInvalid) { | ||
| 1485 | return container_type; | ||
| 1486 | } else if (container_type->id == TypeTableEntryIdStruct) { | ||
| 1487 | switch (kind) { | ||
| 1488 | case ContainerInitKindStruct: | ||
| 1489 | { | ||
| 1490 | StructValExprCodeGen *codegen = &container_init_expr->resolved_struct_val_expr; | ||
| 1491 | codegen->type_entry = container_type; | ||
| 1492 | codegen->source_node = node; | ||
| 1493 | context->struct_val_expr_alloca_list.append(codegen); | ||
| 1494 | |||
| 1495 | |||
| 1496 | int expr_field_count = container_init_expr->entries.length; | ||
| 1497 | int actual_field_count = container_type->data.structure.field_count; | ||
| 1498 | |||
| 1499 | int *field_use_counts = allocate<int>(actual_field_count); | ||
| 1500 | for (int i = 0; i < expr_field_count; i += 1) { | ||
| 1501 | AstNode *val_field_node = container_init_expr->entries.at(i); | ||
| 1502 | assert(val_field_node->type == NodeTypeStructValueField); | ||
| 1503 | |||
| 1504 | int field_index; | ||
| 1505 | TypeStructField *type_field = find_struct_type_field(container_type, | ||
| 1506 | &val_field_node->data.struct_val_field.name, &field_index); | ||
| 1507 | |||
| 1508 | if (!type_field) { | ||
| 1509 | add_node_error(g, val_field_node, | ||
| 1510 | buf_sprintf("no member named '%s' in '%s'", | ||
| 1511 | buf_ptr(&val_field_node->data.struct_val_field.name), buf_ptr(&container_type->name))); | ||
| 1512 | continue; | ||
| 1513 | } | ||
| 1514 | |||
| 1515 | field_use_counts[field_index] += 1; | ||
| 1516 | if (field_use_counts[field_index] > 1) { | ||
| 1517 | add_node_error(g, val_field_node, buf_sprintf("duplicate field")); | ||
| 1518 | continue; | ||
| 1519 | } | ||
| 1520 | |||
| 1521 | val_field_node->data.struct_val_field.type_struct_field = type_field; | ||
| 1522 | |||
| 1523 | analyze_expression(g, import, context, type_field->type_entry, | ||
| 1524 | val_field_node->data.struct_val_field.expr); | ||
| 1525 | } | ||
| 1526 | |||
| 1527 | for (int i = 0; i < actual_field_count; i += 1) { | ||
| 1528 | if (field_use_counts[i] == 0) { | ||
| 1529 | add_node_error(g, node, | ||
| 1530 | buf_sprintf("missing field: '%s'", buf_ptr(container_type->data.structure.fields[i].name))); | ||
| 1531 | } | ||
| 1532 | } | ||
| 1533 | break; | ||
| 1534 | } | ||
| 1535 | case ContainerInitKindArray: | ||
| 1536 | add_node_error(g, node, | ||
| 1537 | buf_sprintf("struct '%s' does not support array initialization syntax", | ||
| 1538 | buf_ptr(&container_type->name))); | ||
| 1539 | break; | ||
| 1540 | } | ||
| 1541 | return container_type; | ||
| 1542 | } else if (container_type->id == TypeTableEntryIdArray) { | ||
| 1543 | zig_panic("TODO array container init"); | ||
| 1544 | return container_type; | ||
| 1545 | } else if (container_type->id == TypeTableEntryIdEnum) { | ||
| 1546 | zig_panic("TODO enum container init"); | ||
| 1547 | return container_type; | ||
| 1548 | } else if (container_type->id == TypeTableEntryIdVoid) { | ||
| 1549 | if (container_init_expr->entries.length != 0) { | ||
| 1550 | add_node_error(g, node, buf_sprintf("void expression expects no arguments")); | ||
| 1551 | return g->builtin_types.entry_invalid; | ||
| 1552 | } else { | ||
| 1553 | return container_type; | ||
| 1554 | } | ||
| 1555 | } else if (container_type->id == TypeTableEntryIdUnreachable) { | ||
| 1556 | if (container_init_expr->entries.length != 0) { | ||
| 1557 | add_node_error(g, node, buf_sprintf("unreachable expression expects no arguments")); | ||
| 1558 | return g->builtin_types.entry_invalid; | ||
| 1559 | } else { | ||
| 1560 | return container_type; | ||
| 1561 | } | ||
| 1562 | } else { | ||
| 1563 | add_node_error(g, node, | ||
| 1564 | buf_sprintf("type '%s' does not support initialization syntax", buf_ptr(&container_type->name))); | ||
| 1565 | return g->builtin_types.entry_invalid; | ||
| 1566 | } | ||
| 1567 | } | ||
| 1568 | |||
| 1556 | static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 1569 | static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 1557 | AstNode *node) | 1570 | AstNode *node) |
| 1558 | { | 1571 | { |
| ... | @@ -1585,7 +1598,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i | ... | @@ -1585,7 +1598,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i |
| 1585 | return_type = g->builtin_types.entry_usize; | 1598 | return_type = g->builtin_types.entry_usize; |
| 1586 | } else if (buf_eql_str(name, "ptr")) { | 1599 | } else if (buf_eql_str(name, "ptr")) { |
| 1587 | // TODO determine whether the pointer should be const | 1600 | // TODO determine whether the pointer should be const |
| 1588 | return_type = get_pointer_to_type(g, struct_type->data.array.child_type, false, false); | 1601 | return_type = get_pointer_to_type(g, struct_type->data.array.child_type, false); |
| 1589 | } else { | 1602 | } else { |
| 1590 | add_node_error(g, node, | 1603 | add_node_error(g, node, |
| 1591 | buf_sprintf("no member named '%s' in '%s'", buf_ptr(name), | 1604 | buf_sprintf("no member named '%s' in '%s'", buf_ptr(name), |
| ... | @@ -1623,16 +1636,16 @@ static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -1623,16 +1636,16 @@ static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import, |
| 1623 | return_type = g->builtin_types.entry_invalid; | 1636 | return_type = g->builtin_types.entry_invalid; |
| 1624 | } else if (array_type->id == TypeTableEntryIdArray) { | 1637 | } else if (array_type->id == TypeTableEntryIdArray) { |
| 1625 | return_type = get_unknown_size_array_type(g, import, array_type->data.array.child_type, | 1638 | return_type = get_unknown_size_array_type(g, import, array_type->data.array.child_type, |
| 1626 | node->data.slice_expr.is_const, false); | 1639 | node->data.slice_expr.is_const); |
| 1627 | } else if (array_type->id == TypeTableEntryIdPointer) { | 1640 | } else if (array_type->id == TypeTableEntryIdPointer) { |
| 1628 | return_type = get_unknown_size_array_type(g, import, array_type->data.pointer.child_type, | 1641 | return_type = get_unknown_size_array_type(g, import, array_type->data.pointer.child_type, |
| 1629 | node->data.slice_expr.is_const, false); | 1642 | node->data.slice_expr.is_const); |
| 1630 | } else if (array_type->id == TypeTableEntryIdStruct && | 1643 | } else if (array_type->id == TypeTableEntryIdStruct && |
| 1631 | array_type->data.structure.is_unknown_size_array) | 1644 | array_type->data.structure.is_unknown_size_array) |
| 1632 | { | 1645 | { |
| 1633 | return_type = get_unknown_size_array_type(g, import, | 1646 | return_type = get_unknown_size_array_type(g, import, |
| 1634 | array_type->data.structure.fields[0].type_entry->data.pointer.child_type, | 1647 | array_type->data.structure.fields[0].type_entry->data.pointer.child_type, |
| 1635 | node->data.slice_expr.is_const, false); | 1648 | node->data.slice_expr.is_const); |
| 1636 | } else { | 1649 | } else { |
| 1637 | add_node_error(g, node, | 1650 | add_node_error(g, node, |
| 1638 | buf_sprintf("slice of non-array type '%s'", buf_ptr(&array_type->name))); | 1651 | buf_sprintf("slice of non-array type '%s'", buf_ptr(&array_type->name))); |
| ... | @@ -1687,19 +1700,24 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -1687,19 +1700,24 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, |
| 1687 | TypeTableEntry *expected_type, AstNode *node) | 1700 | TypeTableEntry *expected_type, AstNode *node) |
| 1688 | { | 1701 | { |
| 1689 | Buf *variable_name = &node->data.symbol_expr.symbol; | 1702 | Buf *variable_name = &node->data.symbol_expr.symbol; |
| 1703 | |||
| 1704 | auto primitive_table_entry = g->primitive_type_table.maybe_get(variable_name); | ||
| 1705 | if (primitive_table_entry) { | ||
| 1706 | return get_meta_type(g, primitive_table_entry->value); | ||
| 1707 | } | ||
| 1708 | |||
| 1690 | VariableTableEntry *var = find_variable(context, variable_name); | 1709 | VariableTableEntry *var = find_variable(context, variable_name); |
| 1691 | if (var) { | 1710 | if (var) { |
| 1692 | return var->type; | 1711 | return var->type; |
| 1693 | } else { | ||
| 1694 | TypeTableEntry *container_type = find_container(context, variable_name); | ||
| 1695 | if (container_type) { | ||
| 1696 | return get_meta_type(g, container_type); | ||
| 1697 | } else { | ||
| 1698 | add_node_error(g, node, | ||
| 1699 | buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name))); | ||
| 1700 | return g->builtin_types.entry_invalid; | ||
| 1701 | } | ||
| 1702 | } | 1712 | } |
| 1713 | |||
| 1714 | TypeTableEntry *container_type = find_container(context, variable_name); | ||
| 1715 | if (container_type) { | ||
| 1716 | return get_meta_type(g, container_type); | ||
| 1717 | } | ||
| 1718 | |||
| 1719 | add_node_error(g, node, buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name))); | ||
| 1720 | return g->builtin_types.entry_invalid; | ||
| 1703 | } | 1721 | } |
| 1704 | 1722 | ||
| 1705 | static TypeTableEntry *analyze_variable_name(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 1723 | static TypeTableEntry *analyze_variable_name(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| ... | @@ -1768,7 +1786,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B | ... | @@ -1768,7 +1786,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B |
| 1768 | { | 1786 | { |
| 1769 | assert(node->type == NodeTypeCastExpr); | 1787 | assert(node->type == NodeTypeCastExpr); |
| 1770 | 1788 | ||
| 1771 | TypeTableEntry *wanted_type = resolve_type(g, node->data.cast_expr.type, import, context, false); | 1789 | TypeTableEntry *wanted_type = analyze_type_expr(g, import, context, node->data.cast_expr.type); |
| 1772 | TypeTableEntry *actual_type = analyze_expression(g, import, context, nullptr, node->data.cast_expr.expr); | 1790 | TypeTableEntry *actual_type = analyze_expression(g, import, context, nullptr, node->data.cast_expr.expr); |
| 1773 | 1791 | ||
| 1774 | if (wanted_type->id == TypeTableEntryIdInvalid || | 1792 | if (wanted_type->id == TypeTableEntryIdInvalid || |
| ... | @@ -1833,23 +1851,22 @@ static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, Bloc | ... | @@ -1833,23 +1851,22 @@ static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, Bloc |
| 1833 | TypeTableEntry *expected_rhs_type = nullptr; | 1851 | TypeTableEntry *expected_rhs_type = nullptr; |
| 1834 | if (lhs_node->type == NodeTypeSymbol) { | 1852 | if (lhs_node->type == NodeTypeSymbol) { |
| 1835 | Buf *name = &lhs_node->data.symbol_expr.symbol; | 1853 | Buf *name = &lhs_node->data.symbol_expr.symbol; |
| 1836 | VariableTableEntry *var = find_variable(block_context, name); | 1854 | if (purpose == LValPurposeAddressOf) { |
| 1837 | if (var) { | 1855 | expected_rhs_type = analyze_symbol_expr(g, import, block_context, nullptr, lhs_node); |
| 1838 | if (purpose == LValPurposeAssign && var->is_const) { | 1856 | } else { |
| 1839 | add_node_error(g, lhs_node, | 1857 | VariableTableEntry *var = find_variable(block_context, name); |
| 1840 | buf_sprintf("cannot assign to constant")); | 1858 | if (var) { |
| 1841 | expected_rhs_type = g->builtin_types.entry_invalid; | 1859 | if (var->is_const) { |
| 1842 | } else if (purpose == LValPurposeAddressOf && var->is_const && !is_ptr_const) { | 1860 | add_node_error(g, lhs_node, buf_sprintf("cannot assign to constant")); |
| 1861 | expected_rhs_type = g->builtin_types.entry_invalid; | ||
| 1862 | } else { | ||
| 1863 | expected_rhs_type = var->type; | ||
| 1864 | } | ||
| 1865 | } else { | ||
| 1843 | add_node_error(g, lhs_node, | 1866 | add_node_error(g, lhs_node, |
| 1844 | buf_sprintf("must use &const to get address of constant")); | 1867 | buf_sprintf("use of undeclared identifier '%s'", buf_ptr(name))); |
| 1845 | expected_rhs_type = g->builtin_types.entry_invalid; | 1868 | expected_rhs_type = g->builtin_types.entry_invalid; |
| 1846 | } else { | ||
| 1847 | expected_rhs_type = var->type; | ||
| 1848 | } | 1869 | } |
| 1849 | } else { | ||
| 1850 | add_node_error(g, lhs_node, | ||
| 1851 | buf_sprintf("use of undeclared identifier '%s'", buf_ptr(name))); | ||
| 1852 | expected_rhs_type = g->builtin_types.entry_invalid; | ||
| 1853 | } | 1870 | } |
| 1854 | } else if (lhs_node->type == NodeTypeArrayAccessExpr) { | 1871 | } else if (lhs_node->type == NodeTypeArrayAccessExpr) { |
| 1855 | expected_rhs_type = analyze_array_access_expr(g, import, block_context, lhs_node); | 1872 | expected_rhs_type = analyze_array_access_expr(g, import, block_context, lhs_node); |
| ... | @@ -1873,13 +1890,19 @@ static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, Bloc | ... | @@ -1873,13 +1890,19 @@ static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, Bloc |
| 1873 | } | 1890 | } |
| 1874 | } else { | 1891 | } else { |
| 1875 | if (purpose == LValPurposeAssign) { | 1892 | if (purpose == LValPurposeAssign) { |
| 1876 | add_node_error(g, lhs_node, | 1893 | add_node_error(g, lhs_node, buf_sprintf("invalid assignment target")); |
| 1877 | buf_sprintf("invalid assignment target")); | 1894 | expected_rhs_type = g->builtin_types.entry_invalid; |
| 1878 | } else if (purpose == LValPurposeAddressOf) { | 1895 | } else if (purpose == LValPurposeAddressOf) { |
| 1879 | add_node_error(g, lhs_node, | 1896 | TypeTableEntry *type_entry = analyze_expression(g, import, block_context, nullptr, lhs_node); |
| 1880 | buf_sprintf("invalid addressof target")); | 1897 | if (type_entry->id == TypeTableEntryIdInvalid) { |
| 1898 | expected_rhs_type = g->builtin_types.entry_invalid; | ||
| 1899 | } else if (type_entry->id == TypeTableEntryIdMetaType) { | ||
| 1900 | expected_rhs_type = type_entry; | ||
| 1901 | } else { | ||
| 1902 | add_node_error(g, lhs_node, buf_sprintf("invalid addressof target")); | ||
| 1903 | expected_rhs_type = g->builtin_types.entry_invalid; | ||
| 1904 | } | ||
| 1881 | } | 1905 | } |
| 1882 | expected_rhs_type = g->builtin_types.entry_invalid; | ||
| 1883 | } | 1906 | } |
| 1884 | assert(expected_rhs_type); | 1907 | assert(expected_rhs_type); |
| 1885 | return expected_rhs_type; | 1908 | return expected_rhs_type; |
| ... | @@ -1988,7 +2011,7 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa | ... | @@ -1988,7 +2011,7 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa |
| 1988 | { | 2011 | { |
| 1989 | TypeTableEntry *explicit_type = nullptr; | 2012 | TypeTableEntry *explicit_type = nullptr; |
| 1990 | if (variable_declaration->type != nullptr) { | 2013 | if (variable_declaration->type != nullptr) { |
| 1991 | explicit_type = resolve_type(g, variable_declaration->type, import, context, false); | 2014 | explicit_type = analyze_type_expr(g, import, context, variable_declaration->type); |
| 1992 | if (explicit_type->id == TypeTableEntryIdUnreachable) { | 2015 | if (explicit_type->id == TypeTableEntryIdUnreachable) { |
| 1993 | add_node_error(g, variable_declaration->type, | 2016 | add_node_error(g, variable_declaration->type, |
| 1994 | buf_sprintf("variable of type 'unreachable' not allowed")); | 2017 | buf_sprintf("variable of type 'unreachable' not allowed")); |
| ... | @@ -2109,78 +2132,46 @@ static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry | ... | @@ -2109,78 +2132,46 @@ static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry |
| 2109 | } | 2132 | } |
| 2110 | } | 2133 | } |
| 2111 | 2134 | ||
| 2112 | static TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name, int *index) { | 2135 | static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 2113 | assert(type_entry->id == TypeTableEntryIdStruct); | ||
| 2114 | for (int i = 0; i < type_entry->data.structure.field_count; i += 1) { | ||
| 2115 | TypeStructField *field = &type_entry->data.structure.fields[i]; | ||
| 2116 | if (buf_eql_buf(field->name, name)) { | ||
| 2117 | *index = i; | ||
| 2118 | return field; | ||
| 2119 | } | ||
| 2120 | } | ||
| 2121 | return nullptr; | ||
| 2122 | } | ||
| 2123 | |||
| 2124 | static TypeTableEntry *analyze_struct_val_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | ||
| 2125 | TypeTableEntry *expected_type, AstNode *node) | 2136 | TypeTableEntry *expected_type, AstNode *node) |
| 2126 | { | 2137 | { |
| 2127 | assert(node->type == NodeTypeStructValueExpr); | 2138 | AstNode *size_node = node->data.array_type.size; |
| 2128 | |||
| 2129 | AstNodeStructValueExpr *struct_val_expr = &node->data.struct_val_expr; | ||
| 2130 | 2139 | ||
| 2131 | TypeTableEntry *type_entry = resolve_type(g, struct_val_expr->type, import, context, false); | 2140 | TypeTableEntry *child_type = analyze_type_expr(g, import, context, node->data.array_type.child_type); |
| 2132 | 2141 | ||
| 2133 | if (type_entry->id == TypeTableEntryIdInvalid) { | 2142 | if (child_type->id == TypeTableEntryIdUnreachable) { |
| 2143 | add_node_error(g, node, buf_create_from_str("array of unreachable not allowed")); | ||
| 2134 | return g->builtin_types.entry_invalid; | 2144 | return g->builtin_types.entry_invalid; |
| 2135 | } else if (type_entry->id != TypeTableEntryIdStruct) { | 2145 | } else if (child_type->id == TypeTableEntryIdInvalid) { |
| 2136 | add_node_error(g, node, | ||
| 2137 | buf_sprintf("type '%s' is not a struct", buf_ptr(&type_entry->name))); | ||
| 2138 | return g->builtin_types.entry_invalid; | 2146 | return g->builtin_types.entry_invalid; |
| 2139 | } | 2147 | } |
| 2140 | 2148 | ||
| 2141 | node->data.struct_val_expr.codegen.type_entry = type_entry; | 2149 | if (size_node) { |
| 2142 | node->data.struct_val_expr.codegen.source_node = node; | 2150 | TypeTableEntry *size_type = analyze_expression(g, import, context, |
| 2143 | context->struct_val_expr_alloca_list.append(&node->data.struct_val_expr.codegen); | 2151 | g->builtin_types.entry_usize, size_node); |
| 2144 | 2152 | if (size_type->id == TypeTableEntryIdInvalid) { | |
| 2145 | int expr_field_count = struct_val_expr->fields.length; | 2153 | return g->builtin_types.entry_invalid; |
| 2146 | int actual_field_count = type_entry->data.structure.field_count; | ||
| 2147 | |||
| 2148 | int *field_use_counts = allocate<int>(actual_field_count); | ||
| 2149 | for (int i = 0; i < expr_field_count; i += 1) { | ||
| 2150 | AstNode *val_field_node = struct_val_expr->fields.at(i); | ||
| 2151 | assert(val_field_node->type == NodeTypeStructValueField); | ||
| 2152 | |||
| 2153 | int field_index; | ||
| 2154 | TypeStructField *type_field = find_struct_type_field(type_entry, | ||
| 2155 | &val_field_node->data.struct_val_field.name, &field_index); | ||
| 2156 | |||
| 2157 | if (!type_field) { | ||
| 2158 | add_node_error(g, val_field_node, | ||
| 2159 | buf_sprintf("no member named '%s' in '%s'", | ||
| 2160 | buf_ptr(&val_field_node->data.struct_val_field.name), buf_ptr(&type_entry->name))); | ||
| 2161 | continue; | ||
| 2162 | } | ||
| 2163 | |||
| 2164 | field_use_counts[field_index] += 1; | ||
| 2165 | if (field_use_counts[field_index] > 1) { | ||
| 2166 | add_node_error(g, val_field_node, buf_sprintf("duplicate field")); | ||
| 2167 | continue; | ||
| 2168 | } | 2154 | } |
| 2169 | 2155 | ||
| 2170 | val_field_node->data.struct_val_field.type_struct_field = type_field; | 2156 | AstNodeNumberLiteral number_literal; |
| 2171 | 2157 | TypeTableEntry *resolved_type = eval_const_expr(g, context, size_node, &number_literal); | |
| 2172 | analyze_expression(g, import, context, type_field->type_entry, | ||
| 2173 | val_field_node->data.struct_val_field.expr); | ||
| 2174 | } | ||
| 2175 | 2158 | ||
| 2176 | for (int i = 0; i < actual_field_count; i += 1) { | 2159 | if (resolved_type->id == TypeTableEntryIdInt) { |
| 2177 | if (field_use_counts[i] == 0) { | 2160 | if (resolved_type->data.integral.is_signed) { |
| 2178 | add_node_error(g, node, | 2161 | add_node_error(g, size_node, |
| 2179 | buf_sprintf("missing field: '%s'", buf_ptr(type_entry->data.structure.fields[i].name))); | 2162 | buf_create_from_str("array size must be unsigned integer")); |
| 2163 | return g->builtin_types.entry_invalid; | ||
| 2164 | } else { | ||
| 2165 | return get_meta_type(g, get_array_type(g, import, child_type, number_literal.data.x_uint)); | ||
| 2166 | } | ||
| 2167 | } else { | ||
| 2168 | add_node_error(g, size_node, | ||
| 2169 | buf_create_from_str("unable to resolve constant expression")); | ||
| 2170 | return g->builtin_types.entry_invalid; | ||
| 2180 | } | 2171 | } |
| 2172 | } else { | ||
| 2173 | return get_meta_type(g, get_unknown_size_array_type(g, import, child_type, node->data.array_type.is_const)); | ||
| 2181 | } | 2174 | } |
| 2182 | |||
| 2183 | return type_entry; | ||
| 2184 | } | 2175 | } |
| 2185 | 2176 | ||
| 2186 | static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 2177 | static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| ... | @@ -2293,9 +2284,14 @@ static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -2293,9 +2284,14 @@ static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import, |
| 2293 | node->data.if_var_expr.then_block, node->data.if_var_expr.else_node, node); | 2284 | node->data.if_var_expr.then_block, node->data.if_var_expr.else_node, node); |
| 2294 | } | 2285 | } |
| 2295 | 2286 | ||
| 2296 | static TypeTableEntry *analyze_min_max_value(CodeGen *g, AstNode *node, TypeTableEntry *type_entry, | 2287 | static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 2297 | const char *err_format) | 2288 | AstNode *node, const char *err_format) |
| 2298 | { | 2289 | { |
| 2290 | assert(node->type == NodeTypeFnCallExpr); | ||
| 2291 | assert(node->data.fn_call_expr.params.length == 1); | ||
| 2292 | |||
| 2293 | AstNode *type_node = node->data.fn_call_expr.params.at(0); | ||
| 2294 | TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node); | ||
| 2299 | if (type_entry->id == TypeTableEntryIdInt || | 2295 | if (type_entry->id == TypeTableEntryIdInt || |
| 2300 | type_entry->id == TypeTableEntryIdFloat || | 2296 | type_entry->id == TypeTableEntryIdFloat || |
| 2301 | type_entry->id == TypeTableEntryIdBool || | 2297 | type_entry->id == TypeTableEntryIdBool || |
| ... | @@ -2309,54 +2305,6 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, AstNode *node, TypeTabl | ... | @@ -2309,54 +2305,6 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, AstNode *node, TypeTabl |
| 2309 | } | 2305 | } |
| 2310 | } | 2306 | } |
| 2311 | 2307 | ||
| 2312 | static TypeTableEntry *analyze_compiler_fn_type(CodeGen *g, ImportTableEntry *import, BlockContext *context, | ||
| 2313 | TypeTableEntry *expected_type, AstNode *node) | ||
| 2314 | { | ||
| 2315 | assert(node->type == NodeTypeCompilerFnType); | ||
| 2316 | |||
| 2317 | Buf *name = &node->data.compiler_fn_type.name; | ||
| 2318 | TypeTableEntry *type_entry = resolve_type(g, node->data.compiler_fn_type.type, import, context, false); | ||
| 2319 | |||
| 2320 | if (buf_eql_str(name, "sizeof")) { | ||
| 2321 | if (type_entry->id == TypeTableEntryIdInvalid) { | ||
| 2322 | return type_entry; | ||
| 2323 | } else if (type_entry->id == TypeTableEntryIdUnreachable) { | ||
| 2324 | add_node_error(g, node, | ||
| 2325 | buf_sprintf("no size available for type '%s'", buf_ptr(&type_entry->name))); | ||
| 2326 | return g->builtin_types.entry_invalid; | ||
| 2327 | } else { | ||
| 2328 | uint64_t size_in_bytes = type_entry->size_in_bits / 8; | ||
| 2329 | |||
| 2330 | TypeTableEntry *num_lit_type = get_number_literal_type_unsigned(g, size_in_bytes); | ||
| 2331 | TypeTableEntry *resolved_type = resolve_rhs_number_literal(g, nullptr, expected_type, node, num_lit_type); | ||
| 2332 | return resolved_type ? resolved_type : num_lit_type; | ||
| 2333 | } | ||
| 2334 | } else if (buf_eql_str(name, "min_value")) { | ||
| 2335 | return analyze_min_max_value(g, node, type_entry, "no min value available for type '%s'"); | ||
| 2336 | } else if (buf_eql_str(name, "max_value")) { | ||
| 2337 | return analyze_min_max_value(g, node, type_entry, "no max value available for type '%s'"); | ||
| 2338 | } else if (buf_eql_str(name, "value_count")) { | ||
| 2339 | if (type_entry->id == TypeTableEntryIdInvalid) { | ||
| 2340 | return type_entry; | ||
| 2341 | } else if (type_entry->id == TypeTableEntryIdEnum) { | ||
| 2342 | uint64_t value_count = type_entry->data.enumeration.field_count; | ||
| 2343 | |||
| 2344 | TypeTableEntry *num_lit_type = get_number_literal_type_unsigned(g, value_count); | ||
| 2345 | TypeTableEntry *resolved_type = resolve_rhs_number_literal(g, nullptr, expected_type, node, num_lit_type); | ||
| 2346 | return resolved_type ? resolved_type : num_lit_type; | ||
| 2347 | |||
| 2348 | } else { | ||
| 2349 | add_node_error(g, node, | ||
| 2350 | buf_sprintf("no value count available for type '%s'", buf_ptr(&type_entry->name))); | ||
| 2351 | return g->builtin_types.entry_invalid; | ||
| 2352 | } | ||
| 2353 | } else { | ||
| 2354 | add_node_error(g, node, | ||
| 2355 | buf_sprintf("invalid compiler function: '%s'", buf_ptr(name))); | ||
| 2356 | return g->builtin_types.entry_invalid; | ||
| 2357 | } | ||
| 2358 | } | ||
| 2359 | |||
| 2360 | static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 2308 | static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 2361 | TypeTableEntry *expected_type, AstNode *node) | 2309 | TypeTableEntry *expected_type, AstNode *node) |
| 2362 | { | 2310 | { |
| ... | @@ -2445,6 +2393,62 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry | ... | @@ -2445,6 +2393,62 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry |
| 2445 | 2393 | ||
| 2446 | return builtin_fn->return_type; | 2394 | return builtin_fn->return_type; |
| 2447 | } | 2395 | } |
| 2396 | case BuiltinFnIdSizeof: | ||
| 2397 | { | ||
| 2398 | AstNode *type_node = node->data.fn_call_expr.params.at(0); | ||
| 2399 | TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node); | ||
| 2400 | if (type_entry->id == TypeTableEntryIdInvalid) { | ||
| 2401 | return g->builtin_types.entry_invalid; | ||
| 2402 | } else if (type_entry->id == TypeTableEntryIdUnreachable) { | ||
| 2403 | add_node_error(g, first_executing_node(type_node), | ||
| 2404 | buf_sprintf("no size available for type '%s'", buf_ptr(&type_entry->name))); | ||
| 2405 | return g->builtin_types.entry_invalid; | ||
| 2406 | } else { | ||
| 2407 | uint64_t size_in_bytes = type_entry->size_in_bits / 8; | ||
| 2408 | |||
| 2409 | TypeTableEntry *num_lit_type = get_number_literal_type_unsigned(g, size_in_bytes); | ||
| 2410 | TypeTableEntry *resolved_type = resolve_rhs_number_literal(g, nullptr, expected_type, node, num_lit_type); | ||
| 2411 | return resolved_type ? resolved_type : num_lit_type; | ||
| 2412 | } | ||
| 2413 | } | ||
| 2414 | case BuiltinFnIdMaxValue: | ||
| 2415 | return analyze_min_max_value(g, import, context, node, "no max value available for type '%s'"); | ||
| 2416 | case BuiltinFnIdMinValue: | ||
| 2417 | return analyze_min_max_value(g, import, context, node, "no min value available for type '%s'"); | ||
| 2418 | case BuiltinFnIdValueCount: | ||
| 2419 | { | ||
| 2420 | AstNode *type_node = node->data.fn_call_expr.params.at(0); | ||
| 2421 | TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node); | ||
| 2422 | |||
| 2423 | if (type_entry->id == TypeTableEntryIdInvalid) { | ||
| 2424 | return type_entry; | ||
| 2425 | } else if (type_entry->id == TypeTableEntryIdEnum) { | ||
| 2426 | uint64_t value_count = type_entry->data.enumeration.field_count; | ||
| 2427 | |||
| 2428 | TypeTableEntry *num_lit_type = get_number_literal_type_unsigned(g, value_count); | ||
| 2429 | TypeTableEntry *resolved_type = resolve_rhs_number_literal(g, nullptr, expected_type, node, num_lit_type); | ||
| 2430 | return resolved_type ? resolved_type : num_lit_type; | ||
| 2431 | |||
| 2432 | } else { | ||
| 2433 | add_node_error(g, node, | ||
| 2434 | buf_sprintf("no value count available for type '%s'", buf_ptr(&type_entry->name))); | ||
| 2435 | return g->builtin_types.entry_invalid; | ||
| 2436 | } | ||
| 2437 | } | ||
| 2438 | case BuiltinFnIdTypeof: | ||
| 2439 | { | ||
| 2440 | AstNode *expr_node = node->data.fn_call_expr.params.at(0); | ||
| 2441 | TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, expr_node); | ||
| 2442 | |||
| 2443 | if (type_entry->id == TypeTableEntryIdInvalid) { | ||
| 2444 | return g->builtin_types.entry_invalid; | ||
| 2445 | } else if (type_entry->id == TypeTableEntryIdMetaType) { | ||
| 2446 | add_node_error(g, node, buf_sprintf("expected expression, got type")); | ||
| 2447 | } else { | ||
| 2448 | return get_meta_type(g, type_entry); | ||
| 2449 | } | ||
| 2450 | } | ||
| 2451 | |||
| 2448 | } | 2452 | } |
| 2449 | zig_unreachable(); | 2453 | zig_unreachable(); |
| 2450 | } else { | 2454 | } else { |
| ... | @@ -2560,15 +2564,127 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import | ... | @@ -2560,15 +2564,127 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import |
| 2560 | AstNode *param_decl_node = fn_proto->params.at(fn_proto_i); | 2564 | AstNode *param_decl_node = fn_proto->params.at(fn_proto_i); |
| 2561 | assert(param_decl_node->type == NodeTypeParamDecl); | 2565 | assert(param_decl_node->type == NodeTypeParamDecl); |
| 2562 | AstNode *param_type_node = param_decl_node->data.param_decl.type; | 2566 | AstNode *param_type_node = param_decl_node->data.param_decl.type; |
| 2563 | assert(param_type_node->type == NodeTypeType); | 2567 | TypeTableEntry *param_type_entry = get_resolved_expr(param_type_node)->type_entry; |
| 2564 | if (param_type_node->data.type.entry) { | 2568 | if (param_type_entry) { |
| 2565 | expected_param_type = param_type_node->data.type.entry; | 2569 | expected_param_type = unwrapped_node_type(param_type_node); |
| 2566 | } | 2570 | } |
| 2567 | } | 2571 | } |
| 2568 | analyze_expression(g, import, context, expected_param_type, child); | 2572 | analyze_expression(g, import, context, expected_param_type, child); |
| 2569 | } | 2573 | } |
| 2570 | 2574 | ||
| 2571 | return fn_proto->return_type->data.type.entry; | 2575 | return unwrapped_node_type(fn_proto->return_type); |
| 2576 | } | ||
| 2577 | } | ||
| 2578 | |||
| 2579 | static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | ||
| 2580 | TypeTableEntry *expected_type, AstNode *node) | ||
| 2581 | { | ||
| 2582 | switch (node->data.prefix_op_expr.prefix_op) { | ||
| 2583 | case PrefixOpInvalid: | ||
| 2584 | zig_unreachable(); | ||
| 2585 | case PrefixOpBoolNot: | ||
| 2586 | analyze_expression(g, import, context, g->builtin_types.entry_bool, | ||
| 2587 | node->data.prefix_op_expr.primary_expr); | ||
| 2588 | return g->builtin_types.entry_bool; | ||
| 2589 | case PrefixOpBinNot: | ||
| 2590 | { | ||
| 2591 | AstNode *operand_node = node->data.prefix_op_expr.primary_expr; | ||
| 2592 | TypeTableEntry *expr_type = analyze_expression(g, import, context, expected_type, | ||
| 2593 | operand_node); | ||
| 2594 | if (expr_type->id == TypeTableEntryIdInvalid) { | ||
| 2595 | return expr_type; | ||
| 2596 | } else if (expr_type->id == TypeTableEntryIdInt || | ||
| 2597 | (expr_type->id == TypeTableEntryIdNumberLiteral && | ||
| 2598 | !is_num_lit_float(expr_type->data.num_lit.kind))) | ||
| 2599 | { | ||
| 2600 | return expr_type; | ||
| 2601 | } else { | ||
| 2602 | add_node_error(g, operand_node, buf_sprintf("invalid binary not type: '%s'", | ||
| 2603 | buf_ptr(&expr_type->name))); | ||
| 2604 | return g->builtin_types.entry_invalid; | ||
| 2605 | } | ||
| 2606 | } | ||
| 2607 | case PrefixOpNegation: | ||
| 2608 | { | ||
| 2609 | AstNode *operand_node = node->data.prefix_op_expr.primary_expr; | ||
| 2610 | TypeTableEntry *expr_type = analyze_expression(g, import, context, expected_type, | ||
| 2611 | operand_node); | ||
| 2612 | if (expr_type->id == TypeTableEntryIdInvalid) { | ||
| 2613 | return expr_type; | ||
| 2614 | } else if (expr_type->id == TypeTableEntryIdInt && | ||
| 2615 | expr_type->data.integral.is_signed) | ||
| 2616 | { | ||
| 2617 | return expr_type; | ||
| 2618 | } else if (expr_type->id == TypeTableEntryIdFloat) { | ||
| 2619 | return expr_type; | ||
| 2620 | } else if (expr_type->id == TypeTableEntryIdNumberLiteral) { | ||
| 2621 | return expr_type; | ||
| 2622 | } else { | ||
| 2623 | add_node_error(g, operand_node, buf_sprintf("invalid negation type: '%s'", | ||
| 2624 | buf_ptr(&expr_type->name))); | ||
| 2625 | return g->builtin_types.entry_invalid; | ||
| 2626 | } | ||
| 2627 | } | ||
| 2628 | case PrefixOpAddressOf: | ||
| 2629 | case PrefixOpConstAddressOf: | ||
| 2630 | { | ||
| 2631 | bool is_const = (node->data.prefix_op_expr.prefix_op == PrefixOpConstAddressOf); | ||
| 2632 | |||
| 2633 | TypeTableEntry *child_type = analyze_lvalue(g, import, context, | ||
| 2634 | node->data.prefix_op_expr.primary_expr, LValPurposeAddressOf, is_const); | ||
| 2635 | |||
| 2636 | if (child_type->id == TypeTableEntryIdInvalid) { | ||
| 2637 | return g->builtin_types.entry_invalid; | ||
| 2638 | } else if (child_type->id == TypeTableEntryIdMetaType) { | ||
| 2639 | TypeTableEntry *meta_child_type = child_type->data.meta_type.child_type; | ||
| 2640 | if (meta_child_type->id == TypeTableEntryIdUnreachable) { | ||
| 2641 | add_node_error(g, node, | ||
| 2642 | buf_create_from_str("pointer to unreachable not allowed")); | ||
| 2643 | } else { | ||
| 2644 | return get_meta_type(g, get_pointer_to_type(g, meta_child_type, is_const)); | ||
| 2645 | } | ||
| 2646 | } else { | ||
| 2647 | return get_pointer_to_type(g, child_type, is_const); | ||
| 2648 | } | ||
| 2649 | } | ||
| 2650 | case PrefixOpDereference: | ||
| 2651 | { | ||
| 2652 | TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, | ||
| 2653 | node->data.prefix_op_expr.primary_expr); | ||
| 2654 | if (type_entry->id == TypeTableEntryIdInvalid) { | ||
| 2655 | return type_entry; | ||
| 2656 | } else if (type_entry->id == TypeTableEntryIdPointer) { | ||
| 2657 | return type_entry->data.pointer.child_type; | ||
| 2658 | } else { | ||
| 2659 | add_node_error(g, node->data.prefix_op_expr.primary_expr, | ||
| 2660 | buf_sprintf("indirection requires pointer operand ('%s' invalid)", | ||
| 2661 | buf_ptr(&type_entry->name))); | ||
| 2662 | return g->builtin_types.entry_invalid; | ||
| 2663 | } | ||
| 2664 | } | ||
| 2665 | case PrefixOpMaybe: | ||
| 2666 | { | ||
| 2667 | TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, | ||
| 2668 | node->data.prefix_op_expr.primary_expr); | ||
| 2669 | |||
| 2670 | if (type_entry->id == TypeTableEntryIdInvalid) { | ||
| 2671 | return type_entry; | ||
| 2672 | } else if (type_entry->id == TypeTableEntryIdMetaType) { | ||
| 2673 | TypeTableEntry *child_type = type_entry->data.meta_type.child_type; | ||
| 2674 | if (child_type->id == TypeTableEntryIdUnreachable) { | ||
| 2675 | add_node_error(g, node, buf_create_from_str("maybe unreachable type not allowed")); | ||
| 2676 | return g->builtin_types.entry_invalid; | ||
| 2677 | } else { | ||
| 2678 | return get_meta_type(g, get_maybe_type(g, child_type)); | ||
| 2679 | } | ||
| 2680 | } else if (type_entry->id == TypeTableEntryIdUnreachable) { | ||
| 2681 | add_node_error(g, node->data.prefix_op_expr.primary_expr, | ||
| 2682 | buf_sprintf("unable to wrap unreachable in maybe type")); | ||
| 2683 | return g->builtin_types.entry_invalid; | ||
| 2684 | } else { | ||
| 2685 | return get_maybe_type(g, type_entry); | ||
| 2686 | } | ||
| 2687 | } | ||
| 2572 | } | 2688 | } |
| 2573 | } | 2689 | } |
| 2574 | 2690 | ||
| ... | @@ -2593,9 +2709,10 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -2593,9 +2709,10 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 2593 | continue; | 2709 | continue; |
| 2594 | } | 2710 | } |
| 2595 | if (return_type->id == TypeTableEntryIdUnreachable) { | 2711 | if (return_type->id == TypeTableEntryIdUnreachable) { |
| 2596 | if (child->type == NodeTypeVoid) { | 2712 | if (is_node_void_expr(child)) { |
| 2597 | // {unreachable;void;void} is allowed. | 2713 | // {unreachable;void;void} is allowed. |
| 2598 | // ignore void statements once we enter unreachable land. | 2714 | // ignore void statements once we enter unreachable land. |
| 2715 | analyze_expression(g, import, context, g->builtin_types.entry_void, child); | ||
| 2599 | continue; | 2716 | continue; |
| 2600 | } | 2717 | } |
| 2601 | add_node_error(g, first_executing_node(child), buf_sprintf("unreachable code")); | 2718 | add_node_error(g, first_executing_node(child), buf_sprintf("unreachable code")); |
| ... | @@ -2604,6 +2721,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -2604,6 +2721,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 2604 | bool is_last = (i == node->data.block.statements.length - 1); | 2721 | bool is_last = (i == node->data.block.statements.length - 1); |
| 2605 | TypeTableEntry *passed_expected_type = is_last ? expected_type : nullptr; | 2722 | TypeTableEntry *passed_expected_type = is_last ? expected_type : nullptr; |
| 2606 | return_type = analyze_expression(g, import, child_context, passed_expected_type, child); | 2723 | return_type = analyze_expression(g, import, child_context, passed_expected_type, child); |
| 2724 | if (!is_last && return_type->id == TypeTableEntryIdMetaType) { | ||
| 2725 | add_node_error(g, child, buf_sprintf("expected expression, found type")); | ||
| 2726 | } | ||
| 2607 | } | 2727 | } |
| 2608 | break; | 2728 | break; |
| 2609 | } | 2729 | } |
| ... | @@ -2664,7 +2784,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -2664,7 +2784,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 2664 | AsmOutput *asm_output = node->data.asm_expr.output_list.at(i); | 2784 | AsmOutput *asm_output = node->data.asm_expr.output_list.at(i); |
| 2665 | if (asm_output->return_type) { | 2785 | if (asm_output->return_type) { |
| 2666 | node->data.asm_expr.return_count += 1; | 2786 | node->data.asm_expr.return_count += 1; |
| 2667 | return_type = resolve_type(g, asm_output->return_type, import, context, false); | 2787 | return_type = analyze_type_expr(g, import, context, asm_output->return_type); |
| 2668 | if (node->data.asm_expr.return_count > 1) { | 2788 | if (node->data.asm_expr.return_count > 1) { |
| 2669 | add_node_error(g, node, | 2789 | add_node_error(g, node, |
| 2670 | buf_sprintf("inline assembly allows up to one output value")); | 2790 | buf_sprintf("inline assembly allows up to one output value")); |
| ... | @@ -2699,6 +2819,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -2699,6 +2819,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 2699 | case NodeTypeFieldAccessExpr: | 2819 | case NodeTypeFieldAccessExpr: |
| 2700 | return_type = analyze_field_access_expr(g, import, context, node); | 2820 | return_type = analyze_field_access_expr(g, import, context, node); |
| 2701 | break; | 2821 | break; |
| 2822 | case NodeTypeContainerInitExpr: | ||
| 2823 | return_type = analyze_container_init_expr(g, import, context, node); | ||
| 2824 | break; | ||
| 2702 | case NodeTypeNumberLiteral: | 2825 | case NodeTypeNumberLiteral: |
| 2703 | return_type = analyze_number_literal_expr(g, import, context, expected_type, node); | 2826 | return_type = analyze_number_literal_expr(g, import, context, expected_type, node); |
| 2704 | break; | 2827 | break; |
| ... | @@ -2713,14 +2836,6 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -2713,14 +2836,6 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 2713 | case NodeTypeCharLiteral: | 2836 | case NodeTypeCharLiteral: |
| 2714 | return_type = g->builtin_types.entry_u8; | 2837 | return_type = g->builtin_types.entry_u8; |
| 2715 | break; | 2838 | break; |
| 2716 | case NodeTypeUnreachable: | ||
| 2717 | return_type = g->builtin_types.entry_unreachable; | ||
| 2718 | break; | ||
| 2719 | |||
| 2720 | case NodeTypeVoid: | ||
| 2721 | return_type = g->builtin_types.entry_void; | ||
| 2722 | break; | ||
| 2723 | |||
| 2724 | case NodeTypeBoolLiteral: | 2839 | case NodeTypeBoolLiteral: |
| 2725 | return_type = g->builtin_types.entry_bool; | 2840 | return_type = g->builtin_types.entry_bool; |
| 2726 | break; | 2841 | break; |
| ... | @@ -2730,96 +2845,13 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -2730,96 +2845,13 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 2730 | break; | 2845 | break; |
| 2731 | 2846 | ||
| 2732 | case NodeTypeSymbol: | 2847 | case NodeTypeSymbol: |
| 2733 | { | 2848 | return_type = analyze_symbol_expr(g, import, context, expected_type, node); |
| 2734 | return_type = analyze_symbol_expr(g, import, context, expected_type, node); | 2849 | break; |
| 2735 | break; | ||
| 2736 | } | ||
| 2737 | case NodeTypeCastExpr: | 2850 | case NodeTypeCastExpr: |
| 2738 | return_type = analyze_cast_expr(g, import, context, expected_type, node); | 2851 | return_type = analyze_cast_expr(g, import, context, expected_type, node); |
| 2739 | break; | 2852 | break; |
| 2740 | case NodeTypePrefixOpExpr: | 2853 | case NodeTypePrefixOpExpr: |
| 2741 | switch (node->data.prefix_op_expr.prefix_op) { | 2854 | return_type = analyze_prefix_op_expr(g, import, context, expected_type, node); |
| 2742 | case PrefixOpInvalid: | ||
| 2743 | zig_unreachable(); | ||
| 2744 | case PrefixOpBoolNot: | ||
| 2745 | analyze_expression(g, import, context, g->builtin_types.entry_bool, | ||
| 2746 | node->data.prefix_op_expr.primary_expr); | ||
| 2747 | return_type = g->builtin_types.entry_bool; | ||
| 2748 | break; | ||
| 2749 | case PrefixOpBinNot: | ||
| 2750 | { | ||
| 2751 | AstNode *operand_node = node->data.prefix_op_expr.primary_expr; | ||
| 2752 | TypeTableEntry *expr_type = analyze_expression(g, import, context, expected_type, | ||
| 2753 | operand_node); | ||
| 2754 | if (expr_type->id == TypeTableEntryIdInvalid) { | ||
| 2755 | return_type = expr_type; | ||
| 2756 | } else if (expr_type->id == TypeTableEntryIdInt || | ||
| 2757 | (expr_type->id == TypeTableEntryIdNumberLiteral && | ||
| 2758 | !is_num_lit_float(expr_type->data.num_lit.kind))) | ||
| 2759 | { | ||
| 2760 | return_type = expr_type; | ||
| 2761 | } else { | ||
| 2762 | add_node_error(g, operand_node, buf_sprintf("invalid binary not type: '%s'", | ||
| 2763 | buf_ptr(&expr_type->name))); | ||
| 2764 | return_type = g->builtin_types.entry_invalid; | ||
| 2765 | } | ||
| 2766 | break; | ||
| 2767 | } | ||
| 2768 | case PrefixOpNegation: | ||
| 2769 | { | ||
| 2770 | AstNode *operand_node = node->data.prefix_op_expr.primary_expr; | ||
| 2771 | TypeTableEntry *expr_type = analyze_expression(g, import, context, expected_type, | ||
| 2772 | operand_node); | ||
| 2773 | if (expr_type->id == TypeTableEntryIdInvalid) { | ||
| 2774 | return_type = expr_type; | ||
| 2775 | } else if (expr_type->id == TypeTableEntryIdInt && | ||
| 2776 | expr_type->data.integral.is_signed) | ||
| 2777 | { | ||
| 2778 | return_type = expr_type; | ||
| 2779 | } else if (expr_type->id == TypeTableEntryIdFloat) { | ||
| 2780 | return_type = expr_type; | ||
| 2781 | } else if (expr_type->id == TypeTableEntryIdNumberLiteral) { | ||
| 2782 | return_type = expr_type; | ||
| 2783 | } else { | ||
| 2784 | add_node_error(g, operand_node, buf_sprintf("invalid negation type: '%s'", | ||
| 2785 | buf_ptr(&expr_type->name))); | ||
| 2786 | return_type = g->builtin_types.entry_invalid; | ||
| 2787 | } | ||
| 2788 | break; | ||
| 2789 | } | ||
| 2790 | case PrefixOpAddressOf: | ||
| 2791 | case PrefixOpConstAddressOf: | ||
| 2792 | { | ||
| 2793 | bool is_const = (node->data.prefix_op_expr.prefix_op == PrefixOpConstAddressOf); | ||
| 2794 | |||
| 2795 | TypeTableEntry *child_type = analyze_lvalue(g, import, context, | ||
| 2796 | node->data.prefix_op_expr.primary_expr, LValPurposeAddressOf, is_const); | ||
| 2797 | |||
| 2798 | if (child_type->id == TypeTableEntryIdInvalid) { | ||
| 2799 | return_type = g->builtin_types.entry_invalid; | ||
| 2800 | break; | ||
| 2801 | } | ||
| 2802 | |||
| 2803 | return_type = get_pointer_to_type(g, child_type, is_const, false); | ||
| 2804 | break; | ||
| 2805 | } | ||
| 2806 | case PrefixOpDereference: | ||
| 2807 | { | ||
| 2808 | TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, | ||
| 2809 | node->data.prefix_op_expr.primary_expr); | ||
| 2810 | if (type_entry->id == TypeTableEntryIdInvalid) { | ||
| 2811 | return_type = type_entry; | ||
| 2812 | } else if (type_entry->id == TypeTableEntryIdPointer) { | ||
| 2813 | return_type = type_entry->data.pointer.child_type; | ||
| 2814 | } else { | ||
| 2815 | add_node_error(g, node->data.prefix_op_expr.primary_expr, | ||
| 2816 | buf_sprintf("indirection requires pointer operand ('%s' invalid)", | ||
| 2817 | buf_ptr(&type_entry->name))); | ||
| 2818 | return_type = g->builtin_types.entry_invalid; | ||
| 2819 | } | ||
| 2820 | break; | ||
| 2821 | } | ||
| 2822 | } | ||
| 2823 | break; | 2855 | break; |
| 2824 | case NodeTypeIfBoolExpr: | 2856 | case NodeTypeIfBoolExpr: |
| 2825 | return_type = analyze_if_bool_expr(g, import, context, expected_type, node); | 2857 | return_type = analyze_if_bool_expr(g, import, context, expected_type, node); |
| ... | @@ -2830,17 +2862,13 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -2830,17 +2862,13 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 2830 | case NodeTypeWhileExpr: | 2862 | case NodeTypeWhileExpr: |
| 2831 | return_type = analyze_while_expr(g, import, context, expected_type, node); | 2863 | return_type = analyze_while_expr(g, import, context, expected_type, node); |
| 2832 | break; | 2864 | break; |
| 2833 | case NodeTypeStructValueExpr: | 2865 | case NodeTypeArrayType: |
| 2834 | return_type = analyze_struct_val_expr(g, import, context, expected_type, node); | 2866 | return_type = analyze_array_type(g, import, context, expected_type, node); |
| 2835 | break; | ||
| 2836 | case NodeTypeCompilerFnType: | ||
| 2837 | return_type = analyze_compiler_fn_type(g, import, context, expected_type, node); | ||
| 2838 | break; | 2867 | break; |
| 2839 | case NodeTypeDirective: | 2868 | case NodeTypeDirective: |
| 2840 | case NodeTypeFnDecl: | 2869 | case NodeTypeFnDecl: |
| 2841 | case NodeTypeFnProto: | 2870 | case NodeTypeFnProto: |
| 2842 | case NodeTypeParamDecl: | 2871 | case NodeTypeParamDecl: |
| 2843 | case NodeTypeType: | ||
| 2844 | case NodeTypeRoot: | 2872 | case NodeTypeRoot: |
| 2845 | case NodeTypeRootExportDecl: | 2873 | case NodeTypeRootExportDecl: |
| 2846 | case NodeTypeExternBlock: | 2874 | case NodeTypeExternBlock: |
| ... | @@ -2850,7 +2878,6 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -2850,7 +2878,6 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 2850 | case NodeTypeStructDecl: | 2878 | case NodeTypeStructDecl: |
| 2851 | case NodeTypeStructField: | 2879 | case NodeTypeStructField: |
| 2852 | case NodeTypeStructValueField: | 2880 | case NodeTypeStructValueField: |
| 2853 | case NodeTypeCompilerFnExpr: | ||
| 2854 | zig_unreachable(); | 2881 | zig_unreachable(); |
| 2855 | } | 2882 | } |
| 2856 | assert(return_type); | 2883 | assert(return_type); |
| ... | @@ -2885,8 +2912,7 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo | ... | @@ -2885,8 +2912,7 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo |
| 2885 | 2912 | ||
| 2886 | // define local variables for parameters | 2913 | // define local variables for parameters |
| 2887 | AstNodeParamDecl *param_decl = &param_decl_node->data.param_decl; | 2914 | AstNodeParamDecl *param_decl = &param_decl_node->data.param_decl; |
| 2888 | assert(param_decl->type->type == NodeTypeType); | 2915 | TypeTableEntry *type = unwrapped_node_type(param_decl->type); |
| 2889 | TypeTableEntry *type = param_decl->type->data.type.entry; | ||
| 2890 | 2916 | ||
| 2891 | if (is_exported && type->id == TypeTableEntryIdStruct) { | 2917 | if (is_exported && type->id == TypeTableEntryIdStruct) { |
| 2892 | add_node_error(g, param_decl_node, | 2918 | add_node_error(g, param_decl_node, |
| ... | @@ -2918,7 +2944,7 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo | ... | @@ -2918,7 +2944,7 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo |
| 2918 | } | 2944 | } |
| 2919 | } | 2945 | } |
| 2920 | 2946 | ||
| 2921 | TypeTableEntry *expected_type = fn_proto->return_type->data.type.entry; | 2947 | TypeTableEntry *expected_type = unwrapped_node_type(fn_proto->return_type); |
| 2922 | TypeTableEntry *block_return_type = analyze_expression(g, import, context, expected_type, node->data.fn_def.body); | 2948 | TypeTableEntry *block_return_type = analyze_expression(g, import, context, expected_type, node->data.fn_def.body); |
| 2923 | 2949 | ||
| 2924 | node->data.fn_def.implicit_return_type = block_return_type; | 2950 | node->data.fn_def.implicit_return_type = block_return_type; |
| ... | @@ -2963,7 +2989,6 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode | ... | @@ -2963,7 +2989,6 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode |
| 2963 | case NodeTypeDirective: | 2989 | case NodeTypeDirective: |
| 2964 | case NodeTypeParamDecl: | 2990 | case NodeTypeParamDecl: |
| 2965 | case NodeTypeFnProto: | 2991 | case NodeTypeFnProto: |
| 2966 | case NodeTypeType: | ||
| 2967 | case NodeTypeFnDecl: | 2992 | case NodeTypeFnDecl: |
| 2968 | case NodeTypeReturnExpr: | 2993 | case NodeTypeReturnExpr: |
| 2969 | case NodeTypeRoot: | 2994 | case NodeTypeRoot: |
| ... | @@ -2975,8 +3000,6 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode | ... | @@ -2975,8 +3000,6 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode |
| 2975 | case NodeTypeNumberLiteral: | 3000 | case NodeTypeNumberLiteral: |
| 2976 | case NodeTypeStringLiteral: | 3001 | case NodeTypeStringLiteral: |
| 2977 | case NodeTypeCharLiteral: | 3002 | case NodeTypeCharLiteral: |
| 2978 | case NodeTypeUnreachable: | ||
| 2979 | case NodeTypeVoid: | ||
| 2980 | case NodeTypeBoolLiteral: | 3003 | case NodeTypeBoolLiteral: |
| 2981 | case NodeTypeNullLiteral: | 3004 | case NodeTypeNullLiteral: |
| 2982 | case NodeTypeSymbol: | 3005 | case NodeTypeSymbol: |
| ... | @@ -2992,177 +3015,150 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode | ... | @@ -2992,177 +3015,150 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode |
| 2992 | case NodeTypeAsmExpr: | 3015 | case NodeTypeAsmExpr: |
| 2993 | case NodeTypeFieldAccessExpr: | 3016 | case NodeTypeFieldAccessExpr: |
| 2994 | case NodeTypeStructField: | 3017 | case NodeTypeStructField: |
| 2995 | case NodeTypeStructValueExpr: | ||
| 2996 | case NodeTypeStructValueField: | 3018 | case NodeTypeStructValueField: |
| 2997 | case NodeTypeCompilerFnExpr: | 3019 | case NodeTypeContainerInitExpr: |
| 2998 | case NodeTypeCompilerFnType: | 3020 | case NodeTypeArrayType: |
| 2999 | zig_unreachable(); | 3021 | zig_unreachable(); |
| 3000 | } | 3022 | } |
| 3001 | } | 3023 | } |
| 3002 | 3024 | ||
| 3003 | static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *expr_node, | 3025 | static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *node, |
| 3004 | TopLevelDecl *decl_node) | 3026 | TopLevelDecl *decl_node) |
| 3005 | { | 3027 | { |
| 3006 | switch (expr_node->type) { | 3028 | switch (node->type) { |
| 3007 | case NodeTypeNumberLiteral: | 3029 | case NodeTypeNumberLiteral: |
| 3008 | case NodeTypeStringLiteral: | 3030 | case NodeTypeStringLiteral: |
| 3009 | case NodeTypeCharLiteral: | 3031 | case NodeTypeCharLiteral: |
| 3010 | case NodeTypeVoid: | ||
| 3011 | case NodeTypeBoolLiteral: | 3032 | case NodeTypeBoolLiteral: |
| 3012 | case NodeTypeNullLiteral: | 3033 | case NodeTypeNullLiteral: |
| 3013 | case NodeTypeUnreachable: | ||
| 3014 | case NodeTypeGoto: | 3034 | case NodeTypeGoto: |
| 3015 | case NodeTypeBreak: | 3035 | case NodeTypeBreak: |
| 3016 | case NodeTypeContinue: | 3036 | case NodeTypeContinue: |
| 3017 | // no dependencies on other top level declarations | 3037 | // no dependencies on other top level declarations |
| 3018 | break; | 3038 | break; |
| 3019 | case NodeTypeSymbol: | 3039 | case NodeTypeSymbol: |
| 3020 | decl_node->deps.put(&expr_node->data.symbol_expr.symbol, expr_node); | 3040 | { |
| 3021 | break; | 3041 | Buf *name = &node->data.symbol_expr.symbol; |
| 3042 | auto table_entry = g->primitive_type_table.maybe_get(name); | ||
| 3043 | if (!table_entry) { | ||
| 3044 | table_entry = import->block_context->type_table.maybe_get(name); | ||
| 3045 | } | ||
| 3046 | if (!table_entry) { | ||
| 3047 | decl_node->deps.put(name, node); | ||
| 3048 | } | ||
| 3049 | break; | ||
| 3050 | } | ||
| 3022 | case NodeTypeBinOpExpr: | 3051 | case NodeTypeBinOpExpr: |
| 3023 | collect_expr_decl_deps(g, import, expr_node->data.bin_op_expr.op1, decl_node); | 3052 | collect_expr_decl_deps(g, import, node->data.bin_op_expr.op1, decl_node); |
| 3024 | collect_expr_decl_deps(g, import, expr_node->data.bin_op_expr.op2, decl_node); | 3053 | collect_expr_decl_deps(g, import, node->data.bin_op_expr.op2, decl_node); |
| 3025 | break; | 3054 | break; |
| 3026 | case NodeTypeReturnExpr: | 3055 | case NodeTypeReturnExpr: |
| 3027 | collect_expr_decl_deps(g, import, expr_node->data.return_expr.expr, decl_node); | 3056 | collect_expr_decl_deps(g, import, node->data.return_expr.expr, decl_node); |
| 3028 | break; | 3057 | break; |
| 3029 | case NodeTypeCastExpr: | 3058 | case NodeTypeCastExpr: |
| 3030 | collect_expr_decl_deps(g, import, expr_node->data.cast_expr.expr, decl_node); | 3059 | collect_expr_decl_deps(g, import, node->data.cast_expr.expr, decl_node); |
| 3031 | collect_type_decl_deps(g, import, expr_node->data.cast_expr.type, decl_node); | 3060 | collect_expr_decl_deps(g, import, node->data.cast_expr.type, decl_node); |
| 3032 | break; | 3061 | break; |
| 3033 | case NodeTypePrefixOpExpr: | 3062 | case NodeTypePrefixOpExpr: |
| 3034 | collect_expr_decl_deps(g, import, expr_node->data.prefix_op_expr.primary_expr, decl_node); | 3063 | collect_expr_decl_deps(g, import, node->data.prefix_op_expr.primary_expr, decl_node); |
| 3035 | break; | 3064 | break; |
| 3036 | case NodeTypeFnCallExpr: | 3065 | case NodeTypeFnCallExpr: |
| 3037 | collect_expr_decl_deps(g, import, expr_node->data.fn_call_expr.fn_ref_expr, decl_node); | 3066 | collect_expr_decl_deps(g, import, node->data.fn_call_expr.fn_ref_expr, decl_node); |
| 3038 | for (int i = 0; i < expr_node->data.fn_call_expr.params.length; i += 1) { | 3067 | for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { |
| 3039 | AstNode *arg_node = expr_node->data.fn_call_expr.params.at(i); | 3068 | AstNode *arg_node = node->data.fn_call_expr.params.at(i); |
| 3040 | collect_expr_decl_deps(g, import, arg_node, decl_node); | 3069 | collect_expr_decl_deps(g, import, arg_node, decl_node); |
| 3041 | } | 3070 | } |
| 3042 | break; | 3071 | break; |
| 3043 | case NodeTypeArrayAccessExpr: | 3072 | case NodeTypeArrayAccessExpr: |
| 3044 | collect_expr_decl_deps(g, import, expr_node->data.array_access_expr.array_ref_expr, decl_node); | 3073 | collect_expr_decl_deps(g, import, node->data.array_access_expr.array_ref_expr, decl_node); |
| 3045 | collect_expr_decl_deps(g, import, expr_node->data.array_access_expr.subscript, decl_node); | 3074 | collect_expr_decl_deps(g, import, node->data.array_access_expr.subscript, decl_node); |
| 3046 | break; | 3075 | break; |
| 3047 | case NodeTypeSliceExpr: | 3076 | case NodeTypeSliceExpr: |
| 3048 | collect_expr_decl_deps(g, import, expr_node->data.slice_expr.array_ref_expr, decl_node); | 3077 | collect_expr_decl_deps(g, import, node->data.slice_expr.array_ref_expr, decl_node); |
| 3049 | collect_expr_decl_deps(g, import, expr_node->data.slice_expr.start, decl_node); | 3078 | collect_expr_decl_deps(g, import, node->data.slice_expr.start, decl_node); |
| 3050 | if (expr_node->data.slice_expr.end) { | 3079 | if (node->data.slice_expr.end) { |
| 3051 | collect_expr_decl_deps(g, import, expr_node->data.slice_expr.end, decl_node); | 3080 | collect_expr_decl_deps(g, import, node->data.slice_expr.end, decl_node); |
| 3052 | } | 3081 | } |
| 3053 | break; | 3082 | break; |
| 3054 | case NodeTypeFieldAccessExpr: | 3083 | case NodeTypeFieldAccessExpr: |
| 3055 | collect_expr_decl_deps(g, import, expr_node->data.field_access_expr.struct_expr, decl_node); | 3084 | collect_expr_decl_deps(g, import, node->data.field_access_expr.struct_expr, decl_node); |
| 3056 | break; | 3085 | break; |
| 3057 | case NodeTypeIfBoolExpr: | 3086 | case NodeTypeIfBoolExpr: |
| 3058 | collect_expr_decl_deps(g, import, expr_node->data.if_bool_expr.condition, decl_node); | 3087 | collect_expr_decl_deps(g, import, node->data.if_bool_expr.condition, decl_node); |
| 3059 | collect_expr_decl_deps(g, import, expr_node->data.if_bool_expr.then_block, decl_node); | 3088 | collect_expr_decl_deps(g, import, node->data.if_bool_expr.then_block, decl_node); |
| 3060 | if (expr_node->data.if_bool_expr.else_node) { | 3089 | if (node->data.if_bool_expr.else_node) { |
| 3061 | collect_expr_decl_deps(g, import, expr_node->data.if_bool_expr.else_node, decl_node); | 3090 | collect_expr_decl_deps(g, import, node->data.if_bool_expr.else_node, decl_node); |
| 3062 | } | 3091 | } |
| 3063 | break; | 3092 | break; |
| 3064 | case NodeTypeIfVarExpr: | 3093 | case NodeTypeIfVarExpr: |
| 3065 | if (expr_node->data.if_var_expr.var_decl.type) { | 3094 | if (node->data.if_var_expr.var_decl.type) { |
| 3066 | collect_type_decl_deps(g, import, expr_node->data.if_var_expr.var_decl.type, decl_node); | 3095 | collect_expr_decl_deps(g, import, node->data.if_var_expr.var_decl.type, decl_node); |
| 3067 | } | 3096 | } |
| 3068 | if (expr_node->data.if_var_expr.var_decl.expr) { | 3097 | if (node->data.if_var_expr.var_decl.expr) { |
| 3069 | collect_expr_decl_deps(g, import, expr_node->data.if_var_expr.var_decl.expr, decl_node); | 3098 | collect_expr_decl_deps(g, import, node->data.if_var_expr.var_decl.expr, decl_node); |
| 3070 | } | 3099 | } |
| 3071 | collect_expr_decl_deps(g, import, expr_node->data.if_var_expr.then_block, decl_node); | 3100 | collect_expr_decl_deps(g, import, node->data.if_var_expr.then_block, decl_node); |
| 3072 | if (expr_node->data.if_bool_expr.else_node) { | 3101 | if (node->data.if_bool_expr.else_node) { |
| 3073 | collect_expr_decl_deps(g, import, expr_node->data.if_var_expr.else_node, decl_node); | 3102 | collect_expr_decl_deps(g, import, node->data.if_var_expr.else_node, decl_node); |
| 3074 | } | 3103 | } |
| 3075 | break; | 3104 | break; |
| 3076 | case NodeTypeWhileExpr: | 3105 | case NodeTypeWhileExpr: |
| 3077 | collect_expr_decl_deps(g, import, expr_node->data.while_expr.condition, decl_node); | 3106 | collect_expr_decl_deps(g, import, node->data.while_expr.condition, decl_node); |
| 3078 | collect_expr_decl_deps(g, import, expr_node->data.while_expr.body, decl_node); | 3107 | collect_expr_decl_deps(g, import, node->data.while_expr.body, decl_node); |
| 3079 | break; | 3108 | break; |
| 3080 | case NodeTypeBlock: | 3109 | case NodeTypeBlock: |
| 3081 | for (int i = 0; i < expr_node->data.block.statements.length; i += 1) { | 3110 | for (int i = 0; i < node->data.block.statements.length; i += 1) { |
| 3082 | AstNode *stmt = expr_node->data.block.statements.at(i); | 3111 | AstNode *stmt = node->data.block.statements.at(i); |
| 3083 | collect_expr_decl_deps(g, import, stmt, decl_node); | 3112 | collect_expr_decl_deps(g, import, stmt, decl_node); |
| 3084 | } | 3113 | } |
| 3085 | break; | 3114 | break; |
| 3086 | case NodeTypeAsmExpr: | 3115 | case NodeTypeAsmExpr: |
| 3087 | for (int i = 0; i < expr_node->data.asm_expr.output_list.length; i += 1) { | 3116 | for (int i = 0; i < node->data.asm_expr.output_list.length; i += 1) { |
| 3088 | AsmOutput *asm_output = expr_node->data.asm_expr.output_list.at(i); | 3117 | AsmOutput *asm_output = node->data.asm_expr.output_list.at(i); |
| 3089 | if (asm_output->return_type) { | 3118 | if (asm_output->return_type) { |
| 3090 | collect_type_decl_deps(g, import, asm_output->return_type, decl_node); | 3119 | collect_expr_decl_deps(g, import, asm_output->return_type, decl_node); |
| 3091 | } else { | 3120 | } else { |
| 3092 | decl_node->deps.put(&asm_output->variable_name, expr_node); | 3121 | decl_node->deps.put(&asm_output->variable_name, node); |
| 3093 | } | 3122 | } |
| 3094 | } | 3123 | } |
| 3095 | for (int i = 0; i < expr_node->data.asm_expr.input_list.length; i += 1) { | 3124 | for (int i = 0; i < node->data.asm_expr.input_list.length; i += 1) { |
| 3096 | AsmInput *asm_input = expr_node->data.asm_expr.input_list.at(i); | 3125 | AsmInput *asm_input = node->data.asm_expr.input_list.at(i); |
| 3097 | collect_expr_decl_deps(g, import, asm_input->expr, decl_node); | 3126 | collect_expr_decl_deps(g, import, asm_input->expr, decl_node); |
| 3098 | } | 3127 | } |
| 3099 | break; | 3128 | break; |
| 3100 | case NodeTypeStructValueExpr: | 3129 | case NodeTypeContainerInitExpr: |
| 3101 | collect_type_decl_deps(g, import, expr_node->data.struct_val_expr.type, decl_node); | 3130 | collect_expr_decl_deps(g, import, node->data.container_init_expr.type, decl_node); |
| 3102 | for (int i = 0; i < expr_node->data.struct_val_expr.fields.length; i += 1) { | 3131 | for (int i = 0; i < node->data.container_init_expr.entries.length; i += 1) { |
| 3103 | AstNode *field_node = expr_node->data.struct_val_expr.fields.at(i); | 3132 | AstNode *child_node = node->data.container_init_expr.entries.at(i); |
| 3104 | assert(field_node->type == NodeTypeStructValueField); | 3133 | collect_expr_decl_deps(g, import, child_node, decl_node); |
| 3105 | collect_expr_decl_deps(g, import, field_node->data.struct_val_field.expr, decl_node); | ||
| 3106 | } | 3134 | } |
| 3107 | break; | 3135 | break; |
| 3108 | case NodeTypeCompilerFnExpr: | 3136 | case NodeTypeStructValueField: |
| 3109 | collect_expr_decl_deps(g, import, expr_node->data.compiler_fn_expr.expr, decl_node); | 3137 | collect_expr_decl_deps(g, import, node->data.struct_val_field.expr, decl_node); |
| 3110 | break; | 3138 | break; |
| 3111 | case NodeTypeCompilerFnType: | 3139 | case NodeTypeArrayType: |
| 3112 | collect_type_decl_deps(g, import, expr_node->data.compiler_fn_type.type, decl_node); | 3140 | if (node->data.array_type.size) { |
| 3141 | collect_expr_decl_deps(g, import, node->data.array_type.size, decl_node); | ||
| 3142 | } | ||
| 3143 | collect_expr_decl_deps(g, import, node->data.array_type.child_type, decl_node); | ||
| 3113 | break; | 3144 | break; |
| 3114 | case NodeTypeRoot: | 3145 | case NodeTypeVariableDeclaration: |
| 3115 | case NodeTypeRootExportDecl: | ||
| 3116 | case NodeTypeFnProto: | 3146 | case NodeTypeFnProto: |
| 3147 | case NodeTypeExternBlock: | ||
| 3148 | case NodeTypeRootExportDecl: | ||
| 3117 | case NodeTypeFnDef: | 3149 | case NodeTypeFnDef: |
| 3150 | case NodeTypeRoot: | ||
| 3118 | case NodeTypeFnDecl: | 3151 | case NodeTypeFnDecl: |
| 3119 | case NodeTypeParamDecl: | 3152 | case NodeTypeParamDecl: |
| 3120 | case NodeTypeType: | ||
| 3121 | case NodeTypeExternBlock: | ||
| 3122 | case NodeTypeDirective: | 3153 | case NodeTypeDirective: |
| 3123 | case NodeTypeVariableDeclaration: | ||
| 3124 | case NodeTypeUse: | 3154 | case NodeTypeUse: |
| 3125 | case NodeTypeLabel: | 3155 | case NodeTypeLabel: |
| 3126 | case NodeTypeStructDecl: | 3156 | case NodeTypeStructDecl: |
| 3127 | case NodeTypeStructField: | 3157 | case NodeTypeStructField: |
| 3128 | case NodeTypeStructValueField: | ||
| 3129 | zig_unreachable(); | 3158 | zig_unreachable(); |
| 3130 | } | 3159 | } |
| 3131 | } | 3160 | } |
| 3132 | 3161 | ||
| 3133 | static void collect_type_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *type_node, TopLevelDecl *decl_node) { | ||
| 3134 | assert(type_node->type == NodeTypeType); | ||
| 3135 | switch (type_node->data.type.type) { | ||
| 3136 | case AstNodeTypeTypePrimitive: | ||
| 3137 | { | ||
| 3138 | Buf *name = &type_node->data.type.primitive_name; | ||
| 3139 | auto table_entry = g->primitive_type_table.maybe_get(name); | ||
| 3140 | if (!table_entry) { | ||
| 3141 | table_entry = import->block_context->type_table.maybe_get(name); | ||
| 3142 | } | ||
| 3143 | if (!table_entry) { | ||
| 3144 | decl_node->deps.put(name, type_node); | ||
| 3145 | } | ||
| 3146 | break; | ||
| 3147 | } | ||
| 3148 | case AstNodeTypeTypePointer: | ||
| 3149 | collect_type_decl_deps(g, import, type_node->data.type.child_type, decl_node); | ||
| 3150 | break; | ||
| 3151 | case AstNodeTypeTypeArray: | ||
| 3152 | collect_type_decl_deps(g, import, type_node->data.type.child_type, decl_node); | ||
| 3153 | if (type_node->data.type.array_size) { | ||
| 3154 | collect_expr_decl_deps(g, import, type_node->data.type.array_size, decl_node); | ||
| 3155 | } | ||
| 3156 | break; | ||
| 3157 | case AstNodeTypeTypeMaybe: | ||
| 3158 | collect_type_decl_deps(g, import, type_node->data.type.child_type, decl_node); | ||
| 3159 | break; | ||
| 3160 | case AstNodeTypeTypeCompilerExpr: | ||
| 3161 | collect_expr_decl_deps(g, import, type_node->data.type.compiler_expr, decl_node); | ||
| 3162 | break; | ||
| 3163 | } | ||
| 3164 | } | ||
| 3165 | |||
| 3166 | static TypeTableEntryId container_to_type(ContainerKind kind) { | 3162 | static TypeTableEntryId container_to_type(ContainerKind kind) { |
| 3167 | switch (kind) { | 3163 | switch (kind) { |
| 3168 | case ContainerKindStruct: | 3164 | case ContainerKindStruct: |
| ... | @@ -3231,7 +3227,7 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast | ... | @@ -3231,7 +3227,7 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast |
| 3231 | for (int i = 0; i < node->data.struct_decl.fields.length; i += 1) { | 3227 | for (int i = 0; i < node->data.struct_decl.fields.length; i += 1) { |
| 3232 | AstNode *field_node = node->data.struct_decl.fields.at(i); | 3228 | AstNode *field_node = node->data.struct_decl.fields.at(i); |
| 3233 | AstNode *type_node = field_node->data.struct_field.type; | 3229 | AstNode *type_node = field_node->data.struct_field.type; |
| 3234 | collect_type_decl_deps(g, import, type_node, decl_node); | 3230 | collect_expr_decl_deps(g, import, type_node, decl_node); |
| 3235 | } | 3231 | } |
| 3236 | decl_node->name = name; | 3232 | decl_node->name = name; |
| 3237 | decl_node->import = import; | 3233 | decl_node->import = import; |
| ... | @@ -3271,7 +3267,7 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast | ... | @@ -3271,7 +3267,7 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast |
| 3271 | TopLevelDecl *decl_node = &node->data.variable_declaration.top_level_decl; | 3267 | TopLevelDecl *decl_node = &node->data.variable_declaration.top_level_decl; |
| 3272 | decl_node->deps.init(1); | 3268 | decl_node->deps.init(1); |
| 3273 | if (node->data.variable_declaration.type) { | 3269 | if (node->data.variable_declaration.type) { |
| 3274 | collect_type_decl_deps(g, import, node->data.variable_declaration.type, decl_node); | 3270 | collect_expr_decl_deps(g, import, node->data.variable_declaration.type, decl_node); |
| 3275 | } | 3271 | } |
| 3276 | if (node->data.variable_declaration.expr) { | 3272 | if (node->data.variable_declaration.expr) { |
| 3277 | collect_expr_decl_deps(g, import, node->data.variable_declaration.expr, decl_node); | 3273 | collect_expr_decl_deps(g, import, node->data.variable_declaration.expr, decl_node); |
| ... | @@ -3294,8 +3290,9 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast | ... | @@ -3294,8 +3290,9 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast |
| 3294 | for (int i = 0; i < node->data.fn_proto.params.length; i += 1) { | 3290 | for (int i = 0; i < node->data.fn_proto.params.length; i += 1) { |
| 3295 | AstNode *param_node = node->data.fn_proto.params.at(i); | 3291 | AstNode *param_node = node->data.fn_proto.params.at(i); |
| 3296 | assert(param_node->type == NodeTypeParamDecl); | 3292 | assert(param_node->type == NodeTypeParamDecl); |
| 3297 | collect_type_decl_deps(g, import, param_node->data.param_decl.type, decl_node); | 3293 | collect_expr_decl_deps(g, import, param_node->data.param_decl.type, decl_node); |
| 3298 | } | 3294 | } |
| 3295 | collect_expr_decl_deps(g, import, node->data.fn_proto.return_type, decl_node); | ||
| 3299 | 3296 | ||
| 3300 | Buf *name = &node->data.fn_proto.name; | 3297 | Buf *name = &node->data.fn_proto.name; |
| 3301 | decl_node->name = name; | 3298 | decl_node->name = name; |
| ... | @@ -3315,7 +3312,6 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast | ... | @@ -3315,7 +3312,6 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast |
| 3315 | break; | 3312 | break; |
| 3316 | case NodeTypeDirective: | 3313 | case NodeTypeDirective: |
| 3317 | case NodeTypeParamDecl: | 3314 | case NodeTypeParamDecl: |
| 3318 | case NodeTypeType: | ||
| 3319 | case NodeTypeFnDecl: | 3315 | case NodeTypeFnDecl: |
| 3320 | case NodeTypeReturnExpr: | 3316 | case NodeTypeReturnExpr: |
| 3321 | case NodeTypeRoot: | 3317 | case NodeTypeRoot: |
| ... | @@ -3327,8 +3323,6 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast | ... | @@ -3327,8 +3323,6 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast |
| 3327 | case NodeTypeNumberLiteral: | 3323 | case NodeTypeNumberLiteral: |
| 3328 | case NodeTypeStringLiteral: | 3324 | case NodeTypeStringLiteral: |
| 3329 | case NodeTypeCharLiteral: | 3325 | case NodeTypeCharLiteral: |
| 3330 | case NodeTypeUnreachable: | ||
| 3331 | case NodeTypeVoid: | ||
| 3332 | case NodeTypeBoolLiteral: | 3326 | case NodeTypeBoolLiteral: |
| 3333 | case NodeTypeNullLiteral: | 3327 | case NodeTypeNullLiteral: |
| 3334 | case NodeTypeSymbol: | 3328 | case NodeTypeSymbol: |
| ... | @@ -3344,10 +3338,9 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast | ... | @@ -3344,10 +3338,9 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast |
| 3344 | case NodeTypeAsmExpr: | 3338 | case NodeTypeAsmExpr: |
| 3345 | case NodeTypeFieldAccessExpr: | 3339 | case NodeTypeFieldAccessExpr: |
| 3346 | case NodeTypeStructField: | 3340 | case NodeTypeStructField: |
| 3347 | case NodeTypeStructValueExpr: | 3341 | case NodeTypeContainerInitExpr: |
| 3348 | case NodeTypeStructValueField: | 3342 | case NodeTypeStructValueField: |
| 3349 | case NodeTypeCompilerFnExpr: | 3343 | case NodeTypeArrayType: |
| 3350 | case NodeTypeCompilerFnType: | ||
| 3351 | zig_unreachable(); | 3344 | zig_unreachable(); |
| 3352 | } | 3345 | } |
| 3353 | } | 3346 | } |
| ... | @@ -3526,18 +3519,14 @@ Expr *get_resolved_expr(AstNode *node) { | ... | @@ -3526,18 +3519,14 @@ Expr *get_resolved_expr(AstNode *node) { |
| 3526 | return &node->data.while_expr.resolved_expr; | 3519 | return &node->data.while_expr.resolved_expr; |
| 3527 | case NodeTypeAsmExpr: | 3520 | case NodeTypeAsmExpr: |
| 3528 | return &node->data.asm_expr.resolved_expr; | 3521 | return &node->data.asm_expr.resolved_expr; |
| 3529 | case NodeTypeStructValueExpr: | 3522 | case NodeTypeContainerInitExpr: |
| 3530 | return &node->data.struct_val_expr.resolved_expr; | 3523 | return &node->data.container_init_expr.resolved_expr; |
| 3531 | case NodeTypeNumberLiteral: | 3524 | case NodeTypeNumberLiteral: |
| 3532 | return &node->data.number_literal.resolved_expr; | 3525 | return &node->data.number_literal.resolved_expr; |
| 3533 | case NodeTypeStringLiteral: | 3526 | case NodeTypeStringLiteral: |
| 3534 | return &node->data.string_literal.resolved_expr; | 3527 | return &node->data.string_literal.resolved_expr; |
| 3535 | case NodeTypeBlock: | 3528 | case NodeTypeBlock: |
| 3536 | return &node->data.block.resolved_expr; | 3529 | return &node->data.block.resolved_expr; |
| 3537 | case NodeTypeVoid: | ||
| 3538 | return &node->data.void_expr.resolved_expr; | ||
| 3539 | case NodeTypeUnreachable: | ||
| 3540 | return &node->data.unreachable_expr.resolved_expr; | ||
| 3541 | case NodeTypeSymbol: | 3530 | case NodeTypeSymbol: |
| 3542 | return &node->data.symbol_expr.resolved_expr; | 3531 | return &node->data.symbol_expr.resolved_expr; |
| 3543 | case NodeTypeVariableDeclaration: | 3532 | case NodeTypeVariableDeclaration: |
| ... | @@ -3554,19 +3543,16 @@ Expr *get_resolved_expr(AstNode *node) { | ... | @@ -3554,19 +3543,16 @@ Expr *get_resolved_expr(AstNode *node) { |
| 3554 | return &node->data.break_expr.resolved_expr; | 3543 | return &node->data.break_expr.resolved_expr; |
| 3555 | case NodeTypeContinue: | 3544 | case NodeTypeContinue: |
| 3556 | return &node->data.continue_expr.resolved_expr; | 3545 | return &node->data.continue_expr.resolved_expr; |
| 3557 | case NodeTypeCompilerFnExpr: | ||
| 3558 | return &node->data.compiler_fn_expr.resolved_expr; | ||
| 3559 | case NodeTypeCompilerFnType: | ||
| 3560 | return &node->data.compiler_fn_type.resolved_expr; | ||
| 3561 | case NodeTypeLabel: | 3546 | case NodeTypeLabel: |
| 3562 | return &node->data.label.resolved_expr; | 3547 | return &node->data.label.resolved_expr; |
| 3548 | case NodeTypeArrayType: | ||
| 3549 | return &node->data.array_type.resolved_expr; | ||
| 3563 | case NodeTypeRoot: | 3550 | case NodeTypeRoot: |
| 3564 | case NodeTypeRootExportDecl: | 3551 | case NodeTypeRootExportDecl: |
| 3565 | case NodeTypeFnProto: | 3552 | case NodeTypeFnProto: |
| 3566 | case NodeTypeFnDef: | 3553 | case NodeTypeFnDef: |
| 3567 | case NodeTypeFnDecl: | 3554 | case NodeTypeFnDecl: |
| 3568 | case NodeTypeParamDecl: | 3555 | case NodeTypeParamDecl: |
| 3569 | case NodeTypeType: | ||
| 3570 | case NodeTypeExternBlock: | 3556 | case NodeTypeExternBlock: |
| 3571 | case NodeTypeDirective: | 3557 | case NodeTypeDirective: |
| 3572 | case NodeTypeUse: | 3558 | case NodeTypeUse: |
| ... | @@ -3581,13 +3567,12 @@ NumLitCodeGen *get_resolved_num_lit(AstNode *node) { | ... | @@ -3581,13 +3567,12 @@ NumLitCodeGen *get_resolved_num_lit(AstNode *node) { |
| 3581 | switch (node->type) { | 3567 | switch (node->type) { |
| 3582 | case NodeTypeNumberLiteral: | 3568 | case NodeTypeNumberLiteral: |
| 3583 | return &node->data.number_literal.codegen; | 3569 | return &node->data.number_literal.codegen; |
| 3584 | case NodeTypeCompilerFnType: | 3570 | case NodeTypeFnCallExpr: |
| 3585 | return &node->data.compiler_fn_type.resolved_num_lit; | 3571 | return &node->data.fn_call_expr.resolved_num_lit; |
| 3586 | case NodeTypeReturnExpr: | 3572 | case NodeTypeReturnExpr: |
| 3587 | case NodeTypeBinOpExpr: | 3573 | case NodeTypeBinOpExpr: |
| 3588 | case NodeTypeCastExpr: | 3574 | case NodeTypeCastExpr: |
| 3589 | case NodeTypePrefixOpExpr: | 3575 | case NodeTypePrefixOpExpr: |
| 3590 | case NodeTypeFnCallExpr: | ||
| 3591 | case NodeTypeArrayAccessExpr: | 3576 | case NodeTypeArrayAccessExpr: |
| 3592 | case NodeTypeSliceExpr: | 3577 | case NodeTypeSliceExpr: |
| 3593 | case NodeTypeFieldAccessExpr: | 3578 | case NodeTypeFieldAccessExpr: |
| ... | @@ -3595,24 +3580,21 @@ NumLitCodeGen *get_resolved_num_lit(AstNode *node) { | ... | @@ -3595,24 +3580,21 @@ NumLitCodeGen *get_resolved_num_lit(AstNode *node) { |
| 3595 | case NodeTypeIfVarExpr: | 3580 | case NodeTypeIfVarExpr: |
| 3596 | case NodeTypeWhileExpr: | 3581 | case NodeTypeWhileExpr: |
| 3597 | case NodeTypeAsmExpr: | 3582 | case NodeTypeAsmExpr: |
| 3598 | case NodeTypeStructValueExpr: | 3583 | case NodeTypeContainerInitExpr: |
| 3599 | case NodeTypeRoot: | 3584 | case NodeTypeRoot: |
| 3600 | case NodeTypeRootExportDecl: | 3585 | case NodeTypeRootExportDecl: |
| 3601 | case NodeTypeFnProto: | 3586 | case NodeTypeFnProto: |
| 3602 | case NodeTypeFnDef: | 3587 | case NodeTypeFnDef: |
| 3603 | case NodeTypeFnDecl: | 3588 | case NodeTypeFnDecl: |
| 3604 | case NodeTypeParamDecl: | 3589 | case NodeTypeParamDecl: |
| 3605 | case NodeTypeType: | ||
| 3606 | case NodeTypeBlock: | 3590 | case NodeTypeBlock: |
| 3607 | case NodeTypeExternBlock: | 3591 | case NodeTypeExternBlock: |
| 3608 | case NodeTypeDirective: | 3592 | case NodeTypeDirective: |
| 3609 | case NodeTypeVariableDeclaration: | 3593 | case NodeTypeVariableDeclaration: |
| 3610 | case NodeTypeStringLiteral: | 3594 | case NodeTypeStringLiteral: |
| 3611 | case NodeTypeCharLiteral: | 3595 | case NodeTypeCharLiteral: |
| 3612 | case NodeTypeUnreachable: | ||
| 3613 | case NodeTypeSymbol: | 3596 | case NodeTypeSymbol: |
| 3614 | case NodeTypeUse: | 3597 | case NodeTypeUse: |
| 3615 | case NodeTypeVoid: | ||
| 3616 | case NodeTypeBoolLiteral: | 3598 | case NodeTypeBoolLiteral: |
| 3617 | case NodeTypeNullLiteral: | 3599 | case NodeTypeNullLiteral: |
| 3618 | case NodeTypeLabel: | 3600 | case NodeTypeLabel: |
| ... | @@ -3622,7 +3604,7 @@ NumLitCodeGen *get_resolved_num_lit(AstNode *node) { | ... | @@ -3622,7 +3604,7 @@ NumLitCodeGen *get_resolved_num_lit(AstNode *node) { |
| 3622 | case NodeTypeStructDecl: | 3604 | case NodeTypeStructDecl: |
| 3623 | case NodeTypeStructField: | 3605 | case NodeTypeStructField: |
| 3624 | case NodeTypeStructValueField: | 3606 | case NodeTypeStructValueField: |
| 3625 | case NodeTypeCompilerFnExpr: | 3607 | case NodeTypeArrayType: |
| 3626 | zig_unreachable(); | 3608 | zig_unreachable(); |
| 3627 | } | 3609 | } |
| 3628 | } | 3610 | } |
| ... | @@ -3648,22 +3630,19 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) { | ... | @@ -3648,22 +3630,19 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) { |
| 3648 | case NodeTypeIfVarExpr: | 3630 | case NodeTypeIfVarExpr: |
| 3649 | case NodeTypeWhileExpr: | 3631 | case NodeTypeWhileExpr: |
| 3650 | case NodeTypeAsmExpr: | 3632 | case NodeTypeAsmExpr: |
| 3651 | case NodeTypeStructValueExpr: | 3633 | case NodeTypeContainerInitExpr: |
| 3652 | case NodeTypeRoot: | 3634 | case NodeTypeRoot: |
| 3653 | case NodeTypeRootExportDecl: | 3635 | case NodeTypeRootExportDecl: |
| 3654 | case NodeTypeFnDef: | 3636 | case NodeTypeFnDef: |
| 3655 | case NodeTypeFnDecl: | 3637 | case NodeTypeFnDecl: |
| 3656 | case NodeTypeParamDecl: | 3638 | case NodeTypeParamDecl: |
| 3657 | case NodeTypeType: | ||
| 3658 | case NodeTypeBlock: | 3639 | case NodeTypeBlock: |
| 3659 | case NodeTypeExternBlock: | 3640 | case NodeTypeExternBlock: |
| 3660 | case NodeTypeDirective: | 3641 | case NodeTypeDirective: |
| 3661 | case NodeTypeStringLiteral: | 3642 | case NodeTypeStringLiteral: |
| 3662 | case NodeTypeCharLiteral: | 3643 | case NodeTypeCharLiteral: |
| 3663 | case NodeTypeUnreachable: | ||
| 3664 | case NodeTypeSymbol: | 3644 | case NodeTypeSymbol: |
| 3665 | case NodeTypeUse: | 3645 | case NodeTypeUse: |
| 3666 | case NodeTypeVoid: | ||
| 3667 | case NodeTypeBoolLiteral: | 3646 | case NodeTypeBoolLiteral: |
| 3668 | case NodeTypeNullLiteral: | 3647 | case NodeTypeNullLiteral: |
| 3669 | case NodeTypeLabel: | 3648 | case NodeTypeLabel: |
| ... | @@ -3672,8 +3651,23 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) { | ... | @@ -3672,8 +3651,23 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) { |
| 3672 | case NodeTypeContinue: | 3651 | case NodeTypeContinue: |
| 3673 | case NodeTypeStructField: | 3652 | case NodeTypeStructField: |
| 3674 | case NodeTypeStructValueField: | 3653 | case NodeTypeStructValueField: |
| 3675 | case NodeTypeCompilerFnExpr: | 3654 | case NodeTypeArrayType: |
| 3676 | case NodeTypeCompilerFnType: | ||
| 3677 | zig_unreachable(); | 3655 | zig_unreachable(); |
| 3678 | } | 3656 | } |
| 3679 | } | 3657 | } |
| 3658 | |||
| 3659 | bool is_node_void_expr(AstNode *node) { | ||
| 3660 | if (node->type == NodeTypeContainerInitExpr && | ||
| 3661 | node->data.container_init_expr.kind == ContainerInitKindArray) | ||
| 3662 | { | ||
| 3663 | AstNode *type_node = node->data.container_init_expr.type; | ||
| 3664 | if (type_node->type == NodeTypeSymbol && | ||
| 3665 | buf_eql_str(&type_node->data.symbol_expr.symbol, "void")) | ||
| 3666 | { | ||
| 3667 | return true; | ||
| 3668 | } | ||
| 3669 | } | ||
| 3670 | |||
| 3671 | return false; | ||
| 3672 | } | ||
| 3673 |
src/analyze.hpp+2-1| ... | @@ -13,12 +13,13 @@ | ... | @@ -13,12 +13,13 @@ |
| 13 | void semantic_analyze(CodeGen *g); | 13 | void semantic_analyze(CodeGen *g); |
| 14 | void add_node_error(CodeGen *g, AstNode *node, Buf *msg); | 14 | void add_node_error(CodeGen *g, AstNode *node, Buf *msg); |
| 15 | TypeTableEntry *new_type_table_entry(TypeTableEntryId id); | 15 | TypeTableEntry *new_type_table_entry(TypeTableEntryId id); |
| 16 | TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const, bool is_noalias); | 16 | TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const); |
| 17 | VariableTableEntry *find_variable(BlockContext *context, Buf *name); | 17 | VariableTableEntry *find_variable(BlockContext *context, Buf *name); |
| 18 | TypeTableEntry *find_container(BlockContext *context, Buf *name); | 18 | TypeTableEntry *find_container(BlockContext *context, Buf *name); |
| 19 | BlockContext *new_block_context(AstNode *node, BlockContext *parent); | 19 | BlockContext *new_block_context(AstNode *node, BlockContext *parent); |
| 20 | Expr *get_resolved_expr(AstNode *node); | 20 | Expr *get_resolved_expr(AstNode *node); |
| 21 | NumLitCodeGen *get_resolved_num_lit(AstNode *node); | 21 | NumLitCodeGen *get_resolved_num_lit(AstNode *node); |
| 22 | TopLevelDecl *get_resolved_top_level_decl(AstNode *node); | 22 | TopLevelDecl *get_resolved_top_level_decl(AstNode *node); |
| 23 | bool is_node_void_expr(AstNode *node); | ||
| 23 | 24 | ||
| 24 | #endif | 25 | #endif |
src/codegen.cpp+197-156| ... | @@ -72,35 +72,35 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType b | ... | @@ -72,35 +72,35 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType b |
| 72 | LLVMValueRef target_ref, LLVMValueRef value, | 72 | LLVMValueRef target_ref, LLVMValueRef value, |
| 73 | TypeTableEntry *op1_type, TypeTableEntry *op2_type); | 73 | TypeTableEntry *op1_type, TypeTableEntry *op2_type); |
| 74 | 74 | ||
| 75 | 75 | static TypeTableEntry *get_type_for_type_node(AstNode *node) { | |
| 76 | static TypeTableEntry *get_type_for_type_node(CodeGen *g, AstNode *type_node) { | 76 | TypeTableEntry *meta_type_entry = get_resolved_expr(node)->type_entry; |
| 77 | assert(type_node->type == NodeTypeType); | 77 | assert(meta_type_entry->id == TypeTableEntryIdMetaType); |
| 78 | return type_node->data.type.entry; | 78 | return meta_type_entry->data.meta_type.child_type; |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | static TypeTableEntry *fn_proto_type_from_type_node(CodeGen *g, AstNode *type_node) { | 81 | static TypeTableEntry *fn_proto_type_from_type_node(CodeGen *g, AstNode *type_node) { |
| 82 | TypeTableEntry *type_entry = get_type_for_type_node(g, type_node); | 82 | TypeTableEntry *type_entry = get_type_for_type_node(type_node); |
| 83 | 83 | ||
| 84 | if (type_entry->id == TypeTableEntryIdStruct || type_entry->id == TypeTableEntryIdArray) { | 84 | if (type_entry->id == TypeTableEntryIdStruct || type_entry->id == TypeTableEntryIdArray) { |
| 85 | return get_pointer_to_type(g, type_entry, true, true); | 85 | return get_pointer_to_type(g, type_entry, true); |
| 86 | } else { | 86 | } else { |
| 87 | return type_entry; | 87 | return type_entry; |
| 88 | } | 88 | } |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | static LLVMZigDIType *to_llvm_debug_type(CodeGen *g, AstNode *type_node) { | 91 | static LLVMZigDIType *to_llvm_debug_type(CodeGen *g, AstNode *type_node) { |
| 92 | TypeTableEntry *type_entry = get_type_for_type_node(g, type_node); | 92 | TypeTableEntry *type_entry = get_type_for_type_node(type_node); |
| 93 | return type_entry->di_type; | 93 | return type_entry->di_type; |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | 96 | ||
| 97 | static bool type_is_unreachable(CodeGen *g, AstNode *type_node) { | 97 | static bool type_is_unreachable(CodeGen *g, AstNode *type_node) { |
| 98 | return get_type_for_type_node(g, type_node)->id == TypeTableEntryIdUnreachable; | 98 | return get_type_for_type_node(type_node)->id == TypeTableEntryIdUnreachable; |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | static bool is_param_decl_type_void(CodeGen *g, AstNode *param_decl_node) { | 101 | static bool is_param_decl_type_void(CodeGen *g, AstNode *param_decl_node) { |
| 102 | assert(param_decl_node->type == NodeTypeParamDecl); | 102 | assert(param_decl_node->type == NodeTypeParamDecl); |
| 103 | return get_type_for_type_node(g, param_decl_node->data.param_decl.type)->id == TypeTableEntryIdVoid; | 103 | return get_type_for_type_node(param_decl_node->data.param_decl.type)->id == TypeTableEntryIdVoid; |
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | static int count_non_void_params(CodeGen *g, ZigList<AstNode *> *params) { | 106 | static int count_non_void_params(CodeGen *g, ZigList<AstNode *> *params) { |
| ... | @@ -146,6 +146,32 @@ static TypeTableEntry *get_expr_type(AstNode *node) { | ... | @@ -146,6 +146,32 @@ static TypeTableEntry *get_expr_type(AstNode *node) { |
| 146 | return expr->type_entry; | 146 | return expr->type_entry; |
| 147 | } | 147 | } |
| 148 | 148 | ||
| 149 | static LLVMValueRef gen_number_literal_raw(CodeGen *g, AstNode *source_node, | ||
| 150 | NumLitCodeGen *codegen_num_lit, AstNodeNumberLiteral *num_lit_node) | ||
| 151 | { | ||
| 152 | TypeTableEntry *type_entry = codegen_num_lit->resolved_type; | ||
| 153 | assert(type_entry); | ||
| 154 | |||
| 155 | // override the expression type for number literals | ||
| 156 | get_resolved_expr(source_node)->type_entry = type_entry; | ||
| 157 | |||
| 158 | if (type_entry->id == TypeTableEntryIdInt) { | ||
| 159 | // here the union has int64_t and uint64_t and we purposefully read | ||
| 160 | // the uint64_t value in either case, because we want the twos | ||
| 161 | // complement representation | ||
| 162 | |||
| 163 | return LLVMConstInt(type_entry->type_ref, | ||
| 164 | num_lit_node->data.x_uint, | ||
| 165 | type_entry->data.integral.is_signed); | ||
| 166 | } else if (type_entry->id == TypeTableEntryIdFloat) { | ||
| 167 | |||
| 168 | return LLVMConstReal(type_entry->type_ref, | ||
| 169 | num_lit_node->data.x_float); | ||
| 170 | } else { | ||
| 171 | zig_panic("bad number literal type"); | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 149 | static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { | 175 | static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { |
| 150 | assert(node->type == NodeTypeFnCallExpr); | 176 | assert(node->type == NodeTypeFnCallExpr); |
| 151 | AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; | 177 | 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) { | ... | @@ -154,6 +180,7 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { |
| 154 | 180 | ||
| 155 | switch (builtin_fn->id) { | 181 | switch (builtin_fn->id) { |
| 156 | case BuiltinFnIdInvalid: | 182 | case BuiltinFnIdInvalid: |
| 183 | case BuiltinFnIdTypeof: | ||
| 157 | zig_unreachable(); | 184 | zig_unreachable(); |
| 158 | case BuiltinFnIdArithmeticWithOverflow: | 185 | case BuiltinFnIdArithmeticWithOverflow: |
| 159 | { | 186 | { |
| ... | @@ -238,6 +265,74 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { | ... | @@ -238,6 +265,74 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { |
| 238 | LLVMBuildCall(g->builder, builtin_fn->fn_val, params, 5, ""); | 265 | LLVMBuildCall(g->builder, builtin_fn->fn_val, params, 5, ""); |
| 239 | return nullptr; | 266 | return nullptr; |
| 240 | } | 267 | } |
| 268 | case BuiltinFnIdSizeof: | ||
| 269 | { | ||
| 270 | assert(node->data.fn_call_expr.params.length == 1); | ||
| 271 | AstNode *type_node = node->data.fn_call_expr.params.at(0); | ||
| 272 | TypeTableEntry *type_entry = get_type_for_type_node(type_node); | ||
| 273 | |||
| 274 | NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node); | ||
| 275 | AstNodeNumberLiteral num_lit_node; | ||
| 276 | num_lit_node.kind = NumLitU64; // this field isn't even read | ||
| 277 | num_lit_node.overflow = false; | ||
| 278 | num_lit_node.data.x_uint = type_entry->size_in_bits / 8; | ||
| 279 | return gen_number_literal_raw(g, node, codegen_num_lit, &num_lit_node); | ||
| 280 | } | ||
| 281 | case BuiltinFnIdMinValue: | ||
| 282 | { | ||
| 283 | assert(node->data.fn_call_expr.params.length == 1); | ||
| 284 | AstNode *type_node = node->data.fn_call_expr.params.at(0); | ||
| 285 | TypeTableEntry *type_entry = get_type_for_type_node(type_node); | ||
| 286 | |||
| 287 | |||
| 288 | if (type_entry->id == TypeTableEntryIdInt) { | ||
| 289 | if (type_entry->data.integral.is_signed) { | ||
| 290 | return LLVMConstInt(type_entry->type_ref, 1ULL << (type_entry->size_in_bits - 1), false); | ||
| 291 | } else { | ||
| 292 | return LLVMConstNull(type_entry->type_ref); | ||
| 293 | } | ||
| 294 | } else if (type_entry->id == TypeTableEntryIdFloat) { | ||
| 295 | zig_panic("TODO codegen min_value float"); | ||
| 296 | } else { | ||
| 297 | zig_unreachable(); | ||
| 298 | } | ||
| 299 | } | ||
| 300 | case BuiltinFnIdMaxValue: | ||
| 301 | { | ||
| 302 | assert(node->data.fn_call_expr.params.length == 1); | ||
| 303 | AstNode *type_node = node->data.fn_call_expr.params.at(0); | ||
| 304 | TypeTableEntry *type_entry = get_type_for_type_node(type_node); | ||
| 305 | |||
| 306 | |||
| 307 | if (type_entry->id == TypeTableEntryIdInt) { | ||
| 308 | if (type_entry->data.integral.is_signed) { | ||
| 309 | return LLVMConstInt(type_entry->type_ref, (1ULL << (type_entry->size_in_bits - 1)) - 1, false); | ||
| 310 | } else { | ||
| 311 | return LLVMConstAllOnes(type_entry->type_ref); | ||
| 312 | } | ||
| 313 | } else if (type_entry->id == TypeTableEntryIdFloat) { | ||
| 314 | zig_panic("TODO codegen max_value float"); | ||
| 315 | } else { | ||
| 316 | zig_unreachable(); | ||
| 317 | } | ||
| 318 | } | ||
| 319 | case BuiltinFnIdValueCount: | ||
| 320 | { | ||
| 321 | assert(node->data.fn_call_expr.params.length == 1); | ||
| 322 | AstNode *type_node = node->data.fn_call_expr.params.at(0); | ||
| 323 | TypeTableEntry *type_entry = get_type_for_type_node(type_node); | ||
| 324 | |||
| 325 | if (type_entry->id == TypeTableEntryIdEnum) { | ||
| 326 | NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node); | ||
| 327 | AstNodeNumberLiteral num_lit_node; | ||
| 328 | num_lit_node.kind = NumLitU64; // field ignored | ||
| 329 | num_lit_node.overflow = false; | ||
| 330 | num_lit_node.data.x_uint = type_entry->data.enumeration.field_count; | ||
| 331 | return gen_number_literal_raw(g, node, codegen_num_lit, &num_lit_node); | ||
| 332 | } else { | ||
| 333 | zig_unreachable(); | ||
| 334 | } | ||
| 335 | } | ||
| 241 | } | 336 | } |
| 242 | zig_unreachable(); | 337 | zig_unreachable(); |
| 243 | } | 338 | } |
| ... | @@ -692,6 +787,10 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) { | ... | @@ -692,6 +787,10 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) { |
| 692 | add_debug_source_node(g, node); | 787 | add_debug_source_node(g, node); |
| 693 | return LLVMBuildLoad(g->builder, expr, ""); | 788 | return LLVMBuildLoad(g->builder, expr, ""); |
| 694 | } | 789 | } |
| 790 | case PrefixOpMaybe: | ||
| 791 | { | ||
| 792 | zig_panic("TODO codegen PrefixOpMaybe"); | ||
| 793 | } | ||
| 695 | } | 794 | } |
| 696 | zig_unreachable(); | 795 | zig_unreachable(); |
| 697 | } | 796 | } |
| ... | @@ -1484,35 +1583,46 @@ static LLVMValueRef gen_null_literal(CodeGen *g, AstNode *node) { | ... | @@ -1484,35 +1583,46 @@ static LLVMValueRef gen_null_literal(CodeGen *g, AstNode *node) { |
| 1484 | return tmp_struct_ptr; | 1583 | return tmp_struct_ptr; |
| 1485 | } | 1584 | } |
| 1486 | 1585 | ||
| 1487 | static LLVMValueRef gen_struct_val_expr(CodeGen *g, AstNode *node) { | 1586 | static LLVMValueRef gen_container_init_expr(CodeGen *g, AstNode *node) { |
| 1488 | assert(node->type == NodeTypeStructValueExpr); | 1587 | assert(node->type == NodeTypeContainerInitExpr); |
| 1489 | 1588 | ||
| 1490 | TypeTableEntry *type_entry = get_expr_type(node); | 1589 | TypeTableEntry *type_entry = get_expr_type(node); |
| 1491 | 1590 | ||
| 1492 | assert(type_entry->id == TypeTableEntryIdStruct); | 1591 | if (type_entry->id == TypeTableEntryIdStruct) { |
| 1592 | assert(node->data.container_init_expr.kind == ContainerInitKindStruct); | ||
| 1493 | 1593 | ||
| 1494 | int field_count = type_entry->data.structure.field_count; | 1594 | int field_count = type_entry->data.structure.field_count; |
| 1495 | assert(field_count == node->data.struct_val_expr.fields.length); | 1595 | assert(field_count == node->data.container_init_expr.entries.length); |
| 1496 | 1596 | ||
| 1497 | StructValExprCodeGen *struct_val_expr_node = &node->data.struct_val_expr.codegen; | 1597 | StructValExprCodeGen *struct_val_expr_node = &node->data.container_init_expr.resolved_struct_val_expr; |
| 1498 | LLVMValueRef tmp_struct_ptr = struct_val_expr_node->ptr; | 1598 | LLVMValueRef tmp_struct_ptr = struct_val_expr_node->ptr; |
| 1499 | 1599 | ||
| 1500 | for (int i = 0; i < field_count; i += 1) { | 1600 | for (int i = 0; i < field_count; i += 1) { |
| 1501 | AstNode *field_node = node->data.struct_val_expr.fields.at(i); | 1601 | AstNode *field_node = node->data.container_init_expr.entries.at(i); |
| 1502 | assert(field_node->type == NodeTypeStructValueField); | 1602 | assert(field_node->type == NodeTypeStructValueField); |
| 1503 | TypeStructField *type_struct_field = field_node->data.struct_val_field.type_struct_field; | 1603 | TypeStructField *type_struct_field = field_node->data.struct_val_field.type_struct_field; |
| 1504 | if (type_struct_field->type_entry->id == TypeTableEntryIdVoid) { | 1604 | if (type_struct_field->type_entry->id == TypeTableEntryIdVoid) { |
| 1505 | continue; | 1605 | continue; |
| 1606 | } | ||
| 1607 | assert(buf_eql_buf(type_struct_field->name, &field_node->data.struct_val_field.name)); | ||
| 1608 | |||
| 1609 | add_debug_source_node(g, field_node); | ||
| 1610 | LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, type_struct_field->gen_index, ""); | ||
| 1611 | LLVMValueRef value = gen_expr(g, field_node->data.struct_val_field.expr); | ||
| 1612 | LLVMBuildStore(g->builder, value, field_ptr); | ||
| 1506 | } | 1613 | } |
| 1507 | assert(buf_eql_buf(type_struct_field->name, &field_node->data.struct_val_field.name)); | ||
| 1508 | 1614 | ||
| 1509 | add_debug_source_node(g, field_node); | 1615 | return tmp_struct_ptr; |
| 1510 | LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, type_struct_field->gen_index, ""); | 1616 | } else if (type_entry->id == TypeTableEntryIdUnreachable) { |
| 1511 | LLVMValueRef value = gen_expr(g, field_node->data.struct_val_field.expr); | 1617 | assert(node->data.container_init_expr.entries.length == 0); |
| 1512 | LLVMBuildStore(g->builder, value, field_ptr); | 1618 | add_debug_source_node(g, node); |
| 1619 | return LLVMBuildUnreachable(g->builder); | ||
| 1620 | } else if (type_entry->id == TypeTableEntryIdVoid) { | ||
| 1621 | assert(node->data.container_init_expr.entries.length == 0); | ||
| 1622 | return nullptr; | ||
| 1623 | } else { | ||
| 1624 | zig_unreachable(); | ||
| 1513 | } | 1625 | } |
| 1514 | |||
| 1515 | return tmp_struct_ptr; | ||
| 1516 | } | 1626 | } |
| 1517 | 1627 | ||
| 1518 | static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) { | 1628 | static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) { |
| ... | @@ -1659,93 +1769,39 @@ static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) { | ... | @@ -1659,93 +1769,39 @@ static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) { |
| 1659 | get_resolved_expr(node)->block_context, false, &init_val); | 1769 | get_resolved_expr(node)->block_context, false, &init_val); |
| 1660 | } | 1770 | } |
| 1661 | 1771 | ||
| 1662 | static LLVMValueRef gen_number_literal_raw(CodeGen *g, AstNode *source_node, | 1772 | static LLVMValueRef gen_number_literal(CodeGen *g, AstNode *node) { |
| 1663 | NumLitCodeGen *codegen_num_lit, AstNodeNumberLiteral *num_lit_node) | 1773 | assert(node->type == NodeTypeNumberLiteral); |
| 1664 | { | ||
| 1665 | TypeTableEntry *type_entry = codegen_num_lit->resolved_type; | ||
| 1666 | assert(type_entry); | ||
| 1667 | |||
| 1668 | // override the expression type for number literals | ||
| 1669 | get_resolved_expr(source_node)->type_entry = type_entry; | ||
| 1670 | |||
| 1671 | if (type_entry->id == TypeTableEntryIdInt) { | ||
| 1672 | // here the union has int64_t and uint64_t and we purposefully read | ||
| 1673 | // the uint64_t value in either case, because we want the twos | ||
| 1674 | // complement representation | ||
| 1675 | 1774 | ||
| 1676 | return LLVMConstInt(type_entry->type_ref, | 1775 | NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node); |
| 1677 | num_lit_node->data.x_uint, | 1776 | assert(codegen_num_lit); |
| 1678 | type_entry->data.integral.is_signed); | ||
| 1679 | } else if (type_entry->id == TypeTableEntryIdFloat) { | ||
| 1680 | 1777 | ||
| 1681 | return LLVMConstReal(type_entry->type_ref, | 1778 | return gen_number_literal_raw(g, node, codegen_num_lit, &node->data.number_literal); |
| 1682 | num_lit_node->data.x_float); | ||
| 1683 | } else { | ||
| 1684 | zig_panic("bad number literal type"); | ||
| 1685 | } | ||
| 1686 | } | 1779 | } |
| 1687 | 1780 | ||
| 1688 | static LLVMValueRef gen_compiler_fn_type(CodeGen *g, AstNode *node) { | 1781 | static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) { |
| 1689 | assert(node->type == NodeTypeCompilerFnType); | 1782 | VariableTableEntry *variable = find_variable( |
| 1690 | 1783 | get_resolved_expr(node)->block_context, | |
| 1691 | Buf *name = &node->data.compiler_fn_type.name; | 1784 | &node->data.symbol_expr.symbol); |
| 1692 | TypeTableEntry *type_entry = get_type_for_type_node(g, node->data.compiler_fn_type.type); | 1785 | assert(variable); |
| 1693 | if (buf_eql_str(name, "sizeof")) { | 1786 | if (variable->type->id == TypeTableEntryIdVoid) { |
| 1694 | NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node); | 1787 | return nullptr; |
| 1695 | AstNodeNumberLiteral num_lit_node; | 1788 | } else if (variable->is_ptr) { |
| 1696 | num_lit_node.kind = type_entry->data.num_lit.kind; | 1789 | assert(variable->value_ref); |
| 1697 | num_lit_node.overflow = false; | 1790 | if (variable->type->id == TypeTableEntryIdArray) { |
| 1698 | num_lit_node.data.x_uint = type_entry->size_in_bits / 8; | 1791 | return variable->value_ref; |
| 1699 | return gen_number_literal_raw(g, node, codegen_num_lit, &num_lit_node); | 1792 | } else if (variable->type->id == TypeTableEntryIdStruct || |
| 1700 | } else if (buf_eql_str(name, "min_value")) { | 1793 | variable->type->id == TypeTableEntryIdMaybe) |
| 1701 | if (type_entry->id == TypeTableEntryIdInt) { | 1794 | { |
| 1702 | if (type_entry->data.integral.is_signed) { | 1795 | return variable->value_ref; |
| 1703 | return LLVMConstInt(type_entry->type_ref, 1ULL << (type_entry->size_in_bits - 1), false); | ||
| 1704 | } else { | ||
| 1705 | return LLVMConstNull(type_entry->type_ref); | ||
| 1706 | } | ||
| 1707 | } else if (type_entry->id == TypeTableEntryIdFloat) { | ||
| 1708 | zig_panic("TODO codegen min_value float"); | ||
| 1709 | } else { | ||
| 1710 | zig_unreachable(); | ||
| 1711 | } | ||
| 1712 | } else if (buf_eql_str(name, "max_value")) { | ||
| 1713 | if (type_entry->id == TypeTableEntryIdInt) { | ||
| 1714 | if (type_entry->data.integral.is_signed) { | ||
| 1715 | return LLVMConstInt(type_entry->type_ref, (1ULL << (type_entry->size_in_bits - 1)) - 1, false); | ||
| 1716 | } else { | ||
| 1717 | return LLVMConstAllOnes(type_entry->type_ref); | ||
| 1718 | } | ||
| 1719 | } else if (type_entry->id == TypeTableEntryIdFloat) { | ||
| 1720 | zig_panic("TODO codegen max_value float"); | ||
| 1721 | } else { | ||
| 1722 | zig_unreachable(); | ||
| 1723 | } | ||
| 1724 | } else if (buf_eql_str(name, "value_count")) { | ||
| 1725 | if (type_entry->id == TypeTableEntryIdEnum) { | ||
| 1726 | NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node); | ||
| 1727 | AstNodeNumberLiteral num_lit_node; | ||
| 1728 | num_lit_node.kind = type_entry->data.num_lit.kind; | ||
| 1729 | num_lit_node.overflow = false; | ||
| 1730 | num_lit_node.data.x_uint = type_entry->data.enumeration.field_count; | ||
| 1731 | return gen_number_literal_raw(g, node, codegen_num_lit, &num_lit_node); | ||
| 1732 | } else { | 1796 | } else { |
| 1733 | zig_unreachable(); | 1797 | add_debug_source_node(g, node); |
| 1798 | return LLVMBuildLoad(g->builder, variable->value_ref, ""); | ||
| 1734 | } | 1799 | } |
| 1735 | } else { | 1800 | } else { |
| 1736 | zig_unreachable(); | 1801 | return variable->value_ref; |
| 1737 | } | 1802 | } |
| 1738 | } | 1803 | } |
| 1739 | 1804 | ||
| 1740 | static LLVMValueRef gen_number_literal(CodeGen *g, AstNode *node) { | ||
| 1741 | assert(node->type == NodeTypeNumberLiteral); | ||
| 1742 | |||
| 1743 | NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node); | ||
| 1744 | assert(codegen_num_lit); | ||
| 1745 | |||
| 1746 | return gen_number_literal_raw(g, node, codegen_num_lit, &node->data.number_literal); | ||
| 1747 | } | ||
| 1748 | |||
| 1749 | static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { | 1805 | static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { |
| 1750 | switch (node->type) { | 1806 | switch (node->type) { |
| 1751 | case NodeTypeBinOpExpr: | 1807 | case NodeTypeBinOpExpr: |
| ... | @@ -1766,11 +1822,6 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { | ... | @@ -1766,11 +1822,6 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { |
| 1766 | return gen_slice_expr(g, node); | 1822 | return gen_slice_expr(g, node); |
| 1767 | case NodeTypeFieldAccessExpr: | 1823 | case NodeTypeFieldAccessExpr: |
| 1768 | return gen_field_access_expr(g, node, false); | 1824 | return gen_field_access_expr(g, node, false); |
| 1769 | case NodeTypeUnreachable: | ||
| 1770 | add_debug_source_node(g, node); | ||
| 1771 | return LLVMBuildUnreachable(g->builder); | ||
| 1772 | case NodeTypeVoid: | ||
| 1773 | return nullptr; | ||
| 1774 | case NodeTypeBoolLiteral: | 1825 | case NodeTypeBoolLiteral: |
| 1775 | if (node->data.bool_literal.value) | 1826 | if (node->data.bool_literal.value) |
| 1776 | return LLVMConstAllOnes(LLVMInt1Type()); | 1827 | return LLVMConstAllOnes(LLVMInt1Type()); |
| ... | @@ -1802,29 +1853,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { | ... | @@ -1802,29 +1853,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { |
| 1802 | case NodeTypeCharLiteral: | 1853 | case NodeTypeCharLiteral: |
| 1803 | return LLVMConstInt(LLVMInt8Type(), node->data.char_literal.value, false); | 1854 | return LLVMConstInt(LLVMInt8Type(), node->data.char_literal.value, false); |
| 1804 | case NodeTypeSymbol: | 1855 | case NodeTypeSymbol: |
| 1805 | { | 1856 | return gen_symbol(g, node); |
| 1806 | VariableTableEntry *variable = find_variable( | ||
| 1807 | get_resolved_expr(node)->block_context, | ||
| 1808 | &node->data.symbol_expr.symbol); | ||
| 1809 | assert(variable); | ||
| 1810 | if (variable->type->id == TypeTableEntryIdVoid) { | ||
| 1811 | return nullptr; | ||
| 1812 | } else if (variable->is_ptr) { | ||
| 1813 | assert(variable->value_ref); | ||
| 1814 | if (variable->type->id == TypeTableEntryIdArray) { | ||
| 1815 | return variable->value_ref; | ||
| 1816 | } else if (variable->type->id == TypeTableEntryIdStruct || | ||
| 1817 | variable->type->id == TypeTableEntryIdMaybe) | ||
| 1818 | { | ||
| 1819 | return variable->value_ref; | ||
| 1820 | } else { | ||
| 1821 | add_debug_source_node(g, node); | ||
| 1822 | return LLVMBuildLoad(g->builder, variable->value_ref, ""); | ||
| 1823 | } | ||
| 1824 | } else { | ||
| 1825 | return variable->value_ref; | ||
| 1826 | } | ||
| 1827 | } | ||
| 1828 | case NodeTypeBlock: | 1857 | case NodeTypeBlock: |
| 1829 | return gen_block(g, node, nullptr); | 1858 | return gen_block(g, node, nullptr); |
| 1830 | case NodeTypeGoto: | 1859 | case NodeTypeGoto: |
| ... | @@ -1846,24 +1875,21 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { | ... | @@ -1846,24 +1875,21 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { |
| 1846 | LLVMPositionBuilderAtEnd(g->builder, basic_block); | 1875 | LLVMPositionBuilderAtEnd(g->builder, basic_block); |
| 1847 | return nullptr; | 1876 | return nullptr; |
| 1848 | } | 1877 | } |
| 1849 | case NodeTypeStructValueExpr: | 1878 | case NodeTypeContainerInitExpr: |
| 1850 | return gen_struct_val_expr(g, node); | 1879 | return gen_container_init_expr(g, node); |
| 1851 | case NodeTypeCompilerFnType: | ||
| 1852 | return gen_compiler_fn_type(g, node); | ||
| 1853 | case NodeTypeRoot: | 1880 | case NodeTypeRoot: |
| 1854 | case NodeTypeRootExportDecl: | 1881 | case NodeTypeRootExportDecl: |
| 1855 | case NodeTypeFnProto: | 1882 | case NodeTypeFnProto: |
| 1856 | case NodeTypeFnDef: | 1883 | case NodeTypeFnDef: |
| 1857 | case NodeTypeFnDecl: | 1884 | case NodeTypeFnDecl: |
| 1858 | case NodeTypeParamDecl: | 1885 | case NodeTypeParamDecl: |
| 1859 | case NodeTypeType: | ||
| 1860 | case NodeTypeExternBlock: | 1886 | case NodeTypeExternBlock: |
| 1861 | case NodeTypeDirective: | 1887 | case NodeTypeDirective: |
| 1862 | case NodeTypeUse: | 1888 | case NodeTypeUse: |
| 1863 | case NodeTypeStructDecl: | 1889 | case NodeTypeStructDecl: |
| 1864 | case NodeTypeStructField: | 1890 | case NodeTypeStructField: |
| 1865 | case NodeTypeStructValueField: | 1891 | case NodeTypeStructValueField: |
| 1866 | case NodeTypeCompilerFnExpr: | 1892 | case NodeTypeArrayType: |
| 1867 | zig_unreachable(); | 1893 | zig_unreachable(); |
| 1868 | } | 1894 | } |
| 1869 | zig_unreachable(); | 1895 | zig_unreachable(); |
| ... | @@ -1872,7 +1898,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { | ... | @@ -1872,7 +1898,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { |
| 1872 | static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { | 1898 | static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { |
| 1873 | LLVMValueRef val = gen_expr_no_cast(g, node); | 1899 | LLVMValueRef val = gen_expr_no_cast(g, node); |
| 1874 | 1900 | ||
| 1875 | if (node->type == NodeTypeVoid) { | 1901 | if (is_node_void_expr(node)) { |
| 1876 | return val; | 1902 | return val; |
| 1877 | } | 1903 | } |
| 1878 | 1904 | ||
| ... | @@ -1966,7 +1992,7 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -1966,7 +1992,7 @@ static void do_code_gen(CodeGen *g) { |
| 1966 | assert(proto_node->type == NodeTypeFnProto); | 1992 | assert(proto_node->type == NodeTypeFnProto); |
| 1967 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; | 1993 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; |
| 1968 | 1994 | ||
| 1969 | LLVMTypeRef ret_type = get_type_for_type_node(g, fn_proto->return_type)->type_ref; | 1995 | LLVMTypeRef ret_type = get_type_for_type_node(fn_proto->return_type)->type_ref; |
| 1970 | int param_count = count_non_void_params(g, &fn_proto->params); | 1996 | int param_count = count_non_void_params(g, &fn_proto->params); |
| 1971 | LLVMTypeRef *param_types = allocate<LLVMTypeRef>(param_count); | 1997 | LLVMTypeRef *param_types = allocate<LLVMTypeRef>(param_count); |
| 1972 | int gen_param_index = 0; | 1998 | int gen_param_index = 0; |
| ... | @@ -2009,7 +2035,7 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -2009,7 +2035,7 @@ static void do_code_gen(CodeGen *g) { |
| 2009 | TypeTableEntry *param_type = fn_proto_type_from_type_node(g, type_node); | 2035 | TypeTableEntry *param_type = fn_proto_type_from_type_node(g, type_node); |
| 2010 | LLVMValueRef argument_val = LLVMGetParam(fn, gen_param_index); | 2036 | LLVMValueRef argument_val = LLVMGetParam(fn, gen_param_index); |
| 2011 | if (param_type->id == TypeTableEntryIdPointer && | 2037 | if (param_type->id == TypeTableEntryIdPointer && |
| 2012 | param_type->data.pointer.is_noalias) | 2038 | false) // TODO test if parameter is noalias |
| 2013 | { | 2039 | { |
| 2014 | LLVMAddAttribute(argument_val, LLVMNoAliasAttribute); | 2040 | LLVMAddAttribute(argument_val, LLVMNoAliasAttribute); |
| 2015 | } else if (param_type->id == TypeTableEntryIdPointer && | 2041 | } else if (param_type->id == TypeTableEntryIdPointer && |
| ... | @@ -2267,7 +2293,7 @@ static void define_builtin_types(CodeGen *g) { | ... | @@ -2267,7 +2293,7 @@ static void define_builtin_types(CodeGen *g) { |
| 2267 | g->builtin_types.entry_u64 = entry; | 2293 | g->builtin_types.entry_u64 = entry; |
| 2268 | g->primitive_type_table.put(&entry->name, entry); | 2294 | g->primitive_type_table.put(&entry->name, entry); |
| 2269 | } | 2295 | } |
| 2270 | g->builtin_types.entry_c_string_literal = get_pointer_to_type(g, g->builtin_types.entry_u8, true, false); | 2296 | g->builtin_types.entry_c_string_literal = get_pointer_to_type(g, g->builtin_types.entry_u8, true); |
| 2271 | { | 2297 | { |
| 2272 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); | 2298 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); |
| 2273 | entry->type_ref = LLVMInt8Type(); | 2299 | entry->type_ref = LLVMInt8Type(); |
| ... | @@ -2413,7 +2439,7 @@ static void define_builtin_fns_int(CodeGen *g, TypeTableEntry *type_entry) { | ... | @@ -2413,7 +2439,7 @@ static void define_builtin_fns_int(CodeGen *g, TypeTableEntry *type_entry) { |
| 2413 | builtin_fn->param_types = allocate<TypeTableEntry *>(builtin_fn->param_count); | 2439 | builtin_fn->param_types = allocate<TypeTableEntry *>(builtin_fn->param_count); |
| 2414 | builtin_fn->param_types[0] = type_entry; | 2440 | builtin_fn->param_types[0] = type_entry; |
| 2415 | builtin_fn->param_types[1] = type_entry; | 2441 | builtin_fn->param_types[1] = type_entry; |
| 2416 | builtin_fn->param_types[2] = get_pointer_to_type(g, type_entry, false, false); | 2442 | builtin_fn->param_types[2] = get_pointer_to_type(g, type_entry, false); |
| 2417 | 2443 | ||
| 2418 | 2444 | ||
| 2419 | const char *signed_str = type_entry->data.integral.is_signed ? | 2445 | 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) { | ... | @@ -2437,6 +2463,23 @@ static void define_builtin_fns_int(CodeGen *g, TypeTableEntry *type_entry) { |
| 2437 | } | 2463 | } |
| 2438 | } | 2464 | } |
| 2439 | 2465 | ||
| 2466 | static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char *name) { | ||
| 2467 | BuiltinFnEntry *builtin_fn = allocate<BuiltinFnEntry>(1); | ||
| 2468 | buf_init_from_str(&builtin_fn->name, name); | ||
| 2469 | builtin_fn->id = id; | ||
| 2470 | g->builtin_fn_table.put(&builtin_fn->name, builtin_fn); | ||
| 2471 | return builtin_fn; | ||
| 2472 | } | ||
| 2473 | |||
| 2474 | static BuiltinFnEntry *create_one_arg_builtin_fn(CodeGen *g, BuiltinFnId id, const char *name) { | ||
| 2475 | BuiltinFnEntry *builtin_fn = create_builtin_fn(g, id, name); | ||
| 2476 | builtin_fn->return_type = nullptr; // manually determined later | ||
| 2477 | builtin_fn->param_count = 1; | ||
| 2478 | builtin_fn->param_types = allocate<TypeTableEntry *>(builtin_fn->param_count); | ||
| 2479 | builtin_fn->param_types[0] = nullptr; // manually checked later | ||
| 2480 | return builtin_fn; | ||
| 2481 | } | ||
| 2482 | |||
| 2440 | static void define_builtin_fns(CodeGen *g) { | 2483 | static void define_builtin_fns(CodeGen *g) { |
| 2441 | define_builtin_fns_int(g, g->builtin_types.entry_u8); | 2484 | define_builtin_fns_int(g, g->builtin_types.entry_u8); |
| 2442 | define_builtin_fns_int(g, g->builtin_types.entry_u16); | 2485 | define_builtin_fns_int(g, g->builtin_types.entry_u16); |
| ... | @@ -2447,9 +2490,7 @@ static void define_builtin_fns(CodeGen *g) { | ... | @@ -2447,9 +2490,7 @@ static void define_builtin_fns(CodeGen *g) { |
| 2447 | define_builtin_fns_int(g, g->builtin_types.entry_i32); | 2490 | define_builtin_fns_int(g, g->builtin_types.entry_i32); |
| 2448 | define_builtin_fns_int(g, g->builtin_types.entry_i64); | 2491 | define_builtin_fns_int(g, g->builtin_types.entry_i64); |
| 2449 | { | 2492 | { |
| 2450 | BuiltinFnEntry *builtin_fn = allocate<BuiltinFnEntry>(1); | 2493 | BuiltinFnEntry *builtin_fn = create_builtin_fn(g, BuiltinFnIdMemcpy, "memcpy"); |
| 2451 | buf_init_from_str(&builtin_fn->name, "memcpy"); | ||
| 2452 | builtin_fn->id = BuiltinFnIdMemcpy; | ||
| 2453 | builtin_fn->return_type = g->builtin_types.entry_void; | 2494 | builtin_fn->return_type = g->builtin_types.entry_void; |
| 2454 | builtin_fn->param_count = 3; | 2495 | builtin_fn->param_count = 3; |
| 2455 | builtin_fn->param_types = allocate<TypeTableEntry *>(builtin_fn->param_count); | 2496 | builtin_fn->param_types = allocate<TypeTableEntry *>(builtin_fn->param_count); |
| ... | @@ -2470,12 +2511,9 @@ static void define_builtin_fns(CodeGen *g) { | ... | @@ -2470,12 +2511,9 @@ static void define_builtin_fns(CodeGen *g) { |
| 2470 | assert(LLVMGetIntrinsicID(builtin_fn->fn_val)); | 2511 | assert(LLVMGetIntrinsicID(builtin_fn->fn_val)); |
| 2471 | 2512 | ||
| 2472 | g->memcpy_fn_val = builtin_fn->fn_val; | 2513 | g->memcpy_fn_val = builtin_fn->fn_val; |
| 2473 | g->builtin_fn_table.put(&builtin_fn->name, builtin_fn); | ||
| 2474 | } | 2514 | } |
| 2475 | { | 2515 | { |
| 2476 | BuiltinFnEntry *builtin_fn = allocate<BuiltinFnEntry>(1); | 2516 | BuiltinFnEntry *builtin_fn = create_builtin_fn(g, BuiltinFnIdMemset, "memset"); |
| 2477 | buf_init_from_str(&builtin_fn->name, "memset"); | ||
| 2478 | builtin_fn->id = BuiltinFnIdMemset; | ||
| 2479 | builtin_fn->return_type = g->builtin_types.entry_void; | 2517 | builtin_fn->return_type = g->builtin_types.entry_void; |
| 2480 | builtin_fn->param_count = 3; | 2518 | builtin_fn->param_count = 3; |
| 2481 | builtin_fn->param_types = allocate<TypeTableEntry *>(builtin_fn->param_count); | 2519 | builtin_fn->param_types = allocate<TypeTableEntry *>(builtin_fn->param_count); |
| ... | @@ -2496,8 +2534,12 @@ static void define_builtin_fns(CodeGen *g) { | ... | @@ -2496,8 +2534,12 @@ static void define_builtin_fns(CodeGen *g) { |
| 2496 | assert(LLVMGetIntrinsicID(builtin_fn->fn_val)); | 2534 | assert(LLVMGetIntrinsicID(builtin_fn->fn_val)); |
| 2497 | 2535 | ||
| 2498 | g->memset_fn_val = builtin_fn->fn_val; | 2536 | g->memset_fn_val = builtin_fn->fn_val; |
| 2499 | g->builtin_fn_table.put(&builtin_fn->name, builtin_fn); | ||
| 2500 | } | 2537 | } |
| 2538 | create_one_arg_builtin_fn(g, BuiltinFnIdSizeof, "sizeof"); | ||
| 2539 | create_one_arg_builtin_fn(g, BuiltinFnIdMaxValue, "max_value"); | ||
| 2540 | create_one_arg_builtin_fn(g, BuiltinFnIdMinValue, "min_value"); | ||
| 2541 | create_one_arg_builtin_fn(g, BuiltinFnIdValueCount, "value_count"); | ||
| 2542 | create_one_arg_builtin_fn(g, BuiltinFnIdTypeof, "typeof"); | ||
| 2501 | } | 2543 | } |
| 2502 | 2544 | ||
| 2503 | 2545 | ||
| ... | @@ -2780,9 +2822,8 @@ void codegen_add_root_code(CodeGen *g, Buf *src_dir, Buf *src_basename, Buf *sou | ... | @@ -2780,9 +2822,8 @@ void codegen_add_root_code(CodeGen *g, Buf *src_dir, Buf *src_basename, Buf *sou |
| 2780 | } | 2822 | } |
| 2781 | 2823 | ||
| 2782 | static void to_c_type(CodeGen *g, AstNode *type_node, Buf *out_buf) { | 2824 | static void to_c_type(CodeGen *g, AstNode *type_node, Buf *out_buf) { |
| 2783 | assert(type_node->type == NodeTypeType); | 2825 | zig_panic("TODO this function needs some love"); |
| 2784 | 2826 | TypeTableEntry *type_entry = get_resolved_expr(type_node)->type_entry; | |
| 2785 | TypeTableEntry *type_entry = type_node->data.type.entry; | ||
| 2786 | assert(type_entry); | 2827 | assert(type_entry); |
| 2787 | 2828 | ||
| 2788 | if (type_entry == g->builtin_types.entry_u8) { | 2829 | if (type_entry == g->builtin_types.entry_u8) { |
src/parser.cpp+395-528| ... | @@ -62,6 +62,7 @@ static const char *prefix_op_str(PrefixOp prefix_op) { | ... | @@ -62,6 +62,7 @@ static const char *prefix_op_str(PrefixOp prefix_op) { |
| 62 | case PrefixOpAddressOf: return "&"; | 62 | case PrefixOpAddressOf: return "&"; |
| 63 | case PrefixOpConstAddressOf: return "&const"; | 63 | case PrefixOpConstAddressOf: return "&const"; |
| 64 | case PrefixOpDereference: return "*"; | 64 | case PrefixOpDereference: return "*"; |
| 65 | case PrefixOpMaybe: return "?"; | ||
| 65 | } | 66 | } |
| 66 | zig_unreachable(); | 67 | zig_unreachable(); |
| 67 | } | 68 | } |
| ... | @@ -80,8 +81,6 @@ const char *node_type_str(NodeType node_type) { | ... | @@ -80,8 +81,6 @@ const char *node_type_str(NodeType node_type) { |
| 80 | return "FnProto"; | 81 | return "FnProto"; |
| 81 | case NodeTypeParamDecl: | 82 | case NodeTypeParamDecl: |
| 82 | return "ParamDecl"; | 83 | return "ParamDecl"; |
| 83 | case NodeTypeType: | ||
| 84 | return "Type"; | ||
| 85 | case NodeTypeBlock: | 84 | case NodeTypeBlock: |
| 86 | return "Block"; | 85 | return "Block"; |
| 87 | case NodeTypeBinOpExpr: | 86 | case NodeTypeBinOpExpr: |
| ... | @@ -108,16 +107,12 @@ const char *node_type_str(NodeType node_type) { | ... | @@ -108,16 +107,12 @@ const char *node_type_str(NodeType node_type) { |
| 108 | return "StringLiteral"; | 107 | return "StringLiteral"; |
| 109 | case NodeTypeCharLiteral: | 108 | case NodeTypeCharLiteral: |
| 110 | return "CharLiteral"; | 109 | return "CharLiteral"; |
| 111 | case NodeTypeUnreachable: | ||
| 112 | return "Unreachable"; | ||
| 113 | case NodeTypeSymbol: | 110 | case NodeTypeSymbol: |
| 114 | return "Symbol"; | 111 | return "Symbol"; |
| 115 | case NodeTypePrefixOpExpr: | 112 | case NodeTypePrefixOpExpr: |
| 116 | return "PrefixOpExpr"; | 113 | return "PrefixOpExpr"; |
| 117 | case NodeTypeUse: | 114 | case NodeTypeUse: |
| 118 | return "Use"; | 115 | return "Use"; |
| 119 | case NodeTypeVoid: | ||
| 120 | return "Void"; | ||
| 121 | case NodeTypeBoolLiteral: | 116 | case NodeTypeBoolLiteral: |
| 122 | return "BoolLiteral"; | 117 | return "BoolLiteral"; |
| 123 | case NodeTypeNullLiteral: | 118 | case NodeTypeNullLiteral: |
| ... | @@ -144,14 +139,12 @@ const char *node_type_str(NodeType node_type) { | ... | @@ -144,14 +139,12 @@ const char *node_type_str(NodeType node_type) { |
| 144 | return "StructDecl"; | 139 | return "StructDecl"; |
| 145 | case NodeTypeStructField: | 140 | case NodeTypeStructField: |
| 146 | return "StructField"; | 141 | return "StructField"; |
| 147 | case NodeTypeStructValueExpr: | ||
| 148 | return "StructValueExpr"; | ||
| 149 | case NodeTypeStructValueField: | 142 | case NodeTypeStructValueField: |
| 150 | return "StructValueField"; | 143 | return "StructValueField"; |
| 151 | case NodeTypeCompilerFnExpr: | 144 | case NodeTypeContainerInitExpr: |
| 152 | return "CompilerFnExpr"; | 145 | return "ContainerInitExpr"; |
| 153 | case NodeTypeCompilerFnType: | 146 | case NodeTypeArrayType: |
| 154 | return "CompilerFnType"; | 147 | return "ArrayType"; |
| 155 | } | 148 | } |
| 156 | zig_unreachable(); | 149 | zig_unreachable(); |
| 157 | } | 150 | } |
| ... | @@ -214,47 +207,6 @@ void ast_print(AstNode *node, int indent) { | ... | @@ -214,47 +207,6 @@ void ast_print(AstNode *node, int indent) { |
| 214 | 207 | ||
| 215 | break; | 208 | break; |
| 216 | } | 209 | } |
| 217 | case NodeTypeType: | ||
| 218 | switch (node->data.type.type) { | ||
| 219 | case AstNodeTypeTypePrimitive: | ||
| 220 | { | ||
| 221 | Buf *name_buf = &node->data.type.primitive_name; | ||
| 222 | fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(name_buf)); | ||
| 223 | break; | ||
| 224 | } | ||
| 225 | case AstNodeTypeTypePointer: | ||
| 226 | { | ||
| 227 | const char *const_or_mut_str = node->data.type.is_const ? "const " : ""; | ||
| 228 | const char *noalias_or_not_str = node->data.type.is_noalias ? "noalias " : ""; | ||
| 229 | fprintf(stderr, "%s%s PointerType\n", const_or_mut_str, noalias_or_not_str); | ||
| 230 | |||
| 231 | ast_print(node->data.type.child_type, indent + 2); | ||
| 232 | break; | ||
| 233 | } | ||
| 234 | case AstNodeTypeTypeArray: | ||
| 235 | { | ||
| 236 | const char *const_or_mut_str = node->data.type.is_const ? "const " : ""; | ||
| 237 | const char *noalias_or_not_str = node->data.type.is_noalias ? "noalias " : ""; | ||
| 238 | fprintf(stderr, "%s%s ArrayType\n", const_or_mut_str, noalias_or_not_str); | ||
| 239 | if (node->data.type.array_size) | ||
| 240 | ast_print(node->data.type.array_size, indent + 2); | ||
| 241 | ast_print(node->data.type.child_type, indent + 2); | ||
| 242 | break; | ||
| 243 | } | ||
| 244 | case AstNodeTypeTypeMaybe: | ||
| 245 | { | ||
| 246 | fprintf(stderr, "MaybeType\n"); | ||
| 247 | ast_print(node->data.type.child_type, indent + 2); | ||
| 248 | break; | ||
| 249 | } | ||
| 250 | case AstNodeTypeTypeCompilerExpr: | ||
| 251 | { | ||
| 252 | fprintf(stderr, "CompilerExprType\n"); | ||
| 253 | ast_print(node->data.type.compiler_expr, indent + 2); | ||
| 254 | break; | ||
| 255 | } | ||
| 256 | } | ||
| 257 | break; | ||
| 258 | case NodeTypeReturnExpr: | 210 | case NodeTypeReturnExpr: |
| 259 | fprintf(stderr, "%s\n", node_type_str(node->type)); | 211 | fprintf(stderr, "%s\n", node_type_str(node->type)); |
| 260 | if (node->data.return_expr.expr) | 212 | if (node->data.return_expr.expr) |
| ... | @@ -348,18 +300,12 @@ void ast_print(AstNode *node, int indent) { | ... | @@ -348,18 +300,12 @@ void ast_print(AstNode *node, int indent) { |
| 348 | fprintf(stderr, "%s '%c'\n", node_type_str(node->type), node->data.char_literal.value); | 300 | fprintf(stderr, "%s '%c'\n", node_type_str(node->type), node->data.char_literal.value); |
| 349 | break; | 301 | break; |
| 350 | } | 302 | } |
| 351 | case NodeTypeUnreachable: | ||
| 352 | fprintf(stderr, "Unreachable\n"); | ||
| 353 | break; | ||
| 354 | case NodeTypeSymbol: | 303 | case NodeTypeSymbol: |
| 355 | fprintf(stderr, "Symbol %s\n", buf_ptr(&node->data.symbol_expr.symbol)); | 304 | fprintf(stderr, "Symbol %s\n", buf_ptr(&node->data.symbol_expr.symbol)); |
| 356 | break; | 305 | break; |
| 357 | case NodeTypeUse: | 306 | case NodeTypeUse: |
| 358 | fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.use.path)); | 307 | fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.use.path)); |
| 359 | break; | 308 | break; |
| 360 | case NodeTypeVoid: | ||
| 361 | fprintf(stderr, "%s\n", node_type_str(node->type)); | ||
| 362 | break; | ||
| 363 | case NodeTypeBoolLiteral: | 309 | case NodeTypeBoolLiteral: |
| 364 | fprintf(stderr, "%s '%s'\n", node_type_str(node->type), | 310 | fprintf(stderr, "%s '%s'\n", node_type_str(node->type), |
| 365 | node->data.bool_literal.value ? "true" : "false"); | 311 | node->data.bool_literal.value ? "true" : "false"); |
| ... | @@ -431,24 +377,28 @@ void ast_print(AstNode *node, int indent) { | ... | @@ -431,24 +377,28 @@ void ast_print(AstNode *node, int indent) { |
| 431 | ast_print(node->data.struct_field.type, indent + 2); | 377 | ast_print(node->data.struct_field.type, indent + 2); |
| 432 | } | 378 | } |
| 433 | break; | 379 | break; |
| 434 | case NodeTypeStructValueExpr: | ||
| 435 | fprintf(stderr, "%s\n", node_type_str(node->type)); | ||
| 436 | ast_print(node->data.struct_val_expr.type, indent + 2); | ||
| 437 | for (int i = 0; i < node->data.struct_val_expr.fields.length; i += 1) { | ||
| 438 | AstNode *child = node->data.struct_val_expr.fields.at(i); | ||
| 439 | ast_print(child, indent + 2); | ||
| 440 | } | ||
| 441 | break; | ||
| 442 | case NodeTypeStructValueField: | 380 | case NodeTypeStructValueField: |
| 443 | fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.struct_val_field.name)); | 381 | fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.struct_val_field.name)); |
| 444 | ast_print(node->data.struct_val_field.expr, indent + 2); | 382 | ast_print(node->data.struct_val_field.expr, indent + 2); |
| 445 | break; | 383 | break; |
| 446 | case NodeTypeCompilerFnExpr: | 384 | case NodeTypeContainerInitExpr: |
| 447 | fprintf(stderr, "%s\n", node_type_str(node->type)); | ||
| 448 | break; | ||
| 449 | case NodeTypeCompilerFnType: | ||
| 450 | fprintf(stderr, "%s\n", node_type_str(node->type)); | 385 | fprintf(stderr, "%s\n", node_type_str(node->type)); |
| 386 | ast_print(node->data.container_init_expr.type, indent + 2); | ||
| 387 | for (int i = 0; i < node->data.container_init_expr.entries.length; i += 1) { | ||
| 388 | AstNode *child = node->data.container_init_expr.entries.at(i); | ||
| 389 | ast_print(child, indent + 2); | ||
| 390 | } | ||
| 451 | break; | 391 | break; |
| 392 | case NodeTypeArrayType: | ||
| 393 | { | ||
| 394 | const char *const_str = node->data.array_type.is_const ? "const" : "var"; | ||
| 395 | fprintf(stderr, "%s %s\n", node_type_str(node->type), const_str); | ||
| 396 | if (node->data.array_type.size) { | ||
| 397 | ast_print(node->data.array_type.size, indent + 2); | ||
| 398 | } | ||
| 399 | ast_print(node->data.array_type.child_type, indent + 2); | ||
| 400 | break; | ||
| 401 | } | ||
| 452 | } | 402 | } |
| 453 | } | 403 | } |
| 454 | 404 | ||
| ... | @@ -539,9 +489,8 @@ static AstNode *ast_create_node_with_node(ParseContext *pc, NodeType type, AstNo | ... | @@ -539,9 +489,8 @@ static AstNode *ast_create_node_with_node(ParseContext *pc, NodeType type, AstNo |
| 539 | } | 489 | } |
| 540 | 490 | ||
| 541 | static AstNode *ast_create_void_type_node(ParseContext *pc, Token *token) { | 491 | static AstNode *ast_create_void_type_node(ParseContext *pc, Token *token) { |
| 542 | AstNode *node = ast_create_node(pc, NodeTypeType, token); | 492 | AstNode *node = ast_create_node(pc, NodeTypeSymbol, token); |
| 543 | node->data.type.type = AstNodeTypeTypePrimitive; | 493 | buf_init_from_str(&node->data.symbol_expr.symbol, "void"); |
| 544 | buf_init_from_str(&node->data.type.primitive_name, "void"); | ||
| 545 | return node; | 494 | return node; |
| 546 | } | 495 | } |
| 547 | 496 | ||
| ... | @@ -961,7 +910,7 @@ static AstNode *ast_parse_expression(ParseContext *pc, int *token_index, bool ma | ... | @@ -961,7 +910,7 @@ static AstNode *ast_parse_expression(ParseContext *pc, int *token_index, bool ma |
| 961 | static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandatory); | 910 | static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandatory); |
| 962 | static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool mandatory); | 911 | static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool mandatory); |
| 963 | static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool mandatory); | 912 | static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool mandatory); |
| 964 | static AstNode *ast_parse_type(ParseContext *pc, int *token_index); | 913 | static AstNode *ast_parse_unwrap_maybe_expr(ParseContext *pc, int *token_index, bool mandatory); |
| 965 | 914 | ||
| 966 | static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) { | 915 | static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) { |
| 967 | if (token->id != token_id) { | 916 | if (token->id != token_id) { |
| ... | @@ -1022,172 +971,42 @@ static void ast_parse_directives(ParseContext *pc, int *token_index, | ... | @@ -1022,172 +971,42 @@ static void ast_parse_directives(ParseContext *pc, int *token_index, |
| 1022 | zig_unreachable(); | 971 | zig_unreachable(); |
| 1023 | } | 972 | } |
| 1024 | 973 | ||
| 1025 | static void ast_parse_type_assume_amp(ParseContext *pc, int *token_index, AstNode *node) { | ||
| 1026 | node->data.type.type = AstNodeTypeTypePointer; | ||
| 1027 | Token *first_type_token = &pc->tokens->at(*token_index); | ||
| 1028 | if (first_type_token->id == TokenIdKeywordConst) { | ||
| 1029 | node->data.type.is_const = true; | ||
| 1030 | *token_index += 1; | ||
| 1031 | first_type_token = &pc->tokens->at(*token_index); | ||
| 1032 | if (first_type_token->id == TokenIdKeywordNoAlias) { | ||
| 1033 | node->data.type.is_noalias = true; | ||
| 1034 | *token_index += 1; | ||
| 1035 | } | ||
| 1036 | } else if (first_type_token->id == TokenIdKeywordNoAlias) { | ||
| 1037 | node->data.type.is_noalias = true; | ||
| 1038 | *token_index += 1; | ||
| 1039 | } | ||
| 1040 | |||
| 1041 | node->data.type.child_type = ast_parse_type(pc, token_index); | ||
| 1042 | } | ||
| 1043 | |||
| 1044 | /* | 974 | /* |
| 1045 | CompilerFnType : token(NumberSign) token(Symbol) token(LParen) Expression token(RParen) | 975 | ParamDecl : option(token(NoAlias)) token(Symbol) token(Colon) UnwrapMaybeExpression | token(Ellipsis) |
| 1046 | */ | 976 | */ |
| 1047 | static AstNode *ast_parse_compiler_fn_type(ParseContext *pc, int *token_index, bool mandatory) { | 977 | static AstNode *ast_parse_param_decl(ParseContext *pc, int *token_index) { |
| 1048 | Token *token = &pc->tokens->at(*token_index); | 978 | Token *first_token = &pc->tokens->at(*token_index); |
| 1049 | 979 | ||
| 1050 | if (token->id == TokenIdNumberSign) { | 980 | if (first_token->id == TokenIdEllipsis) { |
| 1051 | *token_index += 1; | 981 | *token_index += 1; |
| 1052 | } else if (mandatory) { | ||
| 1053 | ast_invalid_token_error(pc, token); | ||
| 1054 | } else { | ||
| 1055 | return nullptr; | 982 | return nullptr; |
| 1056 | } | 983 | } |
| 1057 | 984 | ||
| 1058 | Token *name_symbol = ast_eat_token(pc, token_index, TokenIdSymbol); | 985 | AstNode *node = ast_create_node(pc, NodeTypeParamDecl, first_token); |
| 1059 | ast_eat_token(pc, token_index, TokenIdLParen); | 986 | Token *name_token; |
| 1060 | |||
| 1061 | AstNode *node = ast_create_node(pc, NodeTypeCompilerFnType, token); | ||
| 1062 | ast_buf_from_token(pc, name_symbol, &node->data.compiler_fn_type.name); | ||
| 1063 | node->data.compiler_fn_type.type = ast_parse_type(pc, token_index); | ||
| 1064 | |||
| 1065 | ast_eat_token(pc, token_index, TokenIdRParen); | ||
| 1066 | return node; | ||
| 1067 | } | ||
| 1068 | 987 | ||
| 1069 | /* | 988 | if (first_token->id == TokenIdKeywordNoAlias) { |
| 1070 | CompilerFnExpr : token(NumberSign) token(Symbol) token(LParen) Expression token(RParen) | 989 | node->data.param_decl.is_noalias = true; |
| 1071 | */ | 990 | *token_index += 1; |
| 1072 | static AstNode *ast_parse_compiler_fn_call(ParseContext *pc, int *token_index, bool mandatory) { | 991 | name_token = ast_eat_token(pc, token_index, TokenIdSymbol); |
| 1073 | Token *token = &pc->tokens->at(*token_index); | 992 | } else if (first_token->id == TokenIdSymbol) { |
| 1074 | 993 | name_token = first_token; | |
| 1075 | if (token->id == TokenIdNumberSign) { | ||
| 1076 | *token_index += 1; | 994 | *token_index += 1; |
| 1077 | } else if (mandatory) { | ||
| 1078 | ast_invalid_token_error(pc, token); | ||
| 1079 | } else { | 995 | } else { |
| 1080 | return nullptr; | 996 | ast_invalid_token_error(pc, first_token); |
| 1081 | } | 997 | } |
| 1082 | 998 | ||
| 1083 | Token *name_symbol = ast_eat_token(pc, token_index, TokenIdSymbol); | 999 | ast_buf_from_token(pc, name_token, &node->data.param_decl.name); |
| 1084 | ast_eat_token(pc, token_index, TokenIdLParen); | ||
| 1085 | |||
| 1086 | AstNode *node = ast_create_node(pc, NodeTypeCompilerFnExpr, token); | ||
| 1087 | ast_buf_from_token(pc, name_symbol, &node->data.compiler_fn_expr.name); | ||
| 1088 | node->data.compiler_fn_expr.expr = ast_parse_expression(pc, token_index, true); | ||
| 1089 | |||
| 1090 | ast_eat_token(pc, token_index, TokenIdRParen); | ||
| 1091 | return node; | ||
| 1092 | } | ||
| 1093 | |||
| 1094 | /* | ||
| 1095 | Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType | MaybeType | CompilerFnExpr | ||
| 1096 | PointerType : token(Ampersand) option(token(Const)) option(token(NoAlias)) Type | ||
| 1097 | ArrayType : token(LBracket) option(Expression) token(RBracket) option(token(Const)) option(token(NoAlias)) Type | ||
| 1098 | */ | ||
| 1099 | static AstNode *ast_parse_type(ParseContext *pc, int *token_index) { | ||
| 1100 | Token *token = &pc->tokens->at(*token_index); | ||
| 1101 | AstNode *node = ast_create_node(pc, NodeTypeType, token); | ||
| 1102 | |||
| 1103 | AstNode *compiler_fn_expr = ast_parse_compiler_fn_call(pc, token_index, false); | ||
| 1104 | if (compiler_fn_expr) { | ||
| 1105 | node->data.type.type = AstNodeTypeTypeCompilerExpr; | ||
| 1106 | node->data.type.compiler_expr = compiler_fn_expr; | ||
| 1107 | return node; | ||
| 1108 | } | ||
| 1109 | 1000 | ||
| 1001 | Token *colon = &pc->tokens->at(*token_index); | ||
| 1110 | *token_index += 1; | 1002 | *token_index += 1; |
| 1003 | ast_expect_token(pc, colon, TokenIdColon); | ||
| 1111 | 1004 | ||
| 1112 | if (token->id == TokenIdKeywordUnreachable) { | 1005 | node->data.param_decl.type = ast_parse_unwrap_maybe_expr(pc, token_index, true); |
| 1113 | node->data.type.type = AstNodeTypeTypePrimitive; | ||
| 1114 | buf_init_from_str(&node->data.type.primitive_name, "unreachable"); | ||
| 1115 | } else if (token->id == TokenIdKeywordVoid) { | ||
| 1116 | node->data.type.type = AstNodeTypeTypePrimitive; | ||
| 1117 | buf_init_from_str(&node->data.type.primitive_name, "void"); | ||
| 1118 | } else if (token->id == TokenIdSymbol) { | ||
| 1119 | node->data.type.type = AstNodeTypeTypePrimitive; | ||
| 1120 | ast_buf_from_token(pc, token, &node->data.type.primitive_name); | ||
| 1121 | } else if (token->id == TokenIdAmpersand) { | ||
| 1122 | ast_parse_type_assume_amp(pc, token_index, node); | ||
| 1123 | } else if (token->id == TokenIdMaybe) { | ||
| 1124 | node->data.type.type = AstNodeTypeTypeMaybe; | ||
| 1125 | node->data.type.child_type = ast_parse_type(pc, token_index); | ||
| 1126 | } else if (token->id == TokenIdBoolAnd) { | ||
| 1127 | // Pretend that we got 2 ampersand tokens | ||
| 1128 | node->data.type.type = AstNodeTypeTypePointer; | ||
| 1129 | |||
| 1130 | node->data.type.child_type = ast_create_node_no_line_info(pc, NodeTypeType); | ||
| 1131 | node->data.type.child_type->line = token->start_line; | ||
| 1132 | node->data.type.child_type->column = token->start_column + 1; | ||
| 1133 | |||
| 1134 | ast_parse_type_assume_amp(pc, token_index, node->data.type.child_type); | ||
| 1135 | } else if (token->id == TokenIdLBracket) { | ||
| 1136 | node->data.type.type = AstNodeTypeTypeArray; | ||
| 1137 | |||
| 1138 | node->data.type.array_size = ast_parse_expression(pc, token_index, false); | ||
| 1139 | |||
| 1140 | ast_eat_token(pc, token_index, TokenIdRBracket); | ||
| 1141 | |||
| 1142 | Token *const_tok = &pc->tokens->at(*token_index); | ||
| 1143 | if (const_tok->id == TokenIdKeywordConst) { | ||
| 1144 | *token_index += 1; | ||
| 1145 | node->data.type.is_const = true; | ||
| 1146 | |||
| 1147 | Token *next_tok = &pc->tokens->at(*token_index); | ||
| 1148 | if (next_tok->id == TokenIdKeywordNoAlias) { | ||
| 1149 | *token_index += 1; | ||
| 1150 | node->data.type.is_noalias = true; | ||
| 1151 | } | ||
| 1152 | } else if (const_tok->id == TokenIdKeywordNoAlias) { | ||
| 1153 | *token_index += 1; | ||
| 1154 | node->data.type.is_noalias = true; | ||
| 1155 | } | ||
| 1156 | |||
| 1157 | node->data.type.child_type = ast_parse_type(pc, token_index); | ||
| 1158 | } else { | ||
| 1159 | ast_invalid_token_error(pc, token); | ||
| 1160 | } | ||
| 1161 | 1006 | ||
| 1162 | return node; | 1007 | return node; |
| 1163 | } | 1008 | } |
| 1164 | 1009 | ||
| 1165 | /* | ||
| 1166 | ParamDecl : token(Symbol) token(Colon) Type | token(Ellipsis) | ||
| 1167 | */ | ||
| 1168 | static AstNode *ast_parse_param_decl(ParseContext *pc, int *token_index) { | ||
| 1169 | Token *param_name = &pc->tokens->at(*token_index); | ||
| 1170 | *token_index += 1; | ||
| 1171 | |||
| 1172 | if (param_name->id == TokenIdSymbol) { | ||
| 1173 | AstNode *node = ast_create_node(pc, NodeTypeParamDecl, param_name); | ||
| 1174 | |||
| 1175 | ast_buf_from_token(pc, param_name, &node->data.param_decl.name); | ||
| 1176 | |||
| 1177 | Token *colon = &pc->tokens->at(*token_index); | ||
| 1178 | *token_index += 1; | ||
| 1179 | ast_expect_token(pc, colon, TokenIdColon); | ||
| 1180 | |||
| 1181 | node->data.param_decl.type = ast_parse_type(pc, token_index); | ||
| 1182 | |||
| 1183 | return node; | ||
| 1184 | } else if (param_name->id == TokenIdEllipsis) { | ||
| 1185 | return nullptr; | ||
| 1186 | } else { | ||
| 1187 | ast_invalid_token_error(pc, param_name); | ||
| 1188 | } | ||
| 1189 | } | ||
| 1190 | |||
| 1191 | 1010 | ||
| 1192 | static void ast_parse_param_decl_list(ParseContext *pc, int *token_index, | 1011 | static void ast_parse_param_decl_list(ParseContext *pc, int *token_index, |
| 1193 | ZigList<AstNode *> *params, bool *is_var_args) | 1012 | ZigList<AstNode *> *params, bool *is_var_args) |
| ... | @@ -1274,52 +1093,222 @@ static AstNode *ast_parse_grouped_expr(ParseContext *pc, int *token_index, bool | ... | @@ -1274,52 +1093,222 @@ static AstNode *ast_parse_grouped_expr(ParseContext *pc, int *token_index, bool |
| 1274 | } | 1093 | } |
| 1275 | 1094 | ||
| 1276 | /* | 1095 | /* |
| 1277 | StructValueExpression : token(Symbol) token(LBrace) list(StructValueExpressionField, token(Comma)) token(RBrace) | 1096 | ArrayType : token(LBracket) option(Expression) token(RBracket) option(token(Const)) Expression |
| 1278 | StructValueExpressionField : token(Dot) token(Symbol) token(Eq) Expression | ||
| 1279 | */ | 1097 | */ |
| 1280 | static AstNode *ast_parse_struct_val_expr(ParseContext *pc, int *token_index) { | 1098 | static AstNode *ast_parse_array_type_expr(ParseContext *pc, int *token_index, bool mandatory) { |
| 1281 | Token *first_token = &pc->tokens->at(*token_index); | 1099 | Token *l_bracket = &pc->tokens->at(*token_index); |
| 1282 | AstNode *node = ast_create_node(pc, NodeTypeStructValueExpr, first_token); | 1100 | if (l_bracket->id != TokenIdLBracket) { |
| 1101 | if (mandatory) { | ||
| 1102 | ast_invalid_token_error(pc, l_bracket); | ||
| 1103 | } else { | ||
| 1104 | return nullptr; | ||
| 1105 | } | ||
| 1106 | } | ||
| 1283 | 1107 | ||
| 1284 | node->data.struct_val_expr.type = ast_parse_type(pc, token_index); | 1108 | *token_index += 1; |
| 1285 | 1109 | ||
| 1286 | ast_eat_token(pc, token_index, TokenIdLBrace); | 1110 | AstNode *node = ast_create_node(pc, NodeTypeArrayType, l_bracket); |
| 1111 | node->data.array_type.size = ast_parse_expression(pc, token_index, false); | ||
| 1112 | |||
| 1113 | ast_eat_token(pc, token_index, TokenIdRBracket); | ||
| 1114 | |||
| 1115 | Token *const_tok = &pc->tokens->at(*token_index); | ||
| 1116 | if (const_tok->id == TokenIdKeywordConst) { | ||
| 1117 | *token_index += 1; | ||
| 1118 | node->data.array_type.is_const = true; | ||
| 1119 | } | ||
| 1120 | |||
| 1121 | node->data.array_type.child_type = ast_parse_expression(pc, token_index, true); | ||
| 1122 | |||
| 1123 | return node; | ||
| 1124 | } | ||
| 1125 | |||
| 1126 | /* | ||
| 1127 | AsmInputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) Expression token(RParen) | ||
| 1128 | */ | ||
| 1129 | static void ast_parse_asm_input_item(ParseContext *pc, int *token_index, AstNode *node) { | ||
| 1130 | ast_eat_token(pc, token_index, TokenIdLBracket); | ||
| 1131 | Token *alias = ast_eat_token(pc, token_index, TokenIdSymbol); | ||
| 1132 | ast_eat_token(pc, token_index, TokenIdRBracket); | ||
| 1133 | |||
| 1134 | Token *constraint = ast_eat_token(pc, token_index, TokenIdStringLiteral); | ||
| 1135 | |||
| 1136 | ast_eat_token(pc, token_index, TokenIdLParen); | ||
| 1137 | AstNode *expr_node = ast_parse_expression(pc, token_index, true); | ||
| 1138 | ast_eat_token(pc, token_index, TokenIdRParen); | ||
| 1139 | |||
| 1140 | AsmInput *asm_input = allocate<AsmInput>(1); | ||
| 1141 | ast_buf_from_token(pc, alias, &asm_input->asm_symbolic_name); | ||
| 1142 | parse_string_literal(pc, constraint, &asm_input->constraint, nullptr, nullptr); | ||
| 1143 | asm_input->expr = expr_node; | ||
| 1144 | node->data.asm_expr.input_list.append(asm_input); | ||
| 1145 | } | ||
| 1146 | |||
| 1147 | /* | ||
| 1148 | AsmOutputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) (token(Symbol) | token(Arrow) Expression) token(RParen) | ||
| 1149 | */ | ||
| 1150 | static void ast_parse_asm_output_item(ParseContext *pc, int *token_index, AstNode *node) { | ||
| 1151 | ast_eat_token(pc, token_index, TokenIdLBracket); | ||
| 1152 | Token *alias = ast_eat_token(pc, token_index, TokenIdSymbol); | ||
| 1153 | ast_eat_token(pc, token_index, TokenIdRBracket); | ||
| 1154 | |||
| 1155 | Token *constraint = ast_eat_token(pc, token_index, TokenIdStringLiteral); | ||
| 1156 | |||
| 1157 | AsmOutput *asm_output = allocate<AsmOutput>(1); | ||
| 1158 | |||
| 1159 | ast_eat_token(pc, token_index, TokenIdLParen); | ||
| 1160 | |||
| 1161 | Token *token = &pc->tokens->at(*token_index); | ||
| 1162 | *token_index += 1; | ||
| 1163 | if (token->id == TokenIdSymbol) { | ||
| 1164 | ast_buf_from_token(pc, token, &asm_output->variable_name); | ||
| 1165 | } else if (token->id == TokenIdArrow) { | ||
| 1166 | asm_output->return_type = ast_parse_expression(pc, token_index, true); | ||
| 1167 | } else { | ||
| 1168 | ast_invalid_token_error(pc, token); | ||
| 1169 | } | ||
| 1170 | |||
| 1171 | ast_eat_token(pc, token_index, TokenIdRParen); | ||
| 1172 | |||
| 1173 | ast_buf_from_token(pc, alias, &asm_output->asm_symbolic_name); | ||
| 1174 | parse_string_literal(pc, constraint, &asm_output->constraint, nullptr, nullptr); | ||
| 1175 | node->data.asm_expr.output_list.append(asm_output); | ||
| 1176 | } | ||
| 1177 | |||
| 1178 | /* | ||
| 1179 | AsmClobbers: token(Colon) list(token(String), token(Comma)) | ||
| 1180 | */ | ||
| 1181 | static void ast_parse_asm_clobbers(ParseContext *pc, int *token_index, AstNode *node) { | ||
| 1182 | Token *colon_tok = &pc->tokens->at(*token_index); | ||
| 1183 | |||
| 1184 | if (colon_tok->id != TokenIdColon) | ||
| 1185 | return; | ||
| 1186 | |||
| 1187 | *token_index += 1; | ||
| 1287 | 1188 | ||
| 1288 | for (;;) { | 1189 | for (;;) { |
| 1289 | Token *token = &pc->tokens->at(*token_index); | 1190 | Token *string_tok = &pc->tokens->at(*token_index); |
| 1191 | ast_expect_token(pc, string_tok, TokenIdStringLiteral); | ||
| 1290 | *token_index += 1; | 1192 | *token_index += 1; |
| 1291 | 1193 | ||
| 1292 | if (token->id == TokenIdRBrace) { | 1194 | Buf *clobber_buf = buf_alloc(); |
| 1293 | return node; | 1195 | parse_string_literal(pc, string_tok, clobber_buf, nullptr, nullptr); |
| 1294 | } else if (token->id == TokenIdDot) { | 1196 | node->data.asm_expr.clobber_list.append(clobber_buf); |
| 1295 | Token *field_name_tok = ast_eat_token(pc, token_index, TokenIdSymbol); | 1197 | |
| 1296 | ast_eat_token(pc, token_index, TokenIdEq); | 1198 | Token *comma = &pc->tokens->at(*token_index); |
| 1199 | |||
| 1200 | if (comma->id == TokenIdComma) { | ||
| 1201 | *token_index += 1; | ||
| 1202 | continue; | ||
| 1203 | } else { | ||
| 1204 | break; | ||
| 1205 | } | ||
| 1206 | } | ||
| 1207 | } | ||
| 1297 | 1208 | ||
| 1298 | AstNode *field_node = ast_create_node(pc, NodeTypeStructValueField, token); | 1209 | /* |
| 1210 | AsmInput : token(Colon) list(AsmInputItem, token(Comma)) option(AsmClobbers) | ||
| 1211 | */ | ||
| 1212 | static void ast_parse_asm_input(ParseContext *pc, int *token_index, AstNode *node) { | ||
| 1213 | Token *colon_tok = &pc->tokens->at(*token_index); | ||
| 1299 | 1214 | ||
| 1300 | ast_buf_from_token(pc, field_name_tok, &field_node->data.struct_val_field.name); | 1215 | if (colon_tok->id != TokenIdColon) |
| 1301 | field_node->data.struct_val_field.expr = ast_parse_expression(pc, token_index, true); | 1216 | return; |
| 1302 | 1217 | ||
| 1303 | node->data.struct_val_expr.fields.append(field_node); | 1218 | *token_index += 1; |
| 1304 | 1219 | ||
| 1305 | Token *comma_tok = &pc->tokens->at(*token_index); | 1220 | for (;;) { |
| 1306 | if (comma_tok->id == TokenIdComma) { | 1221 | ast_parse_asm_input_item(pc, token_index, node); |
| 1307 | *token_index += 1; | 1222 | |
| 1308 | } else if (comma_tok->id != TokenIdRBrace) { | 1223 | Token *comma = &pc->tokens->at(*token_index); |
| 1309 | ast_invalid_token_error(pc, comma_tok); | 1224 | |
| 1310 | } else { | 1225 | if (comma->id == TokenIdComma) { |
| 1311 | *token_index += 1; | 1226 | *token_index += 1; |
| 1312 | return node; | 1227 | continue; |
| 1313 | } | ||
| 1314 | } else { | 1228 | } else { |
| 1315 | ast_invalid_token_error(pc, token); | 1229 | break; |
| 1316 | } | 1230 | } |
| 1317 | } | 1231 | } |
| 1232 | |||
| 1233 | ast_parse_asm_clobbers(pc, token_index, node); | ||
| 1318 | } | 1234 | } |
| 1319 | 1235 | ||
| 1320 | /* | 1236 | /* |
| 1321 | PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression | CompilerFnType | (token(AtSign) token(Symbol) FnCallExpression) | 1237 | AsmOutput : token(Colon) list(AsmOutputItem, token(Comma)) option(AsmInput) |
| 1322 | KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False) | token(Null) | 1238 | */ |
| 1239 | static void ast_parse_asm_output(ParseContext *pc, int *token_index, AstNode *node) { | ||
| 1240 | Token *colon_tok = &pc->tokens->at(*token_index); | ||
| 1241 | |||
| 1242 | if (colon_tok->id != TokenIdColon) | ||
| 1243 | return; | ||
| 1244 | |||
| 1245 | *token_index += 1; | ||
| 1246 | |||
| 1247 | for (;;) { | ||
| 1248 | ast_parse_asm_output_item(pc, token_index, node); | ||
| 1249 | |||
| 1250 | Token *comma = &pc->tokens->at(*token_index); | ||
| 1251 | |||
| 1252 | if (comma->id == TokenIdComma) { | ||
| 1253 | *token_index += 1; | ||
| 1254 | continue; | ||
| 1255 | } else { | ||
| 1256 | break; | ||
| 1257 | } | ||
| 1258 | } | ||
| 1259 | |||
| 1260 | ast_parse_asm_input(pc, token_index, node); | ||
| 1261 | } | ||
| 1262 | |||
| 1263 | /* | ||
| 1264 | AsmExpression : token(Asm) option(token(Volatile)) token(LParen) token(String) option(AsmOutput) token(RParen) | ||
| 1265 | */ | ||
| 1266 | static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mandatory) { | ||
| 1267 | Token *asm_token = &pc->tokens->at(*token_index); | ||
| 1268 | |||
| 1269 | if (asm_token->id != TokenIdKeywordAsm) { | ||
| 1270 | if (mandatory) { | ||
| 1271 | ast_invalid_token_error(pc, asm_token); | ||
| 1272 | } else { | ||
| 1273 | return nullptr; | ||
| 1274 | } | ||
| 1275 | } | ||
| 1276 | |||
| 1277 | AstNode *node = ast_create_node(pc, NodeTypeAsmExpr, asm_token); | ||
| 1278 | |||
| 1279 | *token_index += 1; | ||
| 1280 | Token *lparen_tok = &pc->tokens->at(*token_index); | ||
| 1281 | |||
| 1282 | if (lparen_tok->id == TokenIdKeywordVolatile) { | ||
| 1283 | node->data.asm_expr.is_volatile = true; | ||
| 1284 | |||
| 1285 | *token_index += 1; | ||
| 1286 | lparen_tok = &pc->tokens->at(*token_index); | ||
| 1287 | } | ||
| 1288 | |||
| 1289 | ast_expect_token(pc, lparen_tok, TokenIdLParen); | ||
| 1290 | *token_index += 1; | ||
| 1291 | |||
| 1292 | Token *template_tok = &pc->tokens->at(*token_index); | ||
| 1293 | ast_expect_token(pc, template_tok, TokenIdStringLiteral); | ||
| 1294 | *token_index += 1; | ||
| 1295 | |||
| 1296 | parse_string_literal(pc, template_tok, &node->data.asm_expr.asm_template, nullptr, | ||
| 1297 | &node->data.asm_expr.offset_map); | ||
| 1298 | parse_asm_template(pc, node); | ||
| 1299 | |||
| 1300 | ast_parse_asm_output(pc, token_index, node); | ||
| 1301 | |||
| 1302 | Token *rparen_tok = &pc->tokens->at(*token_index); | ||
| 1303 | ast_expect_token(pc, rparen_tok, TokenIdRParen); | ||
| 1304 | *token_index += 1; | ||
| 1305 | |||
| 1306 | return node; | ||
| 1307 | } | ||
| 1308 | |||
| 1309 | /* | ||
| 1310 | PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | token(Symbol) | (token(AtSign) token(Symbol) FnCallExpression) | ArrayType | AsmExpression | ||
| 1311 | KeywordLiteral : token(True) | token(False) | token(Null) | token(Break) | token(Continue) | ||
| 1323 | */ | 1312 | */ |
| 1324 | static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) { | 1313 | static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) { |
| 1325 | Token *token = &pc->tokens->at(*token_index); | 1314 | Token *token = &pc->tokens->at(*token_index); |
| ... | @@ -1339,14 +1328,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool | ... | @@ -1339,14 +1328,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool |
| 1339 | node->data.char_literal.value = parse_char_literal(pc, token); | 1328 | node->data.char_literal.value = parse_char_literal(pc, token); |
| 1340 | *token_index += 1; | 1329 | *token_index += 1; |
| 1341 | return node; | 1330 | return node; |
| 1342 | } else if (token->id == TokenIdKeywordUnreachable) { | ||
| 1343 | AstNode *node = ast_create_node(pc, NodeTypeUnreachable, token); | ||
| 1344 | *token_index += 1; | ||
| 1345 | return node; | ||
| 1346 | } else if (token->id == TokenIdKeywordVoid) { | ||
| 1347 | AstNode *node = ast_create_node(pc, NodeTypeVoid, token); | ||
| 1348 | *token_index += 1; | ||
| 1349 | return node; | ||
| 1350 | } else if (token->id == TokenIdKeywordTrue) { | 1331 | } else if (token->id == TokenIdKeywordTrue) { |
| 1351 | AstNode *node = ast_create_node(pc, NodeTypeBoolLiteral, token); | 1332 | AstNode *node = ast_create_node(pc, NodeTypeBoolLiteral, token); |
| 1352 | node->data.bool_literal.value = true; | 1333 | node->data.bool_literal.value = true; |
| ... | @@ -1357,8 +1338,16 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool | ... | @@ -1357,8 +1338,16 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool |
| 1357 | node->data.bool_literal.value = false; | 1338 | node->data.bool_literal.value = false; |
| 1358 | *token_index += 1; | 1339 | *token_index += 1; |
| 1359 | return node; | 1340 | return node; |
| 1360 | } else if (token->id == TokenIdKeywordNull) { | 1341 | } else if (token->id == TokenIdKeywordNull) { |
| 1361 | AstNode *node = ast_create_node(pc, NodeTypeNullLiteral, token); | 1342 | AstNode *node = ast_create_node(pc, NodeTypeNullLiteral, token); |
| 1343 | *token_index += 1; | ||
| 1344 | return node; | ||
| 1345 | } else if (token->id == TokenIdKeywordBreak) { | ||
| 1346 | AstNode *node = ast_create_node(pc, NodeTypeBreak, token); | ||
| 1347 | *token_index += 1; | ||
| 1348 | return node; | ||
| 1349 | } else if (token->id == TokenIdKeywordContinue) { | ||
| 1350 | AstNode *node = ast_create_node(pc, NodeTypeContinue, token); | ||
| 1362 | *token_index += 1; | 1351 | *token_index += 1; |
| 1363 | return node; | 1352 | return node; |
| 1364 | } else if (token->id == TokenIdAtSign) { | 1353 | } else if (token->id == TokenIdAtSign) { |
| ... | @@ -1374,16 +1363,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool | ... | @@ -1374,16 +1363,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool |
| 1374 | node->data.fn_call_expr.is_builtin = true; | 1363 | node->data.fn_call_expr.is_builtin = true; |
| 1375 | return node; | 1364 | return node; |
| 1376 | } else if (token->id == TokenIdSymbol) { | 1365 | } else if (token->id == TokenIdSymbol) { |
| 1377 | Token *next_token = &pc->tokens->at(*token_index + 1); | 1366 | *token_index += 1; |
| 1378 | 1367 | AstNode *node = ast_create_node(pc, NodeTypeSymbol, token); | |
| 1379 | if (next_token->id == TokenIdLBrace) { | 1368 | ast_buf_from_token(pc, token, &node->data.symbol_expr.symbol); |
| 1380 | return ast_parse_struct_val_expr(pc, token_index); | 1369 | return node; |
| 1381 | } else { | ||
| 1382 | *token_index += 1; | ||
| 1383 | AstNode *node = ast_create_node(pc, NodeTypeSymbol, token); | ||
| 1384 | ast_buf_from_token(pc, token, &node->data.symbol_expr.symbol); | ||
| 1385 | return node; | ||
| 1386 | } | ||
| 1387 | } else if (token->id == TokenIdKeywordGoto) { | 1370 | } else if (token->id == TokenIdKeywordGoto) { |
| 1388 | AstNode *node = ast_create_node(pc, NodeTypeGoto, token); | 1371 | AstNode *node = ast_create_node(pc, NodeTypeGoto, token); |
| 1389 | *token_index += 1; | 1372 | *token_index += 1; |
| ... | @@ -1394,14 +1377,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool | ... | @@ -1394,14 +1377,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool |
| 1394 | 1377 | ||
| 1395 | ast_buf_from_token(pc, dest_symbol, &node->data.goto_expr.name); | 1378 | ast_buf_from_token(pc, dest_symbol, &node->data.goto_expr.name); |
| 1396 | return node; | 1379 | return node; |
| 1397 | } else if (token->id == TokenIdKeywordBreak) { | ||
| 1398 | AstNode *node = ast_create_node(pc, NodeTypeBreak, token); | ||
| 1399 | *token_index += 1; | ||
| 1400 | return node; | ||
| 1401 | } else if (token->id == TokenIdKeywordContinue) { | ||
| 1402 | AstNode *node = ast_create_node(pc, NodeTypeContinue, token); | ||
| 1403 | *token_index += 1; | ||
| 1404 | return node; | ||
| 1405 | } | 1380 | } |
| 1406 | 1381 | ||
| 1407 | AstNode *grouped_expr_node = ast_parse_grouped_expr(pc, token_index, false); | 1382 | AstNode *grouped_expr_node = ast_parse_grouped_expr(pc, token_index, false); |
| ... | @@ -1414,9 +1389,14 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool | ... | @@ -1414,9 +1389,14 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool |
| 1414 | return block_expr_node; | 1389 | return block_expr_node; |
| 1415 | } | 1390 | } |
| 1416 | 1391 | ||
| 1417 | AstNode *compiler_fn_type = ast_parse_compiler_fn_type(pc, token_index, false); | 1392 | AstNode *array_type_node = ast_parse_array_type_expr(pc, token_index, false); |
| 1418 | if (compiler_fn_type) { | 1393 | if (array_type_node) { |
| 1419 | return compiler_fn_type; | 1394 | return array_type_node; |
| 1395 | } | ||
| 1396 | |||
| 1397 | AstNode *asm_expr = ast_parse_asm_expr(pc, token_index, false); | ||
| 1398 | if (asm_expr) { | ||
| 1399 | return asm_expr; | ||
| 1420 | } | 1400 | } |
| 1421 | 1401 | ||
| 1422 | if (!mandatory) | 1402 | if (!mandatory) |
| ... | @@ -1426,11 +1406,14 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool | ... | @@ -1426,11 +1406,14 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool |
| 1426 | } | 1406 | } |
| 1427 | 1407 | ||
| 1428 | /* | 1408 | /* |
| 1429 | SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression) | 1409 | SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression | ContainerInitExpression) |
| 1430 | FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen) | 1410 | FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen) |
| 1431 | ArrayAccessExpression : token(LBracket) Expression token(RBracket) | 1411 | ArrayAccessExpression : token(LBracket) Expression token(RBracket) |
| 1432 | SliceExpression : token(LBracket) Expression token(Ellipsis) option(Expression) token(RBracket) option(token(Const)) | 1412 | SliceExpression : token(LBracket) Expression token(Ellipsis) option(Expression) token(RBracket) option(token(Const)) |
| 1433 | FieldAccessExpression : token(Dot) token(Symbol) | 1413 | FieldAccessExpression : token(Dot) token(Symbol) |
| 1414 | ContainerInitExpression : token(LBrace) ContainerInitBody token(RBrace) | ||
| 1415 | ContainerInitBody : list(StructLiteralField, token(Comma)) | list(Expression, token(Comma)) | ||
| 1416 | StructLiteralField : token(Dot) token(Symbol) token(Eq) Expression | ||
| 1434 | */ | 1417 | */ |
| 1435 | static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, bool mandatory) { | 1418 | static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, bool mandatory) { |
| 1436 | AstNode *primary_expr = ast_parse_primary_expr(pc, token_index, mandatory); | 1419 | AstNode *primary_expr = ast_parse_primary_expr(pc, token_index, mandatory); |
| ... | @@ -1439,16 +1422,16 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, boo | ... | @@ -1439,16 +1422,16 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, boo |
| 1439 | } | 1422 | } |
| 1440 | 1423 | ||
| 1441 | while (true) { | 1424 | while (true) { |
| 1442 | Token *token = &pc->tokens->at(*token_index); | 1425 | Token *first_token = &pc->tokens->at(*token_index); |
| 1443 | if (token->id == TokenIdLParen) { | 1426 | if (first_token->id == TokenIdLParen) { |
| 1444 | *token_index += 1; | 1427 | *token_index += 1; |
| 1445 | 1428 | ||
| 1446 | AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, token); | 1429 | AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, first_token); |
| 1447 | node->data.fn_call_expr.fn_ref_expr = primary_expr; | 1430 | node->data.fn_call_expr.fn_ref_expr = primary_expr; |
| 1448 | ast_parse_fn_call_param_list(pc, token_index, &node->data.fn_call_expr.params); | 1431 | ast_parse_fn_call_param_list(pc, token_index, &node->data.fn_call_expr.params); |
| 1449 | 1432 | ||
| 1450 | primary_expr = node; | 1433 | primary_expr = node; |
| 1451 | } else if (token->id == TokenIdLBracket) { | 1434 | } else if (first_token->id == TokenIdLBracket) { |
| 1452 | *token_index += 1; | 1435 | *token_index += 1; |
| 1453 | 1436 | ||
| 1454 | AstNode *expr_node = ast_parse_expression(pc, token_index, true); | 1437 | AstNode *expr_node = ast_parse_expression(pc, token_index, true); |
| ... | @@ -1458,7 +1441,7 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, boo | ... | @@ -1458,7 +1441,7 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, boo |
| 1458 | if (ellipsis_or_r_bracket->id == TokenIdEllipsis) { | 1441 | if (ellipsis_or_r_bracket->id == TokenIdEllipsis) { |
| 1459 | *token_index += 1; | 1442 | *token_index += 1; |
| 1460 | 1443 | ||
| 1461 | AstNode *node = ast_create_node(pc, NodeTypeSliceExpr, token); | 1444 | AstNode *node = ast_create_node(pc, NodeTypeSliceExpr, first_token); |
| 1462 | node->data.slice_expr.array_ref_expr = primary_expr; | 1445 | node->data.slice_expr.array_ref_expr = primary_expr; |
| 1463 | node->data.slice_expr.start = expr_node; | 1446 | node->data.slice_expr.start = expr_node; |
| 1464 | node->data.slice_expr.end = ast_parse_expression(pc, token_index, false); | 1447 | node->data.slice_expr.end = ast_parse_expression(pc, token_index, false); |
| ... | @@ -1475,23 +1458,88 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, boo | ... | @@ -1475,23 +1458,88 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, boo |
| 1475 | } else if (ellipsis_or_r_bracket->id == TokenIdRBracket) { | 1458 | } else if (ellipsis_or_r_bracket->id == TokenIdRBracket) { |
| 1476 | *token_index += 1; | 1459 | *token_index += 1; |
| 1477 | 1460 | ||
| 1478 | AstNode *node = ast_create_node(pc, NodeTypeArrayAccessExpr, token); | 1461 | AstNode *node = ast_create_node(pc, NodeTypeArrayAccessExpr, first_token); |
| 1479 | node->data.array_access_expr.array_ref_expr = primary_expr; | 1462 | node->data.array_access_expr.array_ref_expr = primary_expr; |
| 1480 | node->data.array_access_expr.subscript = expr_node; | 1463 | node->data.array_access_expr.subscript = expr_node; |
| 1481 | 1464 | ||
| 1482 | primary_expr = node; | 1465 | primary_expr = node; |
| 1483 | } else { | 1466 | } else { |
| 1484 | ast_invalid_token_error(pc, token); | 1467 | ast_invalid_token_error(pc, first_token); |
| 1485 | } | 1468 | } |
| 1486 | } else if (token->id == TokenIdDot) { | 1469 | } else if (first_token->id == TokenIdDot) { |
| 1487 | *token_index += 1; | 1470 | *token_index += 1; |
| 1488 | 1471 | ||
| 1489 | Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol); | 1472 | Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol); |
| 1490 | 1473 | ||
| 1491 | AstNode *node = ast_create_node(pc, NodeTypeFieldAccessExpr, token); | 1474 | AstNode *node = ast_create_node(pc, NodeTypeFieldAccessExpr, first_token); |
| 1492 | node->data.field_access_expr.struct_expr = primary_expr; | 1475 | node->data.field_access_expr.struct_expr = primary_expr; |
| 1493 | ast_buf_from_token(pc, name_token, &node->data.field_access_expr.field_name); | 1476 | ast_buf_from_token(pc, name_token, &node->data.field_access_expr.field_name); |
| 1494 | 1477 | ||
| 1478 | primary_expr = node; | ||
| 1479 | } else if (first_token->id == TokenIdLBrace) { | ||
| 1480 | *token_index += 1; | ||
| 1481 | |||
| 1482 | AstNode *node = ast_create_node(pc, NodeTypeContainerInitExpr, first_token); | ||
| 1483 | node->data.container_init_expr.type = primary_expr; | ||
| 1484 | |||
| 1485 | Token *token = &pc->tokens->at(*token_index); | ||
| 1486 | if (token->id == TokenIdDot) { | ||
| 1487 | for (;;) { | ||
| 1488 | if (token->id == TokenIdDot) { | ||
| 1489 | ast_eat_token(pc, token_index, TokenIdDot); | ||
| 1490 | Token *field_name_tok = ast_eat_token(pc, token_index, TokenIdSymbol); | ||
| 1491 | ast_eat_token(pc, token_index, TokenIdEq); | ||
| 1492 | |||
| 1493 | AstNode *field_node = ast_create_node(pc, NodeTypeStructValueField, token); | ||
| 1494 | |||
| 1495 | ast_buf_from_token(pc, field_name_tok, &field_node->data.struct_val_field.name); | ||
| 1496 | field_node->data.struct_val_field.expr = ast_parse_expression(pc, token_index, true); | ||
| 1497 | |||
| 1498 | node->data.container_init_expr.entries.append(field_node); | ||
| 1499 | |||
| 1500 | Token *comma_tok = &pc->tokens->at(*token_index); | ||
| 1501 | if (comma_tok->id == TokenIdComma) { | ||
| 1502 | *token_index += 1; | ||
| 1503 | token = &pc->tokens->at(*token_index); | ||
| 1504 | continue; | ||
| 1505 | } else if (comma_tok->id != TokenIdRBrace) { | ||
| 1506 | ast_invalid_token_error(pc, comma_tok); | ||
| 1507 | } else { | ||
| 1508 | *token_index += 1; | ||
| 1509 | break; | ||
| 1510 | } | ||
| 1511 | } else if (token->id == TokenIdRBrace) { | ||
| 1512 | *token_index += 1; | ||
| 1513 | break; | ||
| 1514 | } else { | ||
| 1515 | ast_invalid_token_error(pc, token); | ||
| 1516 | } | ||
| 1517 | } | ||
| 1518 | |||
| 1519 | } else { | ||
| 1520 | for (;;) { | ||
| 1521 | if (token->id == TokenIdRBrace) { | ||
| 1522 | *token_index += 1; | ||
| 1523 | break; | ||
| 1524 | } else { | ||
| 1525 | AstNode *elem_node = ast_parse_expression(pc, token_index, true); | ||
| 1526 | node->data.container_init_expr.entries.append(elem_node); | ||
| 1527 | |||
| 1528 | Token *comma_tok = &pc->tokens->at(*token_index); | ||
| 1529 | if (comma_tok->id == TokenIdComma) { | ||
| 1530 | *token_index += 1; | ||
| 1531 | token = &pc->tokens->at(*token_index); | ||
| 1532 | continue; | ||
| 1533 | } else if (comma_tok->id != TokenIdRBrace) { | ||
| 1534 | ast_invalid_token_error(pc, comma_tok); | ||
| 1535 | } else { | ||
| 1536 | *token_index += 1; | ||
| 1537 | break; | ||
| 1538 | } | ||
| 1539 | } | ||
| 1540 | } | ||
| 1541 | } | ||
| 1542 | |||
| 1495 | primary_expr = node; | 1543 | primary_expr = node; |
| 1496 | } else { | 1544 | } else { |
| 1497 | return primary_expr; | 1545 | return primary_expr; |
| ... | @@ -1506,56 +1554,54 @@ static PrefixOp tok_to_prefix_op(Token *token) { | ... | @@ -1506,56 +1554,54 @@ static PrefixOp tok_to_prefix_op(Token *token) { |
| 1506 | case TokenIdTilde: return PrefixOpBinNot; | 1554 | case TokenIdTilde: return PrefixOpBinNot; |
| 1507 | case TokenIdAmpersand: return PrefixOpAddressOf; | 1555 | case TokenIdAmpersand: return PrefixOpAddressOf; |
| 1508 | case TokenIdStar: return PrefixOpDereference; | 1556 | case TokenIdStar: return PrefixOpDereference; |
| 1557 | case TokenIdMaybe: return PrefixOpMaybe; | ||
| 1558 | case TokenIdBoolAnd: return PrefixOpAddressOf; | ||
| 1509 | default: return PrefixOpInvalid; | 1559 | default: return PrefixOpInvalid; |
| 1510 | } | 1560 | } |
| 1511 | } | 1561 | } |
| 1512 | 1562 | ||
| 1513 | /* | 1563 | /* |
| 1564 | PrefixOpExpression : PrefixOp PrefixOpExpression | SuffixOpExpression | ||
| 1514 | PrefixOp : token(Not) | token(Dash) | token(Tilde) | token(Star) | (token(Ampersand) option(token(Const))) | 1565 | PrefixOp : token(Not) | token(Dash) | token(Tilde) | token(Star) | (token(Ampersand) option(token(Const))) |
| 1515 | */ | 1566 | */ |
| 1516 | static PrefixOp ast_parse_prefix_op(ParseContext *pc, int *token_index, bool mandatory) { | 1567 | static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, bool mandatory) { |
| 1517 | Token *token = &pc->tokens->at(*token_index); | 1568 | Token *token = &pc->tokens->at(*token_index); |
| 1518 | PrefixOp result = tok_to_prefix_op(token); | 1569 | PrefixOp prefix_op = tok_to_prefix_op(token); |
| 1519 | if (result == PrefixOpInvalid) { | 1570 | if (prefix_op == PrefixOpInvalid) { |
| 1520 | if (mandatory) { | 1571 | return ast_parse_suffix_op_expr(pc, token_index, mandatory); |
| 1521 | ast_invalid_token_error(pc, token); | ||
| 1522 | } else { | ||
| 1523 | return PrefixOpInvalid; | ||
| 1524 | } | ||
| 1525 | } | 1572 | } |
| 1526 | *token_index += 1; | 1573 | *token_index += 1; |
| 1527 | 1574 | ||
| 1528 | if (result == PrefixOpAddressOf) { | 1575 | AstNode *node = ast_create_node(pc, NodeTypePrefixOpExpr, token); |
| 1576 | AstNode *parent_node = node; | ||
| 1577 | if (token->id == TokenIdBoolAnd) { | ||
| 1578 | // pretend that we got 2 ampersand tokens | ||
| 1579 | |||
| 1580 | parent_node = ast_create_node(pc, NodeTypePrefixOpExpr, token); | ||
| 1581 | parent_node->data.prefix_op_expr.primary_expr = node; | ||
| 1582 | parent_node->data.prefix_op_expr.prefix_op = PrefixOpAddressOf; | ||
| 1583 | |||
| 1584 | node->column += 1; | ||
| 1585 | } | ||
| 1586 | |||
| 1587 | if (prefix_op == PrefixOpAddressOf) { | ||
| 1529 | Token *token = &pc->tokens->at(*token_index); | 1588 | Token *token = &pc->tokens->at(*token_index); |
| 1530 | if (token->id == TokenIdKeywordConst) { | 1589 | if (token->id == TokenIdKeywordConst) { |
| 1531 | *token_index += 1; | 1590 | *token_index += 1; |
| 1532 | result = PrefixOpConstAddressOf; | 1591 | prefix_op = PrefixOpConstAddressOf; |
| 1533 | } | 1592 | } |
| 1534 | } | 1593 | } |
| 1535 | 1594 | ||
| 1536 | return result; | ||
| 1537 | } | ||
| 1538 | |||
| 1539 | /* | ||
| 1540 | PrefixOpExpression : PrefixOp PrefixOpExpression | SuffixOpExpression | ||
| 1541 | */ | ||
| 1542 | static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, bool mandatory) { | ||
| 1543 | Token *token = &pc->tokens->at(*token_index); | ||
| 1544 | PrefixOp prefix_op = ast_parse_prefix_op(pc, token_index, false); | ||
| 1545 | if (prefix_op == PrefixOpInvalid) | ||
| 1546 | return ast_parse_suffix_op_expr(pc, token_index, mandatory); | ||
| 1547 | |||
| 1548 | AstNode *prefix_op_expr = ast_parse_prefix_op_expr(pc, token_index, true); | 1595 | AstNode *prefix_op_expr = ast_parse_prefix_op_expr(pc, token_index, true); |
| 1549 | AstNode *node = ast_create_node(pc, NodeTypePrefixOpExpr, token); | ||
| 1550 | node->data.prefix_op_expr.primary_expr = prefix_op_expr; | 1596 | node->data.prefix_op_expr.primary_expr = prefix_op_expr; |
| 1551 | node->data.prefix_op_expr.prefix_op = prefix_op; | 1597 | node->data.prefix_op_expr.prefix_op = prefix_op; |
| 1552 | 1598 | ||
| 1553 | return node; | 1599 | return parent_node; |
| 1554 | } | 1600 | } |
| 1555 | 1601 | ||
| 1556 | 1602 | ||
| 1557 | /* | 1603 | /* |
| 1558 | CastExpression : CastExpression token(as) Type | PrefixOpExpression | 1604 | CastExpression : CastExpression token(as) PrimaryExpression | PrefixOpExpression |
| 1559 | */ | 1605 | */ |
| 1560 | static AstNode *ast_parse_cast_expression(ParseContext *pc, int *token_index, bool mandatory) { | 1606 | static AstNode *ast_parse_cast_expression(ParseContext *pc, int *token_index, bool mandatory) { |
| 1561 | AstNode *operand_1 = ast_parse_prefix_op_expr(pc, token_index, mandatory); | 1607 | AstNode *operand_1 = ast_parse_prefix_op_expr(pc, token_index, mandatory); |
| ... | @@ -1571,7 +1617,7 @@ static AstNode *ast_parse_cast_expression(ParseContext *pc, int *token_index, bo | ... | @@ -1571,7 +1617,7 @@ static AstNode *ast_parse_cast_expression(ParseContext *pc, int *token_index, bo |
| 1571 | AstNode *node = ast_create_node(pc, NodeTypeCastExpr, as_kw); | 1617 | AstNode *node = ast_create_node(pc, NodeTypeCastExpr, as_kw); |
| 1572 | node->data.cast_expr.expr = operand_1; | 1618 | node->data.cast_expr.expr = operand_1; |
| 1573 | 1619 | ||
| 1574 | node->data.cast_expr.type = ast_parse_type(pc, token_index); | 1620 | node->data.cast_expr.type = ast_parse_primary_expr(pc, token_index, true); |
| 1575 | 1621 | ||
| 1576 | operand_1 = node; | 1622 | operand_1 = node; |
| 1577 | } | 1623 | } |
| ... | @@ -1899,7 +1945,7 @@ static AstNode *ast_parse_else(ParseContext *pc, int *token_index, bool mandator | ... | @@ -1899,7 +1945,7 @@ static AstNode *ast_parse_else(ParseContext *pc, int *token_index, bool mandator |
| 1899 | /* | 1945 | /* |
| 1900 | IfExpression : IfVarExpression | IfBoolExpression | 1946 | IfExpression : IfVarExpression | IfBoolExpression |
| 1901 | IfBoolExpression : token(If) token(LParen) Expression token(RParen) Expression option(Else) | 1947 | IfBoolExpression : token(If) token(LParen) Expression token(RParen) Expression option(Else) |
| 1902 | IfVarExpression : token(If) token(LParen) (token(Const) | token(Var)) token(Symbol) option(token(Colon) Type) Token(MaybeAssign) Expression token(RParen) Expression Option(Else) | 1948 | IfVarExpression : token(If) token(LParen) (token(Const) | token(Var)) token(Symbol) option(Expression) Token(MaybeAssign) Expression token(RParen) Expression Option(Else) |
| 1903 | */ | 1949 | */ |
| 1904 | static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool mandatory) { | 1950 | static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool mandatory) { |
| 1905 | Token *if_tok = &pc->tokens->at(*token_index); | 1951 | Token *if_tok = &pc->tokens->at(*token_index); |
| ... | @@ -1924,11 +1970,12 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool manda | ... | @@ -1924,11 +1970,12 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool manda |
| 1924 | ast_buf_from_token(pc, name_token, &node->data.if_var_expr.var_decl.symbol); | 1970 | ast_buf_from_token(pc, name_token, &node->data.if_var_expr.var_decl.symbol); |
| 1925 | 1971 | ||
| 1926 | Token *eq_or_colon = &pc->tokens->at(*token_index); | 1972 | Token *eq_or_colon = &pc->tokens->at(*token_index); |
| 1927 | *token_index += 1; | ||
| 1928 | if (eq_or_colon->id == TokenIdMaybeAssign) { | 1973 | if (eq_or_colon->id == TokenIdMaybeAssign) { |
| 1974 | *token_index += 1; | ||
| 1929 | node->data.if_var_expr.var_decl.expr = ast_parse_expression(pc, token_index, true); | 1975 | node->data.if_var_expr.var_decl.expr = ast_parse_expression(pc, token_index, true); |
| 1930 | } else if (eq_or_colon->id == TokenIdColon) { | 1976 | } else if (eq_or_colon->id == TokenIdColon) { |
| 1931 | node->data.if_var_expr.var_decl.type = ast_parse_type(pc, token_index); | 1977 | *token_index += 1; |
| 1978 | node->data.if_var_expr.var_decl.type = ast_parse_expression(pc, token_index, true); | ||
| 1932 | 1979 | ||
| 1933 | ast_eat_token(pc, token_index, TokenIdMaybeAssign); | 1980 | ast_eat_token(pc, token_index, TokenIdMaybeAssign); |
| 1934 | node->data.if_var_expr.var_decl.expr = ast_parse_expression(pc, token_index, true); | 1981 | node->data.if_var_expr.var_decl.expr = ast_parse_expression(pc, token_index, true); |
| ... | @@ -1967,7 +2014,7 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool m | ... | @@ -1967,7 +2014,7 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool m |
| 1967 | } | 2014 | } |
| 1968 | 2015 | ||
| 1969 | /* | 2016 | /* |
| 1970 | VariableDeclaration : option(FnVisibleMod) (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) Type option(token(Eq) Expression)) | 2017 | VariableDeclaration : option(FnVisibleMod) (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) UnwrapMaybeExpression option(token(Eq) Expression)) |
| 1971 | */ | 2018 | */ |
| 1972 | static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token_index, bool mandatory) { | 2019 | static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token_index, bool mandatory) { |
| 1973 | Token *first_token = &pc->tokens->at(*token_index); | 2020 | Token *first_token = &pc->tokens->at(*token_index); |
| ... | @@ -2008,8 +2055,7 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token | ... | @@ -2008,8 +2055,7 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token |
| 2008 | node->data.variable_declaration.expr = ast_parse_expression(pc, token_index, true); | 2055 | node->data.variable_declaration.expr = ast_parse_expression(pc, token_index, true); |
| 2009 | return node; | 2056 | return node; |
| 2010 | } else if (eq_or_colon->id == TokenIdColon) { | 2057 | } else if (eq_or_colon->id == TokenIdColon) { |
| 2011 | node->data.variable_declaration.type = ast_parse_type(pc, token_index); | 2058 | node->data.variable_declaration.type = ast_parse_unwrap_maybe_expr(pc, token_index, true); |
| 2012 | |||
| 2013 | Token *eq_token = &pc->tokens->at(*token_index); | 2059 | Token *eq_token = &pc->tokens->at(*token_index); |
| 2014 | if (eq_token->id == TokenIdEq) { | 2060 | if (eq_token->id == TokenIdEq) { |
| 2015 | *token_index += 1; | 2061 | *token_index += 1; |
| ... | @@ -2138,6 +2184,7 @@ static BinOpType ast_parse_ass_op(ParseContext *pc, int *token_index, bool manda | ... | @@ -2138,6 +2184,7 @@ static BinOpType ast_parse_ass_op(ParseContext *pc, int *token_index, bool manda |
| 2138 | /* | 2184 | /* |
| 2139 | UnwrapMaybeExpression : BoolOrExpression token(DoubleQuestion) BoolOrExpression | BoolOrExpression | 2185 | UnwrapMaybeExpression : BoolOrExpression token(DoubleQuestion) BoolOrExpression | BoolOrExpression |
| 2140 | */ | 2186 | */ |
| 2187 | // this is currently the first child expression of assignment | ||
| 2141 | static AstNode *ast_parse_unwrap_maybe_expr(ParseContext *pc, int *token_index, bool mandatory) { | 2188 | static AstNode *ast_parse_unwrap_maybe_expr(ParseContext *pc, int *token_index, bool mandatory) { |
| 2142 | AstNode *lhs = ast_parse_bool_or_expr(pc, token_index, mandatory); | 2189 | AstNode *lhs = ast_parse_bool_or_expr(pc, token_index, mandatory); |
| 2143 | if (!lhs) | 2190 | if (!lhs) |
| ... | @@ -2185,190 +2232,7 @@ static AstNode *ast_parse_ass_expr(ParseContext *pc, int *token_index, bool mand | ... | @@ -2185,190 +2232,7 @@ static AstNode *ast_parse_ass_expr(ParseContext *pc, int *token_index, bool mand |
| 2185 | } | 2232 | } |
| 2186 | 2233 | ||
| 2187 | /* | 2234 | /* |
| 2188 | AsmInputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) Expression token(RParen) | 2235 | NonBlockExpression : ReturnExpression | AssignmentExpression |
| 2189 | */ | ||
| 2190 | static void ast_parse_asm_input_item(ParseContext *pc, int *token_index, AstNode *node) { | ||
| 2191 | ast_eat_token(pc, token_index, TokenIdLBracket); | ||
| 2192 | Token *alias = ast_eat_token(pc, token_index, TokenIdSymbol); | ||
| 2193 | ast_eat_token(pc, token_index, TokenIdRBracket); | ||
| 2194 | |||
| 2195 | Token *constraint = ast_eat_token(pc, token_index, TokenIdStringLiteral); | ||
| 2196 | |||
| 2197 | ast_eat_token(pc, token_index, TokenIdLParen); | ||
| 2198 | AstNode *expr_node = ast_parse_expression(pc, token_index, true); | ||
| 2199 | ast_eat_token(pc, token_index, TokenIdRParen); | ||
| 2200 | |||
| 2201 | AsmInput *asm_input = allocate<AsmInput>(1); | ||
| 2202 | ast_buf_from_token(pc, alias, &asm_input->asm_symbolic_name); | ||
| 2203 | parse_string_literal(pc, constraint, &asm_input->constraint, nullptr, nullptr); | ||
| 2204 | asm_input->expr = expr_node; | ||
| 2205 | node->data.asm_expr.input_list.append(asm_input); | ||
| 2206 | } | ||
| 2207 | |||
| 2208 | /* | ||
| 2209 | AsmOutputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) (token(Symbol) | token(Arrow) Type) token(RParen) | ||
| 2210 | */ | ||
| 2211 | static void ast_parse_asm_output_item(ParseContext *pc, int *token_index, AstNode *node) { | ||
| 2212 | ast_eat_token(pc, token_index, TokenIdLBracket); | ||
| 2213 | Token *alias = ast_eat_token(pc, token_index, TokenIdSymbol); | ||
| 2214 | ast_eat_token(pc, token_index, TokenIdRBracket); | ||
| 2215 | |||
| 2216 | Token *constraint = ast_eat_token(pc, token_index, TokenIdStringLiteral); | ||
| 2217 | |||
| 2218 | AsmOutput *asm_output = allocate<AsmOutput>(1); | ||
| 2219 | |||
| 2220 | ast_eat_token(pc, token_index, TokenIdLParen); | ||
| 2221 | |||
| 2222 | Token *token = &pc->tokens->at(*token_index); | ||
| 2223 | *token_index += 1; | ||
| 2224 | if (token->id == TokenIdSymbol) { | ||
| 2225 | ast_buf_from_token(pc, token, &asm_output->variable_name); | ||
| 2226 | } else if (token->id == TokenIdArrow) { | ||
| 2227 | asm_output->return_type = ast_parse_type(pc, token_index); | ||
| 2228 | } else { | ||
| 2229 | ast_invalid_token_error(pc, token); | ||
| 2230 | } | ||
| 2231 | |||
| 2232 | ast_eat_token(pc, token_index, TokenIdRParen); | ||
| 2233 | |||
| 2234 | ast_buf_from_token(pc, alias, &asm_output->asm_symbolic_name); | ||
| 2235 | parse_string_literal(pc, constraint, &asm_output->constraint, nullptr, nullptr); | ||
| 2236 | node->data.asm_expr.output_list.append(asm_output); | ||
| 2237 | } | ||
| 2238 | |||
| 2239 | /* | ||
| 2240 | AsmClobbers: token(Colon) list(token(String), token(Comma)) | ||
| 2241 | */ | ||
| 2242 | static void ast_parse_asm_clobbers(ParseContext *pc, int *token_index, AstNode *node) { | ||
| 2243 | Token *colon_tok = &pc->tokens->at(*token_index); | ||
| 2244 | |||
| 2245 | if (colon_tok->id != TokenIdColon) | ||
| 2246 | return; | ||
| 2247 | |||
| 2248 | *token_index += 1; | ||
| 2249 | |||
| 2250 | for (;;) { | ||
| 2251 | Token *string_tok = &pc->tokens->at(*token_index); | ||
| 2252 | ast_expect_token(pc, string_tok, TokenIdStringLiteral); | ||
| 2253 | *token_index += 1; | ||
| 2254 | |||
| 2255 | Buf *clobber_buf = buf_alloc(); | ||
| 2256 | parse_string_literal(pc, string_tok, clobber_buf, nullptr, nullptr); | ||
| 2257 | node->data.asm_expr.clobber_list.append(clobber_buf); | ||
| 2258 | |||
| 2259 | Token *comma = &pc->tokens->at(*token_index); | ||
| 2260 | |||
| 2261 | if (comma->id == TokenIdComma) { | ||
| 2262 | *token_index += 1; | ||
| 2263 | continue; | ||
| 2264 | } else { | ||
| 2265 | break; | ||
| 2266 | } | ||
| 2267 | } | ||
| 2268 | } | ||
| 2269 | |||
| 2270 | /* | ||
| 2271 | AsmInput : token(Colon) list(AsmInputItem, token(Comma)) option(AsmClobbers) | ||
| 2272 | */ | ||
| 2273 | static void ast_parse_asm_input(ParseContext *pc, int *token_index, AstNode *node) { | ||
| 2274 | Token *colon_tok = &pc->tokens->at(*token_index); | ||
| 2275 | |||
| 2276 | if (colon_tok->id != TokenIdColon) | ||
| 2277 | return; | ||
| 2278 | |||
| 2279 | *token_index += 1; | ||
| 2280 | |||
| 2281 | for (;;) { | ||
| 2282 | ast_parse_asm_input_item(pc, token_index, node); | ||
| 2283 | |||
| 2284 | Token *comma = &pc->tokens->at(*token_index); | ||
| 2285 | |||
| 2286 | if (comma->id == TokenIdComma) { | ||
| 2287 | *token_index += 1; | ||
| 2288 | continue; | ||
| 2289 | } else { | ||
| 2290 | break; | ||
| 2291 | } | ||
| 2292 | } | ||
| 2293 | |||
| 2294 | ast_parse_asm_clobbers(pc, token_index, node); | ||
| 2295 | } | ||
| 2296 | |||
| 2297 | /* | ||
| 2298 | AsmOutput : token(Colon) list(AsmOutputItem, token(Comma)) option(AsmInput) | ||
| 2299 | */ | ||
| 2300 | static void ast_parse_asm_output(ParseContext *pc, int *token_index, AstNode *node) { | ||
| 2301 | Token *colon_tok = &pc->tokens->at(*token_index); | ||
| 2302 | |||
| 2303 | if (colon_tok->id != TokenIdColon) | ||
| 2304 | return; | ||
| 2305 | |||
| 2306 | *token_index += 1; | ||
| 2307 | |||
| 2308 | for (;;) { | ||
| 2309 | ast_parse_asm_output_item(pc, token_index, node); | ||
| 2310 | |||
| 2311 | Token *comma = &pc->tokens->at(*token_index); | ||
| 2312 | |||
| 2313 | if (comma->id == TokenIdComma) { | ||
| 2314 | *token_index += 1; | ||
| 2315 | continue; | ||
| 2316 | } else { | ||
| 2317 | break; | ||
| 2318 | } | ||
| 2319 | } | ||
| 2320 | |||
| 2321 | ast_parse_asm_input(pc, token_index, node); | ||
| 2322 | } | ||
| 2323 | |||
| 2324 | /* | ||
| 2325 | AsmExpression : token(Asm) option(token(Volatile)) token(LParen) token(String) option(AsmOutput) token(RParen) | ||
| 2326 | */ | ||
| 2327 | static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mandatory) { | ||
| 2328 | Token *asm_token = &pc->tokens->at(*token_index); | ||
| 2329 | |||
| 2330 | if (asm_token->id != TokenIdKeywordAsm) { | ||
| 2331 | if (mandatory) { | ||
| 2332 | ast_invalid_token_error(pc, asm_token); | ||
| 2333 | } else { | ||
| 2334 | return nullptr; | ||
| 2335 | } | ||
| 2336 | } | ||
| 2337 | |||
| 2338 | AstNode *node = ast_create_node(pc, NodeTypeAsmExpr, asm_token); | ||
| 2339 | |||
| 2340 | *token_index += 1; | ||
| 2341 | Token *lparen_tok = &pc->tokens->at(*token_index); | ||
| 2342 | |||
| 2343 | if (lparen_tok->id == TokenIdKeywordVolatile) { | ||
| 2344 | node->data.asm_expr.is_volatile = true; | ||
| 2345 | |||
| 2346 | *token_index += 1; | ||
| 2347 | lparen_tok = &pc->tokens->at(*token_index); | ||
| 2348 | } | ||
| 2349 | |||
| 2350 | ast_expect_token(pc, lparen_tok, TokenIdLParen); | ||
| 2351 | *token_index += 1; | ||
| 2352 | |||
| 2353 | Token *template_tok = &pc->tokens->at(*token_index); | ||
| 2354 | ast_expect_token(pc, template_tok, TokenIdStringLiteral); | ||
| 2355 | *token_index += 1; | ||
| 2356 | |||
| 2357 | parse_string_literal(pc, template_tok, &node->data.asm_expr.asm_template, nullptr, | ||
| 2358 | &node->data.asm_expr.offset_map); | ||
| 2359 | parse_asm_template(pc, node); | ||
| 2360 | |||
| 2361 | ast_parse_asm_output(pc, token_index, node); | ||
| 2362 | |||
| 2363 | Token *rparen_tok = &pc->tokens->at(*token_index); | ||
| 2364 | ast_expect_token(pc, rparen_tok, TokenIdRParen); | ||
| 2365 | *token_index += 1; | ||
| 2366 | |||
| 2367 | return node; | ||
| 2368 | } | ||
| 2369 | |||
| 2370 | /* | ||
| 2371 | NonBlockExpression : ReturnExpression | AssignmentExpression | AsmExpression | ||
| 2372 | */ | 2236 | */ |
| 2373 | static AstNode *ast_parse_non_block_expr(ParseContext *pc, int *token_index, bool mandatory) { | 2237 | static AstNode *ast_parse_non_block_expr(ParseContext *pc, int *token_index, bool mandatory) { |
| 2374 | Token *token = &pc->tokens->at(*token_index); | 2238 | Token *token = &pc->tokens->at(*token_index); |
| ... | @@ -2381,10 +2245,6 @@ static AstNode *ast_parse_non_block_expr(ParseContext *pc, int *token_index, boo | ... | @@ -2381,10 +2245,6 @@ static AstNode *ast_parse_non_block_expr(ParseContext *pc, int *token_index, boo |
| 2381 | if (ass_expr) | 2245 | if (ass_expr) |
| 2382 | return ass_expr; | 2246 | return ass_expr; |
| 2383 | 2247 | ||
| 2384 | AstNode *asm_expr = ast_parse_asm_expr(pc, token_index, false); | ||
| 2385 | if (asm_expr) | ||
| 2386 | return asm_expr; | ||
| 2387 | |||
| 2388 | if (mandatory) | 2248 | if (mandatory) |
| 2389 | ast_invalid_token_error(pc, token); | 2249 | ast_invalid_token_error(pc, token); |
| 2390 | 2250 | ||
| ... | @@ -2440,6 +2300,14 @@ static AstNode *ast_parse_label(ParseContext *pc, int *token_index, bool mandato | ... | @@ -2440,6 +2300,14 @@ static AstNode *ast_parse_label(ParseContext *pc, int *token_index, bool mandato |
| 2440 | return node; | 2300 | return node; |
| 2441 | } | 2301 | } |
| 2442 | 2302 | ||
| 2303 | static AstNode *ast_create_void_expr(ParseContext *pc, Token *token) { | ||
| 2304 | AstNode *node = ast_create_node(pc, NodeTypeContainerInitExpr, token); | ||
| 2305 | node->data.container_init_expr.type = ast_create_node(pc, NodeTypeSymbol, token); | ||
| 2306 | node->data.container_init_expr.kind = ContainerInitKindArray; | ||
| 2307 | buf_init_from_str(&node->data.container_init_expr.type->data.symbol_expr.symbol, "void"); | ||
| 2308 | return node; | ||
| 2309 | } | ||
| 2310 | |||
| 2443 | /* | 2311 | /* |
| 2444 | Block : token(LBrace) list(option(Statement), token(Semicolon)) token(RBrace) | 2312 | Block : token(LBrace) list(option(Statement), token(Semicolon)) token(RBrace) |
| 2445 | Statement : Label | VariableDeclaration token(Semicolon) | NonBlockExpression token(Semicolon) | BlockExpression | 2313 | Statement : Label | VariableDeclaration token(Semicolon) | NonBlockExpression token(Semicolon) | BlockExpression |
| ... | @@ -2478,7 +2346,7 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato | ... | @@ -2478,7 +2346,7 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato |
| 2478 | if (!statement_node) { | 2346 | if (!statement_node) { |
| 2479 | statement_node = ast_parse_non_block_expr(pc, token_index, false); | 2347 | statement_node = ast_parse_non_block_expr(pc, token_index, false); |
| 2480 | if (!statement_node) { | 2348 | if (!statement_node) { |
| 2481 | statement_node = ast_create_node(pc, NodeTypeVoid, last_token); | 2349 | statement_node = ast_create_void_expr(pc, last_token); |
| 2482 | } | 2350 | } |
| 2483 | } | 2351 | } |
| 2484 | } | 2352 | } |
| ... | @@ -2501,7 +2369,7 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato | ... | @@ -2501,7 +2369,7 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato |
| 2501 | } | 2369 | } |
| 2502 | 2370 | ||
| 2503 | /* | 2371 | /* |
| 2504 | FnProto : many(Directive) option(FnVisibleMod) token(Fn) token(Symbol) ParamDeclList option(token(Arrow) Type) | 2372 | FnProto : many(Directive) option(FnVisibleMod) token(Fn) token(Symbol) ParamDeclList option(Expression) |
| 2505 | */ | 2373 | */ |
| 2506 | static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mandatory) { | 2374 | static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mandatory) { |
| 2507 | Token *first_token = &pc->tokens->at(*token_index); | 2375 | Token *first_token = &pc->tokens->at(*token_index); |
| ... | @@ -2552,19 +2420,17 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mand | ... | @@ -2552,19 +2420,17 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mand |
| 2552 | 2420 | ||
| 2553 | ast_parse_param_decl_list(pc, token_index, &node->data.fn_proto.params, &node->data.fn_proto.is_var_args); | 2421 | ast_parse_param_decl_list(pc, token_index, &node->data.fn_proto.params, &node->data.fn_proto.is_var_args); |
| 2554 | 2422 | ||
| 2555 | Token *arrow = &pc->tokens->at(*token_index); | 2423 | Token *next_token = &pc->tokens->at(*token_index); |
| 2556 | if (arrow->id == TokenIdArrow) { | 2424 | node->data.fn_proto.return_type = ast_parse_expression(pc, token_index, false); |
| 2557 | *token_index += 1; | 2425 | if (!node->data.fn_proto.return_type) { |
| 2558 | node->data.fn_proto.return_type = ast_parse_type(pc, token_index); | 2426 | node->data.fn_proto.return_type = ast_create_void_type_node(pc, next_token); |
| 2559 | } else { | ||
| 2560 | node->data.fn_proto.return_type = ast_create_void_type_node(pc, arrow); | ||
| 2561 | } | 2427 | } |
| 2562 | 2428 | ||
| 2563 | return node; | 2429 | return node; |
| 2564 | } | 2430 | } |
| 2565 | 2431 | ||
| 2566 | /* | 2432 | /* |
| 2567 | FnDef : FnProto Block | 2433 | FnDef : FnProto token(FatArrow) Block |
| 2568 | */ | 2434 | */ |
| 2569 | static AstNode *ast_parse_fn_def(ParseContext *pc, int *token_index, bool mandatory) { | 2435 | static AstNode *ast_parse_fn_def(ParseContext *pc, int *token_index, bool mandatory) { |
| 2570 | AstNode *fn_proto = ast_parse_fn_proto(pc, token_index, mandatory); | 2436 | AstNode *fn_proto = ast_parse_fn_proto(pc, token_index, mandatory); |
| ... | @@ -2573,6 +2439,7 @@ static AstNode *ast_parse_fn_def(ParseContext *pc, int *token_index, bool mandat | ... | @@ -2573,6 +2439,7 @@ static AstNode *ast_parse_fn_def(ParseContext *pc, int *token_index, bool mandat |
| 2573 | AstNode *node = ast_create_node_with_node(pc, NodeTypeFnDef, fn_proto); | 2439 | AstNode *node = ast_create_node_with_node(pc, NodeTypeFnDef, fn_proto); |
| 2574 | 2440 | ||
| 2575 | node->data.fn_def.fn_proto = fn_proto; | 2441 | node->data.fn_def.fn_proto = fn_proto; |
| 2442 | ast_eat_token(pc, token_index, TokenIdFatArrow); | ||
| 2576 | node->data.fn_def.body = ast_parse_block(pc, token_index, true); | 2443 | node->data.fn_def.body = ast_parse_block(pc, token_index, true); |
| 2577 | 2444 | ||
| 2578 | return node; | 2445 | return node; |
| ... | @@ -2709,7 +2576,7 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index) { | ... | @@ -2709,7 +2576,7 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index) { |
| 2709 | /* | 2576 | /* |
| 2710 | ContainerDecl : many(Directive) option(FnVisibleMod) (token(Struct) | token(Enum)) token(Symbol) token(LBrace) many(StructMember) token(RBrace) | 2577 | ContainerDecl : many(Directive) option(FnVisibleMod) (token(Struct) | token(Enum)) token(Symbol) token(LBrace) many(StructMember) token(RBrace) |
| 2711 | StructMember: StructField | FnDecl | 2578 | StructMember: StructField | FnDecl |
| 2712 | StructField : token(Symbol) token(Colon) Type token(Comma) | 2579 | StructField : token(Symbol) option(token(Colon) Expression) token(Comma)) |
| 2713 | */ | 2580 | */ |
| 2714 | static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) { | 2581 | static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) { |
| 2715 | Token *first_token = &pc->tokens->at(*token_index); | 2582 | Token *first_token = &pc->tokens->at(*token_index); |
| ... | @@ -2792,16 +2659,16 @@ static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) { | ... | @@ -2792,16 +2659,16 @@ static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) { |
| 2792 | 2659 | ||
| 2793 | ast_buf_from_token(pc, token, &field_node->data.struct_field.name); | 2660 | ast_buf_from_token(pc, token, &field_node->data.struct_field.name); |
| 2794 | 2661 | ||
| 2795 | Token *colon_tok = &pc->tokens->at(*token_index); | 2662 | Token *expr_or_comma = &pc->tokens->at(*token_index); |
| 2796 | if (colon_tok->id == TokenIdColon) { | 2663 | if (expr_or_comma->id == TokenIdComma) { |
| 2664 | field_node->data.struct_field.type = ast_create_void_type_node(pc, expr_or_comma); | ||
| 2797 | *token_index += 1; | 2665 | *token_index += 1; |
| 2798 | field_node->data.struct_field.type = ast_parse_type(pc, token_index); | ||
| 2799 | } else { | 2666 | } else { |
| 2800 | field_node->data.struct_field.type = ast_create_void_type_node(pc, colon_tok); | 2667 | ast_eat_token(pc, token_index, TokenIdColon); |
| 2668 | field_node->data.struct_field.type = ast_parse_expression(pc, token_index, true); | ||
| 2669 | ast_eat_token(pc, token_index, TokenIdComma); | ||
| 2801 | } | 2670 | } |
| 2802 | 2671 | ||
| 2803 | ast_eat_token(pc, token_index, TokenIdComma); | ||
| 2804 | |||
| 2805 | node->data.struct_decl.fields.append(field_node); | 2672 | node->data.struct_decl.fields.append(field_node); |
| 2806 | } else { | 2673 | } else { |
| 2807 | ast_invalid_token_error(pc, token); | 2674 | ast_invalid_token_error(pc, token); |
src/tokenizer.cpp+6-6| ... | @@ -207,8 +207,6 @@ static void end_token(Tokenize *t) { | ... | @@ -207,8 +207,6 @@ static void end_token(Tokenize *t) { |
| 207 | t->cur_tok->id = TokenIdKeywordConst; | 207 | t->cur_tok->id = TokenIdKeywordConst; |
| 208 | } else if (mem_eql_str(token_mem, token_len, "extern")) { | 208 | } else if (mem_eql_str(token_mem, token_len, "extern")) { |
| 209 | t->cur_tok->id = TokenIdKeywordExtern; | 209 | t->cur_tok->id = TokenIdKeywordExtern; |
| 210 | } else if (mem_eql_str(token_mem, token_len, "unreachable")) { | ||
| 211 | t->cur_tok->id = TokenIdKeywordUnreachable; | ||
| 212 | } else if (mem_eql_str(token_mem, token_len, "pub")) { | 210 | } else if (mem_eql_str(token_mem, token_len, "pub")) { |
| 213 | t->cur_tok->id = TokenIdKeywordPub; | 211 | t->cur_tok->id = TokenIdKeywordPub; |
| 214 | } else if (mem_eql_str(token_mem, token_len, "export")) { | 212 | } else if (mem_eql_str(token_mem, token_len, "export")) { |
| ... | @@ -217,8 +215,6 @@ static void end_token(Tokenize *t) { | ... | @@ -217,8 +215,6 @@ static void end_token(Tokenize *t) { |
| 217 | t->cur_tok->id = TokenIdKeywordAs; | 215 | t->cur_tok->id = TokenIdKeywordAs; |
| 218 | } else if (mem_eql_str(token_mem, token_len, "use")) { | 216 | } else if (mem_eql_str(token_mem, token_len, "use")) { |
| 219 | t->cur_tok->id = TokenIdKeywordUse; | 217 | t->cur_tok->id = TokenIdKeywordUse; |
| 220 | } else if (mem_eql_str(token_mem, token_len, "void")) { | ||
| 221 | t->cur_tok->id = TokenIdKeywordVoid; | ||
| 222 | } else if (mem_eql_str(token_mem, token_len, "true")) { | 218 | } else if (mem_eql_str(token_mem, token_len, "true")) { |
| 223 | t->cur_tok->id = TokenIdKeywordTrue; | 219 | t->cur_tok->id = TokenIdKeywordTrue; |
| 224 | } else if (mem_eql_str(token_mem, token_len, "false")) { | 220 | } else if (mem_eql_str(token_mem, token_len, "false")) { |
| ... | @@ -553,6 +549,11 @@ void tokenize(Buf *buf, Tokenization *out) { | ... | @@ -553,6 +549,11 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 553 | end_token(&t); | 549 | end_token(&t); |
| 554 | t.state = TokenizeStateStart; | 550 | t.state = TokenizeStateStart; |
| 555 | break; | 551 | break; |
| 552 | case '>': | ||
| 553 | t.cur_tok->id = TokenIdFatArrow; | ||
| 554 | end_token(&t); | ||
| 555 | t.state = TokenizeStateStart; | ||
| 556 | break; | ||
| 556 | default: | 557 | default: |
| 557 | t.pos -= 1; | 558 | t.pos -= 1; |
| 558 | end_token(&t); | 559 | end_token(&t); |
| ... | @@ -1009,12 +1010,10 @@ static const char * token_name(Token *token) { | ... | @@ -1009,12 +1010,10 @@ static const char * token_name(Token *token) { |
| 1009 | case TokenIdKeywordVar: return "Var"; | 1010 | case TokenIdKeywordVar: return "Var"; |
| 1010 | case TokenIdKeywordReturn: return "Return"; | 1011 | case TokenIdKeywordReturn: return "Return"; |
| 1011 | case TokenIdKeywordExtern: return "Extern"; | 1012 | case TokenIdKeywordExtern: return "Extern"; |
| 1012 | case TokenIdKeywordUnreachable: return "Unreachable"; | ||
| 1013 | case TokenIdKeywordPub: return "Pub"; | 1013 | case TokenIdKeywordPub: return "Pub"; |
| 1014 | case TokenIdKeywordExport: return "Export"; | 1014 | case TokenIdKeywordExport: return "Export"; |
| 1015 | case TokenIdKeywordAs: return "As"; | 1015 | case TokenIdKeywordAs: return "As"; |
| 1016 | case TokenIdKeywordUse: return "Use"; | 1016 | case TokenIdKeywordUse: return "Use"; |
| 1017 | case TokenIdKeywordVoid: return "Void"; | ||
| 1018 | case TokenIdKeywordTrue: return "True"; | 1017 | case TokenIdKeywordTrue: return "True"; |
| 1019 | case TokenIdKeywordFalse: return "False"; | 1018 | case TokenIdKeywordFalse: return "False"; |
| 1020 | case TokenIdKeywordIf: return "If"; | 1019 | case TokenIdKeywordIf: return "If"; |
| ... | @@ -1044,6 +1043,7 @@ static const char * token_name(Token *token) { | ... | @@ -1044,6 +1043,7 @@ static const char * token_name(Token *token) { |
| 1044 | case TokenIdPlus: return "Plus"; | 1043 | case TokenIdPlus: return "Plus"; |
| 1045 | case TokenIdColon: return "Colon"; | 1044 | case TokenIdColon: return "Colon"; |
| 1046 | case TokenIdArrow: return "Arrow"; | 1045 | case TokenIdArrow: return "Arrow"; |
| 1046 | case TokenIdFatArrow: return "FatArrow"; | ||
| 1047 | case TokenIdDash: return "Dash"; | 1047 | case TokenIdDash: return "Dash"; |
| 1048 | case TokenIdNumberSign: return "NumberSign"; | 1048 | case TokenIdNumberSign: return "NumberSign"; |
| 1049 | case TokenIdBinOr: return "BinOr"; | 1049 | case TokenIdBinOr: return "BinOr"; |
src/tokenizer.hpp+1-2| ... | @@ -18,12 +18,10 @@ enum TokenId { | ... | @@ -18,12 +18,10 @@ enum TokenId { |
| 18 | TokenIdKeywordVar, | 18 | TokenIdKeywordVar, |
| 19 | TokenIdKeywordConst, | 19 | TokenIdKeywordConst, |
| 20 | TokenIdKeywordExtern, | 20 | TokenIdKeywordExtern, |
| 21 | TokenIdKeywordUnreachable, | ||
| 22 | TokenIdKeywordPub, | 21 | TokenIdKeywordPub, |
| 23 | TokenIdKeywordExport, | 22 | TokenIdKeywordExport, |
| 24 | TokenIdKeywordAs, | 23 | TokenIdKeywordAs, |
| 25 | TokenIdKeywordUse, | 24 | TokenIdKeywordUse, |
| 26 | TokenIdKeywordVoid, | ||
| 27 | TokenIdKeywordTrue, | 25 | TokenIdKeywordTrue, |
| 28 | TokenIdKeywordFalse, | 26 | TokenIdKeywordFalse, |
| 29 | TokenIdKeywordIf, | 27 | TokenIdKeywordIf, |
| ... | @@ -53,6 +51,7 @@ enum TokenId { | ... | @@ -53,6 +51,7 @@ enum TokenId { |
| 53 | TokenIdPlus, | 51 | TokenIdPlus, |
| 54 | TokenIdColon, | 52 | TokenIdColon, |
| 55 | TokenIdArrow, | 53 | TokenIdArrow, |
| 54 | TokenIdFatArrow, | ||
| 56 | TokenIdDash, | 55 | TokenIdDash, |
| 57 | TokenIdNumberSign, | 56 | TokenIdNumberSign, |
| 58 | TokenIdBoolOr, | 57 | TokenIdBoolOr, |
std/bootstrap.zig+30-5| ... | @@ -3,10 +3,35 @@ use "syscall.zig"; | ... | @@ -3,10 +3,35 @@ use "syscall.zig"; |
| 3 | // The compiler treats this file special by implicitly importing the function `main` | 3 | // The compiler treats this file special by implicitly importing the function `main` |
| 4 | // from the root source file. | 4 | // from the root source file. |
| 5 | 5 | ||
| 6 | var env: &&u8; | ||
| 7 | |||
| 6 | #attribute("naked") | 8 | #attribute("naked") |
| 7 | export fn _start() -> unreachable { | 9 | export fn _start() unreachable => { |
| 8 | const argc = asm("mov (%%rsp), %[argc]" : [argc] "=r" (-> isize)); | 10 | const argc = asm("mov (%%rsp), %[argc]": [argc] "=r" (-> isize)); |
| 9 | const argv = asm("lea 0x8(%%rsp), %[argv]" : [argv] "=r" (-> &&u8)); | 11 | const argv = asm("lea 0x8(%%rsp), %[argv]": [argv] "=r" (-> &&u8)); |
| 10 | const env = asm("lea 0x10(%%rsp,%%rdi,8), %[env]" : [env] "=r" (-> &&u8)); | 12 | env = asm("lea 0x10(%%rsp,%%rdi,8), %[env]": [env] "=r" (-> &&u8)); |
| 11 | exit(main(argc, argv, env)) | 13 | |
| 14 | exit(main(argc, argv, env)); | ||
| 15 | |||
| 16 | /* | ||
| 17 | var args = @alloca_array([]u8, argc); | ||
| 18 | var i : @typeof(argc) = 0; | ||
| 19 | // TODO for in loop over the array | ||
| 20 | while (i < argc) { | ||
| 21 | const ptr = argv[i]; | ||
| 22 | args[i] = ptr[0...strlen(ptr)]; | ||
| 23 | i += 1; | ||
| 24 | } | ||
| 25 | exit(main(args)) | ||
| 26 | */ | ||
| 27 | } | ||
| 28 | |||
| 29 | /* | ||
| 30 | fn strlen(ptr: &u8) isize => { | ||
| 31 | var count: isize = 0; | ||
| 32 | while (ptr[count]) { | ||
| 33 | count += 1; | ||
| 34 | } | ||
| 35 | return count; | ||
| 12 | } | 36 | } |
| 37 | */ |
std/builtin.zig+4-4| ... | @@ -1,8 +1,8 @@ | ... | @@ -1,8 +1,8 @@ |
| 1 | // These functions are provided when not linking against libc because LLVM | 1 | // These functions are provided when not linking against libc because LLVM |
| 2 | // sometimes generates code that calls them. | 2 | // sometimes generates code that calls them. |
| 3 | 3 | ||
| 4 | export fn memset(dest: &u8, c: u8, n: usize) -> &u8 { | 4 | export fn memset(dest: &u8, c: u8, n: usize) &u8 => { |
| 5 | var index : #typeof(n) = 0; | 5 | var index : @typeof(n) = 0; |
| 6 | while (index != n) { | 6 | while (index != n) { |
| 7 | dest[index] = c; | 7 | dest[index] = c; |
| 8 | index += 1; | 8 | index += 1; |
| ... | @@ -10,8 +10,8 @@ export fn memset(dest: &u8, c: u8, n: usize) -> &u8 { | ... | @@ -10,8 +10,8 @@ export fn memset(dest: &u8, c: u8, n: usize) -> &u8 { |
| 10 | return dest; | 10 | return dest; |
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | export fn memcpy(dest: &noalias u8, src: &const noalias u8, n: usize) -> &u8 { | 13 | export fn memcpy(noalias dest: &u8, noalias src: &const u8, n: usize) &u8 => { |
| 14 | var index : #typeof(n) = 0; | 14 | var index : @typeof(n) = 0; |
| 15 | while (index != n) { | 15 | while (index != n) { |
| 16 | dest[index] = src[index]; | 16 | dest[index] = src[index]; |
| 17 | index += 1; | 17 | index += 1; |
std/rand.zig+18-18| ... | @@ -4,13 +4,13 @@ const ARRAY_SIZE : u16 = 624; | ... | @@ -4,13 +4,13 @@ const ARRAY_SIZE : u16 = 624; |
| 4 | /// Use `rand_init` to initialize this state. | 4 | /// Use `rand_init` to initialize this state. |
| 5 | pub struct Rand { | 5 | pub struct Rand { |
| 6 | array: [ARRAY_SIZE]u32, | 6 | array: [ARRAY_SIZE]u32, |
| 7 | index: #typeof(ARRAY_SIZE), | 7 | index: @typeof(ARRAY_SIZE), |
| 8 | 8 | ||
| 9 | /// Initialize random state with the given seed. | 9 | /// Initialize random state with the given seed. |
| 10 | pub fn init(r: &Rand, seed: u32) { | 10 | pub fn init(r: &Rand, seed: u32) => { |
| 11 | r.index = 0; | 11 | r.index = 0; |
| 12 | r.array[0] = seed; | 12 | r.array[0] = seed; |
| 13 | var i : #typeof(ARRAY_SIZE) = 1; | 13 | var i : @typeof(ARRAY_SIZE) = 1; |
| 14 | while (i < ARRAY_SIZE) { | 14 | while (i < ARRAY_SIZE) { |
| 15 | const prev_value : u64 = r.array[i - 1]; | 15 | const prev_value : u64 = r.array[i - 1]; |
| 16 | r.array[i] = ((prev_value ^ (prev_value << 30)) * 0x6c078965 + i) as u32; | 16 | r.array[i] = ((prev_value ^ (prev_value << 30)) * 0x6c078965 + i) as u32; |
| ... | @@ -20,7 +20,7 @@ pub struct Rand { | ... | @@ -20,7 +20,7 @@ pub struct Rand { |
| 20 | 20 | ||
| 21 | 21 | ||
| 22 | /// Get 32 bits of randomness. | 22 | /// Get 32 bits of randomness. |
| 23 | pub fn get_u32(r: &Rand) -> u32 { | 23 | pub fn get_u32(r: &Rand) u32 => { |
| 24 | if (r.index == 0) { | 24 | if (r.index == 0) { |
| 25 | r.generate_numbers(); | 25 | r.generate_numbers(); |
| 26 | } | 26 | } |
| ... | @@ -37,13 +37,13 @@ pub struct Rand { | ... | @@ -37,13 +37,13 @@ pub struct Rand { |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | /// Fill `buf` with randomness. | 39 | /// Fill `buf` with randomness. |
| 40 | pub fn get_bytes(r: &Rand, buf: []u8) { | 40 | pub fn get_bytes(r: &Rand, buf: []u8) => { |
| 41 | var bytes_left = r.get_bytes_aligned(buf); | 41 | var bytes_left = r.get_bytes_aligned(buf); |
| 42 | if (bytes_left > 0) { | 42 | if (bytes_left > 0) { |
| 43 | var rand_val_array : [#sizeof(u32)]u8; | 43 | var rand_val_array : [@sizeof(u32)]u8; |
| 44 | *(rand_val_array.ptr as &u32) = r.get_u32(); | 44 | *(rand_val_array.ptr as (&u32)) = r.get_u32(); |
| 45 | while (bytes_left > 0) { | 45 | while (bytes_left > 0) { |
| 46 | buf[buf.len - bytes_left] = rand_val_array[#sizeof(u32) - bytes_left]; | 46 | buf[buf.len - bytes_left] = rand_val_array[@sizeof(u32) - bytes_left]; |
| 47 | bytes_left -= 1; | 47 | bytes_left -= 1; |
| 48 | } | 48 | } |
| 49 | } | 49 | } |
| ... | @@ -51,23 +51,23 @@ pub struct Rand { | ... | @@ -51,23 +51,23 @@ pub struct Rand { |
| 51 | 51 | ||
| 52 | /// Get a random unsigned integer with even distribution between `start` | 52 | /// Get a random unsigned integer with even distribution between `start` |
| 53 | /// inclusive and `end` exclusive. | 53 | /// inclusive and `end` exclusive. |
| 54 | pub fn range_u64(r: &Rand, start: u64, end: u64) -> u64 { | 54 | pub fn range_u64(r: &Rand, start: u64, end: u64) u64 => { |
| 55 | const range = end - start; | 55 | const range = end - start; |
| 56 | const leftover = #max_value(u64) % range; | 56 | const leftover = @max_value(u64) % range; |
| 57 | const upper_bound = #max_value(u64) - leftover; | 57 | const upper_bound = @max_value(u64) - leftover; |
| 58 | var rand_val_array : [#sizeof(u64)]u8; | 58 | var rand_val_array : [@sizeof(u64)]u8; |
| 59 | 59 | ||
| 60 | while (true) { | 60 | while (true) { |
| 61 | r.get_bytes_aligned(rand_val_array); | 61 | r.get_bytes_aligned(rand_val_array); |
| 62 | const rand_val = *(rand_val_array.ptr as &u64); | 62 | const rand_val = *(rand_val_array.ptr as (&u64)); |
| 63 | if (rand_val < upper_bound) { | 63 | if (rand_val < upper_bound) { |
| 64 | return start + (rand_val % range); | 64 | return start + (rand_val % range); |
| 65 | } | 65 | } |
| 66 | } | 66 | } |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | fn generate_numbers(r: &Rand) { | 69 | fn generate_numbers(r: &Rand) => { |
| 70 | var i : #typeof(ARRAY_SIZE) = 0; | 70 | var i : @typeof(ARRAY_SIZE) = 0; |
| 71 | while (i < ARRAY_SIZE) { | 71 | while (i < ARRAY_SIZE) { |
| 72 | const y : u32 = (r.array[i] & 0x80000000) + (r.array[(i + 1) % ARRAY_SIZE] & 0x7fffffff); | 72 | const y : u32 = (r.array[i] & 0x80000000) + (r.array[(i + 1) % ARRAY_SIZE] & 0x7fffffff); |
| 73 | const untempered : u32 = r.array[(i + 397) % ARRAY_SIZE] ^ (y >> 1); | 73 | const untempered : u32 = r.array[(i + 397) % ARRAY_SIZE] ^ (y >> 1); |
| ... | @@ -82,11 +82,11 @@ pub struct Rand { | ... | @@ -82,11 +82,11 @@ pub struct Rand { |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | // does not populate the remaining (buf.len % 4) bytes | 84 | // does not populate the remaining (buf.len % 4) bytes |
| 85 | fn get_bytes_aligned(r: &Rand, buf: []u8) -> usize { | 85 | fn get_bytes_aligned(r: &Rand, buf: []u8) usize => { |
| 86 | var bytes_left = buf.len; | 86 | var bytes_left = buf.len; |
| 87 | while (bytes_left >= 4) { | 87 | while (bytes_left >= 4) { |
| 88 | *(&buf[buf.len - bytes_left] as &u32) = r.get_u32(); | 88 | *(&buf[buf.len - bytes_left] as (&u32)) = r.get_u32(); |
| 89 | bytes_left -= #sizeof(u32); | 89 | bytes_left -= @sizeof(u32); |
| 90 | } | 90 | } |
| 91 | return bytes_left; | 91 | return bytes_left; |
| 92 | } | 92 | } |
std/std.zig+12-12| ... | @@ -5,25 +5,25 @@ pub const stdout_fileno : isize = 1; | ... | @@ -5,25 +5,25 @@ pub const stdout_fileno : isize = 1; |
| 5 | pub const stderr_fileno : isize = 2; | 5 | pub const stderr_fileno : isize = 2; |
| 6 | 6 | ||
| 7 | // TODO error handling | 7 | // TODO error handling |
| 8 | pub fn os_get_random_bytes(buf: &u8, count: usize) -> isize { | 8 | pub fn os_get_random_bytes(buf: &u8, count: usize) isize => { |
| 9 | getrandom(buf, count, 0) | 9 | getrandom(buf, count, 0) |
| 10 | } | 10 | } |
| 11 | 11 | ||
| 12 | // TODO error handling | 12 | // TODO error handling |
| 13 | // TODO handle buffering and flushing (mutex protected) | 13 | // TODO handle buffering and flushing (mutex protected) |
| 14 | pub fn print_str(str: []const u8) -> isize { | 14 | pub fn print_str(str: []const u8) isize => { |
| 15 | fprint_str(stdout_fileno, str) | 15 | fprint_str(stdout_fileno, str) |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | // TODO error handling | 18 | // TODO error handling |
| 19 | // TODO handle buffering and flushing (mutex protected) | 19 | // TODO handle buffering and flushing (mutex protected) |
| 20 | pub fn fprint_str(fd: isize, str: []const u8) -> isize { | 20 | pub fn fprint_str(fd: isize, str: []const u8) isize => { |
| 21 | write(fd, str.ptr, str.len) | 21 | write(fd, str.ptr, str.len) |
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | // TODO handle buffering and flushing (mutex protected) | 24 | // TODO handle buffering and flushing (mutex protected) |
| 25 | // TODO error handling | 25 | // TODO error handling |
| 26 | pub fn print_u64(x: u64) -> isize { | 26 | pub fn print_u64(x: u64) isize => { |
| 27 | var buf: [max_u64_base10_digits]u8; | 27 | var buf: [max_u64_base10_digits]u8; |
| 28 | const len = buf_print_u64(buf, x); | 28 | const len = buf_print_u64(buf, x); |
| 29 | return write(stdout_fileno, buf.ptr, len); | 29 | return write(stdout_fileno, buf.ptr, len); |
| ... | @@ -31,14 +31,14 @@ pub fn print_u64(x: u64) -> isize { | ... | @@ -31,14 +31,14 @@ pub fn print_u64(x: u64) -> isize { |
| 31 | 31 | ||
| 32 | // TODO handle buffering and flushing (mutex protected) | 32 | // TODO handle buffering and flushing (mutex protected) |
| 33 | // TODO error handling | 33 | // TODO error handling |
| 34 | pub fn print_i64(x: i64) -> isize { | 34 | pub fn print_i64(x: i64) isize => { |
| 35 | var buf: [max_u64_base10_digits]u8; | 35 | var buf: [max_u64_base10_digits]u8; |
| 36 | const len = buf_print_i64(buf, x); | 36 | const len = buf_print_i64(buf, x); |
| 37 | return write(stdout_fileno, buf.ptr, len); | 37 | return write(stdout_fileno, buf.ptr, len); |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | // TODO error handling | 40 | // TODO error handling |
| 41 | pub fn readline(buf: []u8, out_len: &usize) -> bool { | 41 | pub fn readline(buf: []u8, out_len: &usize) bool => { |
| 42 | const amt_read = read(stdin_fileno, buf.ptr, buf.len); | 42 | const amt_read = read(stdin_fileno, buf.ptr, buf.len); |
| 43 | if (amt_read < 0) { | 43 | if (amt_read < 0) { |
| 44 | return true; | 44 | return true; |
| ... | @@ -48,10 +48,10 @@ pub fn readline(buf: []u8, out_len: &usize) -> bool { | ... | @@ -48,10 +48,10 @@ pub fn readline(buf: []u8, out_len: &usize) -> bool { |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | // TODO return ?u64 when we support returning struct byval | 50 | // TODO return ?u64 when we support returning struct byval |
| 51 | pub fn parse_u64(buf: []u8, radix: u8, result: &u64) -> bool { | 51 | pub fn parse_u64(buf: []u8, radix: u8, result: &u64) bool => { |
| 52 | var x : u64 = 0; | 52 | var x : u64 = 0; |
| 53 | 53 | ||
| 54 | var i : #typeof(buf.len) = 0; | 54 | var i : @typeof(buf.len) = 0; |
| 55 | while (i < buf.len) { | 55 | while (i < buf.len) { |
| 56 | const c = buf[i]; | 56 | const c = buf[i]; |
| 57 | const digit = char_to_digit(c); | 57 | const digit = char_to_digit(c); |
| ... | @@ -77,7 +77,7 @@ pub fn parse_u64(buf: []u8, radix: u8, result: &u64) -> bool { | ... | @@ -77,7 +77,7 @@ pub fn parse_u64(buf: []u8, radix: u8, result: &u64) -> bool { |
| 77 | return false; | 77 | return false; |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | fn char_to_digit(c: u8) -> u8 { | 80 | fn char_to_digit(c: u8) u8 => { |
| 81 | if ('0' <= c && c <= '9') { | 81 | if ('0' <= c && c <= '9') { |
| 82 | c - '0' | 82 | c - '0' |
| 83 | } else if ('A' <= c && c <= 'Z') { | 83 | } else if ('A' <= c && c <= 'Z') { |
| ... | @@ -85,13 +85,13 @@ fn char_to_digit(c: u8) -> u8 { | ... | @@ -85,13 +85,13 @@ fn char_to_digit(c: u8) -> u8 { |
| 85 | } else if ('a' <= c && c <= 'z') { | 85 | } else if ('a' <= c && c <= 'z') { |
| 86 | c - 'a' + 10 | 86 | c - 'a' + 10 |
| 87 | } else { | 87 | } else { |
| 88 | #max_value(u8) | 88 | @max_value(u8) |
| 89 | } | 89 | } |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | const max_u64_base10_digits: usize = 20; | 92 | const max_u64_base10_digits: usize = 20; |
| 93 | 93 | ||
| 94 | fn buf_print_i64(out_buf: []u8, x: i64) -> usize { | 94 | fn buf_print_i64(out_buf: []u8, x: i64) usize => { |
| 95 | if (x < 0) { | 95 | if (x < 0) { |
| 96 | out_buf[0] = '-'; | 96 | out_buf[0] = '-'; |
| 97 | return 1 + buf_print_u64(out_buf[1...], ((-(x + 1)) as u64) + 1); | 97 | 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 { | ... | @@ -100,7 +100,7 @@ fn buf_print_i64(out_buf: []u8, x: i64) -> usize { |
| 100 | } | 100 | } |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | fn buf_print_u64(out_buf: []u8, x: u64) -> usize { | 103 | fn buf_print_u64(out_buf: []u8, x: u64) usize => { |
| 104 | var buf: [max_u64_base10_digits]u8; | 104 | var buf: [max_u64_base10_digits]u8; |
| 105 | var a = x; | 105 | var a = x; |
| 106 | var index = buf.len; | 106 | var index = buf.len; |
std/syscall.zig+7-7| ... | @@ -3,34 +3,34 @@ const SYS_write : usize = 1; | ... | @@ -3,34 +3,34 @@ const SYS_write : usize = 1; |
| 3 | const SYS_exit : usize = 60; | 3 | const SYS_exit : usize = 60; |
| 4 | const SYS_getrandom : usize = 318; | 4 | const SYS_getrandom : usize = 318; |
| 5 | 5 | ||
| 6 | fn syscall1(number: usize, arg1: usize) -> usize { | 6 | fn syscall1(number: usize, arg1: usize) usize => { |
| 7 | asm volatile ("syscall" | 7 | asm volatile ("syscall" |
| 8 | : [ret] "={rax}" (-> usize) | 8 | : [ret] "={rax}" (-> usize) |
| 9 | : [number] "{rax}" (number), [arg1] "{rdi}" (arg1) | 9 | : [number] "{rax}" (number), [arg1] "{rdi}" (arg1) |
| 10 | : "rcx", "r11") | 10 | : "rcx", "r11") |
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) -> usize { | 13 | fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) usize => { |
| 14 | asm volatile ("syscall" | 14 | asm volatile ("syscall" |
| 15 | : [ret] "={rax}" (-> usize) | 15 | : [ret] "={rax}" (-> usize) |
| 16 | : [number] "{rax}" (number), [arg1] "{rdi}" (arg1), [arg2] "{rsi}" (arg2), [arg3] "{rdx}" (arg3) | 16 | : [number] "{rax}" (number), [arg1] "{rdi}" (arg1), [arg2] "{rsi}" (arg2), [arg3] "{rdx}" (arg3) |
| 17 | : "rcx", "r11") | 17 | : "rcx", "r11") |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | pub fn read(fd: isize, buf: &u8, count: usize) -> isize { | 20 | pub fn read(fd: isize, buf: &u8, count: usize) isize => { |
| 21 | syscall3(SYS_read, fd as usize, buf as usize, count) as isize | 21 | syscall3(SYS_read, fd as usize, buf as usize, count) as isize |
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | pub fn write(fd: isize, buf: &const u8, count: usize) -> isize { | 24 | pub fn write(fd: isize, buf: &const u8, count: usize) isize => { |
| 25 | syscall3(SYS_write, fd as usize, buf as usize, count) as isize | 25 | syscall3(SYS_write, fd as usize, buf as usize, count) as isize |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | pub fn exit(status: i32) -> unreachable { | 28 | pub fn exit(status: i32) unreachable => { |
| 29 | syscall1(SYS_exit, status as usize); | 29 | syscall1(SYS_exit, status as usize); |
| 30 | unreachable | 30 | unreachable{} |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | pub fn getrandom(buf: &u8, count: usize, flags: u32) -> isize { | 33 | pub fn getrandom(buf: &u8, count: usize, flags: u32) isize => { |
| 34 | syscall3(SYS_getrandom, buf as usize, count, flags as usize) as isize | 34 | syscall3(SYS_getrandom, buf as usize, count, flags as usize) as isize |
| 35 | } | 35 | } |
| 36 | 36 |
test/run_tests.cpp+209-209| ... | @@ -96,50 +96,50 @@ static TestCase *add_compile_fail_case(const char *case_name, const char *source | ... | @@ -96,50 +96,50 @@ static TestCase *add_compile_fail_case(const char *case_name, const char *source |
| 96 | 96 | ||
| 97 | static void add_compiling_test_cases(void) { | 97 | static void add_compiling_test_cases(void) { |
| 98 | add_simple_case("hello world with libc", R"SOURCE( | 98 | add_simple_case("hello world with libc", R"SOURCE( |
| 99 | #link("c") | 99 | #link("c") |
| 100 | extern { | 100 | extern { |
| 101 | fn puts(s: &const u8) -> i32; | 101 | fn puts(s: &const u8) i32; |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | export fn main(argc: i32, argv: &&u8, env: &&u8) -> i32 { | 104 | export fn main(argc: i32, argv: &&u8, env: &&u8) i32 => { |
| 105 | puts(c"Hello, world!"); | 105 | puts(c"Hello, world!"); |
| 106 | return 0; | 106 | return 0; |
| 107 | } | 107 | } |
| 108 | )SOURCE", "Hello, world!\n"); | 108 | )SOURCE", "Hello, world!\n"); |
| 109 | 109 | ||
| 110 | add_simple_case("function call", R"SOURCE( | 110 | add_simple_case("function call", R"SOURCE( |
| 111 | use "std.zig"; | 111 | use "std.zig"; |
| 112 | use "syscall.zig"; | 112 | use "syscall.zig"; |
| 113 | 113 | ||
| 114 | fn empty_function_1() {} | 114 | fn empty_function_1() => {} |
| 115 | fn empty_function_2() { return; } | 115 | fn empty_function_2() => { return; } |
| 116 | 116 | ||
| 117 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 117 | pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { |
| 118 | empty_function_1(); | 118 | empty_function_1(); |
| 119 | empty_function_2(); | 119 | empty_function_2(); |
| 120 | this_is_a_function(); | 120 | this_is_a_function(); |
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | fn this_is_a_function() -> unreachable { | 123 | fn this_is_a_function() unreachable => { |
| 124 | print_str("OK\n"); | 124 | print_str("OK\n"); |
| 125 | exit(0); | 125 | exit(0); |
| 126 | } | 126 | } |
| 127 | )SOURCE", "OK\n"); | 127 | )SOURCE", "OK\n"); |
| 128 | 128 | ||
| 129 | add_simple_case("comments", R"SOURCE( | 129 | add_simple_case("comments", R"SOURCE( |
| 130 | use "std.zig"; | 130 | use "std.zig"; |
| 131 | 131 | ||
| 132 | /** | 132 | /** |
| 133 | * multi line doc comment | 133 | * multi line doc comment |
| 134 | */ | 134 | */ |
| 135 | fn another_function() {} | 135 | fn another_function() => {} |
| 136 | 136 | ||
| 137 | /// this is a documentation comment | 137 | /// this is a documentation comment |
| 138 | /// doc comment line 2 | 138 | /// doc comment line 2 |
| 139 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 139 | pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { |
| 140 | print_str(/* mid-line comment /* nested */ */ "OK\n"); | 140 | print_str(/* mid-line comment /* nested */ */ "OK\n"); |
| 141 | return 0; | 141 | return 0; |
| 142 | } | 142 | } |
| 143 | )SOURCE", "OK\n"); | 143 | )SOURCE", "OK\n"); |
| 144 | 144 | ||
| 145 | { | 145 | { |
| ... | @@ -147,13 +147,13 @@ static void add_compiling_test_cases(void) { | ... | @@ -147,13 +147,13 @@ static void add_compiling_test_cases(void) { |
| 147 | use "std.zig"; | 147 | use "std.zig"; |
| 148 | use "foo.zig"; | 148 | use "foo.zig"; |
| 149 | 149 | ||
| 150 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 150 | pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { |
| 151 | private_function(); | 151 | private_function(); |
| 152 | print_str("OK 2\n"); | 152 | print_str("OK 2\n"); |
| 153 | return 0; | 153 | return 0; |
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | fn private_function() { | 156 | fn private_function() => { |
| 157 | print_text(); | 157 | print_text(); |
| 158 | } | 158 | } |
| 159 | )SOURCE", "OK 1\nOK 2\n"); | 159 | )SOURCE", "OK 1\nOK 2\n"); |
| ... | @@ -163,11 +163,11 @@ use "std.zig"; | ... | @@ -163,11 +163,11 @@ use "std.zig"; |
| 163 | 163 | ||
| 164 | // purposefully conflicting function with main.zig | 164 | // purposefully conflicting function with main.zig |
| 165 | // but it's private so it should be OK | 165 | // but it's private so it should be OK |
| 166 | fn private_function() { | 166 | fn private_function() => { |
| 167 | print_str("OK 1\n"); | 167 | print_str("OK 1\n"); |
| 168 | } | 168 | } |
| 169 | 169 | ||
| 170 | pub fn print_text() { | 170 | pub fn print_text() => { |
| 171 | private_function(); | 171 | private_function(); |
| 172 | } | 172 | } |
| 173 | )SOURCE"); | 173 | )SOURCE"); |
| ... | @@ -178,7 +178,7 @@ pub fn print_text() { | ... | @@ -178,7 +178,7 @@ pub fn print_text() { |
| 178 | use "foo.zig"; | 178 | use "foo.zig"; |
| 179 | use "bar.zig"; | 179 | use "bar.zig"; |
| 180 | 180 | ||
| 181 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 181 | pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { |
| 182 | foo_function(); | 182 | foo_function(); |
| 183 | bar_function(); | 183 | bar_function(); |
| 184 | return 0; | 184 | return 0; |
| ... | @@ -187,7 +187,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | ... | @@ -187,7 +187,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { |
| 187 | 187 | ||
| 188 | add_source_file(tc, "foo.zig", R"SOURCE( | 188 | add_source_file(tc, "foo.zig", R"SOURCE( |
| 189 | use "std.zig"; | 189 | use "std.zig"; |
| 190 | pub fn foo_function() { | 190 | pub fn foo_function() => { |
| 191 | print_str("OK\n"); | 191 | print_str("OK\n"); |
| 192 | } | 192 | } |
| 193 | )SOURCE"); | 193 | )SOURCE"); |
| ... | @@ -196,7 +196,7 @@ pub fn foo_function() { | ... | @@ -196,7 +196,7 @@ pub fn foo_function() { |
| 196 | use "other.zig"; | 196 | use "other.zig"; |
| 197 | use "std.zig"; | 197 | use "std.zig"; |
| 198 | 198 | ||
| 199 | pub fn bar_function() { | 199 | pub fn bar_function() => { |
| 200 | if (foo_function()) { | 200 | if (foo_function()) { |
| 201 | print_str("OK\n"); | 201 | print_str("OK\n"); |
| 202 | } | 202 | } |
| ... | @@ -204,7 +204,7 @@ pub fn bar_function() { | ... | @@ -204,7 +204,7 @@ pub fn bar_function() { |
| 204 | )SOURCE"); | 204 | )SOURCE"); |
| 205 | 205 | ||
| 206 | add_source_file(tc, "other.zig", R"SOURCE( | 206 | add_source_file(tc, "other.zig", R"SOURCE( |
| 207 | pub fn foo_function() -> bool { | 207 | pub fn foo_function() bool => { |
| 208 | // this one conflicts with the one from foo | 208 | // this one conflicts with the one from foo |
| 209 | return true; | 209 | return true; |
| 210 | } | 210 | } |
| ... | @@ -212,65 +212,65 @@ pub fn foo_function() -> bool { | ... | @@ -212,65 +212,65 @@ pub fn foo_function() -> bool { |
| 212 | } | 212 | } |
| 213 | 213 | ||
| 214 | add_simple_case("if statements", R"SOURCE( | 214 | add_simple_case("if statements", R"SOURCE( |
| 215 | use "std.zig"; | 215 | use "std.zig"; |
| 216 | 216 | ||
| 217 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 217 | pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { |
| 218 | if (1 != 0) { | 218 | if (1 != 0) { |
| 219 | print_str("1 is true\n"); | 219 | print_str("1 is true\n"); |
| 220 | } else { | 220 | } else { |
| 221 | print_str("1 is false\n"); | 221 | print_str("1 is false\n"); |
| 222 | } | 222 | } |
| 223 | if (0 != 0) { | 223 | if (0 != 0) { |
| 224 | print_str("0 is true\n"); | 224 | print_str("0 is true\n"); |
| 225 | } else if (1 - 1 != 0) { | 225 | } else if (1 - 1 != 0) { |
| 226 | print_str("1 - 1 is true\n"); | 226 | print_str("1 - 1 is true\n"); |
| 227 | } | 227 | } |
| 228 | if (!(0 != 0)) { | 228 | if (!(0 != 0)) { |
| 229 | print_str("!0 is true\n"); | 229 | print_str("!0 is true\n"); |
| 230 | } | 230 | } |
| 231 | return 0; | 231 | return 0; |
| 232 | } | 232 | } |
| 233 | )SOURCE", "1 is true\n!0 is true\n"); | 233 | )SOURCE", "1 is true\n!0 is true\n"); |
| 234 | 234 | ||
| 235 | add_simple_case("params", R"SOURCE( | 235 | add_simple_case("params", R"SOURCE( |
| 236 | use "std.zig"; | 236 | use "std.zig"; |
| 237 | 237 | ||
| 238 | fn add(a: i32, b: i32) -> i32 { | 238 | fn add(a: i32, b: i32) i32 => { |
| 239 | a + b | 239 | a + b |
| 240 | } | 240 | } |
| 241 | 241 | ||
| 242 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 242 | pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { |
| 243 | if (add(22, 11) == 33) { | 243 | if (add(22, 11) == 33) { |
| 244 | print_str("pass\n"); | 244 | print_str("pass\n"); |
| 245 | } | 245 | } |
| 246 | return 0; | 246 | return 0; |
| 247 | } | 247 | } |
| 248 | )SOURCE", "pass\n"); | 248 | )SOURCE", "pass\n"); |
| 249 | 249 | ||
| 250 | add_simple_case("goto", R"SOURCE( | 250 | add_simple_case("goto", R"SOURCE( |
| 251 | use "std.zig"; | 251 | use "std.zig"; |
| 252 | 252 | ||
| 253 | fn loop(a : i32) { | 253 | fn loop(a : i32) => { |
| 254 | if (a == 0) { | 254 | if (a == 0) { |
| 255 | goto done; | 255 | goto done; |
| 256 | } | 256 | } |
| 257 | print_str("loop\n"); | 257 | print_str("loop\n"); |
| 258 | loop(a - 1); | 258 | loop(a - 1); |
| 259 | 259 | ||
| 260 | done: | 260 | done: |
| 261 | return; | 261 | return; |
| 262 | } | 262 | } |
| 263 | 263 | ||
| 264 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 264 | pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { |
| 265 | loop(3); | 265 | loop(3); |
| 266 | return 0; | 266 | return 0; |
| 267 | } | 267 | } |
| 268 | )SOURCE", "loop\nloop\nloop\n"); | 268 | )SOURCE", "loop\nloop\nloop\n"); |
| 269 | 269 | ||
| 270 | add_simple_case("local variables", R"SOURCE( | 270 | add_simple_case("local variables", R"SOURCE( |
| 271 | use "std.zig"; | 271 | use "std.zig"; |
| 272 | 272 | ||
| 273 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 273 | pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { |
| 274 | const a : i32 = 1; | 274 | const a : i32 = 1; |
| 275 | const b = 2 as i32; | 275 | const b = 2 as i32; |
| 276 | if (a + b == 3) { | 276 | if (a + b == 3) { |
| ... | @@ -283,7 +283,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | ... | @@ -283,7 +283,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { |
| 283 | add_simple_case("bool literals", R"SOURCE( | 283 | add_simple_case("bool literals", R"SOURCE( |
| 284 | use "std.zig"; | 284 | use "std.zig"; |
| 285 | 285 | ||
| 286 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 286 | pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { |
| 287 | if (true) { print_str("OK 1\n"); } | 287 | if (true) { print_str("OK 1\n"); } |
| 288 | if (false) { print_str("BAD 1\n"); } | 288 | if (false) { print_str("BAD 1\n"); } |
| 289 | if (!true) { print_str("BAD 2\n"); } | 289 | if (!true) { print_str("BAD 2\n"); } |
| ... | @@ -295,7 +295,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | ... | @@ -295,7 +295,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { |
| 295 | add_simple_case("separate block scopes", R"SOURCE( | 295 | add_simple_case("separate block scopes", R"SOURCE( |
| 296 | use "std.zig"; | 296 | use "std.zig"; |
| 297 | 297 | ||
| 298 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 298 | pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { |
| 299 | if (true) { | 299 | if (true) { |
| 300 | const no_conflict : i32 = 5; | 300 | const no_conflict : i32 = 5; |
| 301 | if (no_conflict == 5) { print_str("OK 1\n"); } | 301 | if (no_conflict == 5) { print_str("OK 1\n"); } |
| ... | @@ -313,12 +313,12 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | ... | @@ -313,12 +313,12 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { |
| 313 | add_simple_case("void parameters", R"SOURCE( | 313 | add_simple_case("void parameters", R"SOURCE( |
| 314 | use "std.zig"; | 314 | use "std.zig"; |
| 315 | 315 | ||
| 316 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 316 | pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { |
| 317 | void_fun(1, void, 2); | 317 | void_fun(1, void{}, 2); |
| 318 | return 0; | 318 | return 0; |
| 319 | } | 319 | } |
| 320 | 320 | ||
| 321 | fn void_fun(a : i32, b : void, c : i32) { | 321 | fn void_fun(a : i32, b : void, c : i32) => { |
| 322 | const v = b; | 322 | const v = b; |
| 323 | const vv : void = if (a == 1) {v} else {}; | 323 | const vv : void = if (a == 1) {v} else {}; |
| 324 | if (a + c == 3) { print_str("OK\n"); } | 324 | if (a + c == 3) { print_str("OK\n"); } |
| ... | @@ -333,16 +333,16 @@ struct Foo { | ... | @@ -333,16 +333,16 @@ struct Foo { |
| 333 | b : i32, | 333 | b : i32, |
| 334 | c : void, | 334 | c : void, |
| 335 | } | 335 | } |
| 336 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 336 | pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { |
| 337 | const foo = Foo { | 337 | const foo = Foo { |
| 338 | .a = void, | 338 | .a = void{}, |
| 339 | .b = 1, | 339 | .b = 1, |
| 340 | .c = void, | 340 | .c = void{}, |
| 341 | }; | 341 | }; |
| 342 | if (foo.b != 1) { | 342 | if (foo.b != 1) { |
| 343 | print_str("BAD\n"); | 343 | print_str("BAD\n"); |
| 344 | } | 344 | } |
| 345 | if (#sizeof(Foo) != 4) { | 345 | if (@sizeof(Foo) != 4) { |
| 346 | print_str("BAD\n"); | 346 | print_str("BAD\n"); |
| 347 | } | 347 | } |
| 348 | print_str("OK\n"); | 348 | print_str("OK\n"); |
| ... | @@ -354,7 +354,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | ... | @@ -354,7 +354,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { |
| 354 | add_simple_case("mutable local variables", R"SOURCE( | 354 | add_simple_case("mutable local variables", R"SOURCE( |
| 355 | use "std.zig"; | 355 | use "std.zig"; |
| 356 | 356 | ||
| 357 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 357 | pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { |
| 358 | var zero : i32 = 0; | 358 | var zero : i32 = 0; |
| 359 | if (zero == 0) { print_str("zero\n"); } | 359 | if (zero == 0) { print_str("zero\n"); } |
| 360 | 360 | ||
| ... | @@ -374,7 +374,7 @@ done: | ... | @@ -374,7 +374,7 @@ done: |
| 374 | add_simple_case("arrays", R"SOURCE( | 374 | add_simple_case("arrays", R"SOURCE( |
| 375 | use "std.zig"; | 375 | use "std.zig"; |
| 376 | 376 | ||
| 377 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 377 | pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { |
| 378 | var array : [5]u32; | 378 | var array : [5]u32; |
| 379 | 379 | ||
| 380 | var i : u32 = 0; | 380 | var i : u32 = 0; |
| ... | @@ -401,7 +401,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | ... | @@ -401,7 +401,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { |
| 401 | 401 | ||
| 402 | return 0; | 402 | return 0; |
| 403 | } | 403 | } |
| 404 | fn get_array_len(a: []u32) -> usize { | 404 | fn get_array_len(a: []u32) usize => { |
| 405 | a.len | 405 | a.len |
| 406 | } | 406 | } |
| 407 | )SOURCE", "OK\n"); | 407 | )SOURCE", "OK\n"); |
| ... | @@ -410,7 +410,7 @@ fn get_array_len(a: []u32) -> usize { | ... | @@ -410,7 +410,7 @@ fn get_array_len(a: []u32) -> usize { |
| 410 | add_simple_case("hello world without libc", R"SOURCE( | 410 | add_simple_case("hello world without libc", R"SOURCE( |
| 411 | use "std.zig"; | 411 | use "std.zig"; |
| 412 | 412 | ||
| 413 | pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { | 413 | pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => { |
| 414 | print_str("Hello, world!\n"); | 414 | print_str("Hello, world!\n"); |
| 415 | return 0; | 415 | return 0; |
| 416 | } | 416 | } |
| ... | @@ -420,7 +420,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { | ... | @@ -420,7 +420,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { |
| 420 | add_simple_case("a + b + c", R"SOURCE( | 420 | add_simple_case("a + b + c", R"SOURCE( |
| 421 | use "std.zig"; | 421 | use "std.zig"; |
| 422 | 422 | ||
| 423 | pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { | 423 | pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => { |
| 424 | if (false || false || false) { print_str("BAD 1\n"); } | 424 | if (false || false || false) { print_str("BAD 1\n"); } |
| 425 | if (true && true && false) { print_str("BAD 2\n"); } | 425 | if (true && true && false) { print_str("BAD 2\n"); } |
| 426 | if (1 | 2 | 4 != 7) { print_str("BAD 3\n"); } | 426 | if (1 | 2 | 4 != 7) { print_str("BAD 3\n"); } |
| ... | @@ -442,7 +442,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { | ... | @@ -442,7 +442,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { |
| 442 | add_simple_case("short circuit", R"SOURCE( | 442 | add_simple_case("short circuit", R"SOURCE( |
| 443 | use "std.zig"; | 443 | use "std.zig"; |
| 444 | 444 | ||
| 445 | pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { | 445 | pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => { |
| 446 | if (true || { print_str("BAD 1\n"); false }) { | 446 | if (true || { print_str("BAD 1\n"); false }) { |
| 447 | print_str("OK 1\n"); | 447 | print_str("OK 1\n"); |
| 448 | } | 448 | } |
| ... | @@ -465,7 +465,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { | ... | @@ -465,7 +465,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { |
| 465 | add_simple_case("modify operators", R"SOURCE( | 465 | add_simple_case("modify operators", R"SOURCE( |
| 466 | use "std.zig"; | 466 | use "std.zig"; |
| 467 | 467 | ||
| 468 | pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { | 468 | pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => { |
| 469 | var i : i32 = 0; | 469 | var i : i32 = 0; |
| 470 | i += 5; if (i != 5) { print_str("BAD +=\n"); } | 470 | i += 5; if (i != 5) { print_str("BAD +=\n"); } |
| 471 | i -= 2; if (i != 3) { print_str("BAD -=\n"); } | 471 | i -= 2; if (i != 3) { print_str("BAD -=\n"); } |
| ... | @@ -488,10 +488,10 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { | ... | @@ -488,10 +488,10 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { |
| 488 | add_simple_case("number literals", R"SOURCE( | 488 | add_simple_case("number literals", R"SOURCE( |
| 489 | #link("c") | 489 | #link("c") |
| 490 | extern { | 490 | extern { |
| 491 | fn printf(__format: &const u8, ...) -> i32; | 491 | fn printf(__format: &const u8, ...) i32; |
| 492 | } | 492 | } |
| 493 | 493 | ||
| 494 | export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { | 494 | export fn main(argc : isize, argv : &&u8, env : &&u8) i32 => { |
| 495 | printf(c"\n"); | 495 | printf(c"\n"); |
| 496 | 496 | ||
| 497 | printf(c"0: %llu\n", | 497 | printf(c"0: %llu\n", |
| ... | @@ -617,9 +617,9 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { | ... | @@ -617,9 +617,9 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { |
| 617 | add_simple_case("structs", R"SOURCE( | 617 | add_simple_case("structs", R"SOURCE( |
| 618 | use "std.zig"; | 618 | use "std.zig"; |
| 619 | 619 | ||
| 620 | pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { | 620 | pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => { |
| 621 | var foo : Foo; | 621 | var foo : Foo; |
| 622 | @memset(&foo, 0, #sizeof(Foo)); | 622 | @memset(&foo, 0, @sizeof(Foo)); |
| 623 | foo.a += 1; | 623 | foo.a += 1; |
| 624 | foo.b = foo.a == 1; | 624 | foo.b = foo.a == 1; |
| 625 | test_foo(foo); | 625 | test_foo(foo); |
| ... | @@ -638,12 +638,12 @@ struct Foo { | ... | @@ -638,12 +638,12 @@ struct Foo { |
| 638 | b : bool, | 638 | b : bool, |
| 639 | c : f32, | 639 | c : f32, |
| 640 | } | 640 | } |
| 641 | fn test_foo(foo : Foo) { | 641 | fn test_foo(foo : Foo) => { |
| 642 | if (!foo.b) { | 642 | if (!foo.b) { |
| 643 | print_str("BAD\n"); | 643 | print_str("BAD\n"); |
| 644 | } | 644 | } |
| 645 | } | 645 | } |
| 646 | fn test_mutation(foo : &Foo) { | 646 | fn test_mutation(foo : &Foo) => { |
| 647 | foo.c = 100; | 647 | foo.c = 100; |
| 648 | } | 648 | } |
| 649 | struct Node { | 649 | struct Node { |
| ... | @@ -654,7 +654,7 @@ struct Node { | ... | @@ -654,7 +654,7 @@ struct Node { |
| 654 | struct Val { | 654 | struct Val { |
| 655 | x: i32, | 655 | x: i32, |
| 656 | } | 656 | } |
| 657 | fn test_point_to_self() { | 657 | fn test_point_to_self() => { |
| 658 | var root : Node; | 658 | var root : Node; |
| 659 | root.val.x = 1; | 659 | root.val.x = 1; |
| 660 | 660 | ||
| ... | @@ -668,7 +668,7 @@ fn test_point_to_self() { | ... | @@ -668,7 +668,7 @@ fn test_point_to_self() { |
| 668 | print_str("BAD\n"); | 668 | print_str("BAD\n"); |
| 669 | } | 669 | } |
| 670 | } | 670 | } |
| 671 | fn test_byval_assign() { | 671 | fn test_byval_assign() => { |
| 672 | var foo1 : Foo; | 672 | var foo1 : Foo; |
| 673 | var foo2 : Foo; | 673 | var foo2 : Foo; |
| 674 | 674 | ||
| ... | @@ -680,7 +680,7 @@ fn test_byval_assign() { | ... | @@ -680,7 +680,7 @@ fn test_byval_assign() { |
| 680 | 680 | ||
| 681 | if (foo2.a != 1234) { print_str("BAD - byval assignment failed\n"); } | 681 | if (foo2.a != 1234) { print_str("BAD - byval assignment failed\n"); } |
| 682 | } | 682 | } |
| 683 | fn test_initializer() { | 683 | fn test_initializer() => { |
| 684 | const val = Val { .x = 42 }; | 684 | const val = Val { .x = 42 }; |
| 685 | if (val.x != 42) { print_str("BAD\n"); } | 685 | if (val.x != 42) { print_str("BAD\n"); } |
| 686 | } | 686 | } |
| ... | @@ -692,7 +692,7 @@ use "std.zig"; | ... | @@ -692,7 +692,7 @@ use "std.zig"; |
| 692 | const g1 : i32 = 1233 + 1; | 692 | const g1 : i32 = 1233 + 1; |
| 693 | var g2 : i32 = 0; | 693 | var g2 : i32 = 0; |
| 694 | 694 | ||
| 695 | pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { | 695 | pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => { |
| 696 | if (g2 != 0) { print_str("BAD\n"); } | 696 | if (g2 != 0) { print_str("BAD\n"); } |
| 697 | g2 = g1; | 697 | g2 = g1; |
| 698 | if (g2 != 1234) { print_str("BAD\n"); } | 698 | if (g2 != 1234) { print_str("BAD\n"); } |
| ... | @@ -703,7 +703,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { | ... | @@ -703,7 +703,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { |
| 703 | 703 | ||
| 704 | add_simple_case("while loop", R"SOURCE( | 704 | add_simple_case("while loop", R"SOURCE( |
| 705 | use "std.zig"; | 705 | use "std.zig"; |
| 706 | pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { | 706 | pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => { |
| 707 | var i : i32 = 0; | 707 | var i : i32 = 0; |
| 708 | while (i < 4) { | 708 | while (i < 4) { |
| 709 | print_str("loop\n"); | 709 | print_str("loop\n"); |
| ... | @@ -711,7 +711,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { | ... | @@ -711,7 +711,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { |
| 711 | } | 711 | } |
| 712 | return f(); | 712 | return f(); |
| 713 | } | 713 | } |
| 714 | fn f() -> i32 { | 714 | fn f() i32 => { |
| 715 | while (true) { | 715 | while (true) { |
| 716 | return 0; | 716 | return 0; |
| 717 | } | 717 | } |
| ... | @@ -720,7 +720,7 @@ fn f() -> i32 { | ... | @@ -720,7 +720,7 @@ fn f() -> i32 { |
| 720 | 720 | ||
| 721 | add_simple_case("continue and break", R"SOURCE( | 721 | add_simple_case("continue and break", R"SOURCE( |
| 722 | use "std.zig"; | 722 | use "std.zig"; |
| 723 | pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { | 723 | pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => { |
| 724 | var i : i32 = 0; | 724 | var i : i32 = 0; |
| 725 | while (true) { | 725 | while (true) { |
| 726 | print_str("loop\n"); | 726 | print_str("loop\n"); |
| ... | @@ -736,7 +736,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { | ... | @@ -736,7 +736,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { |
| 736 | 736 | ||
| 737 | add_simple_case("maybe type", R"SOURCE( | 737 | add_simple_case("maybe type", R"SOURCE( |
| 738 | use "std.zig"; | 738 | use "std.zig"; |
| 739 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 739 | pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { |
| 740 | const x : ?bool = true; | 740 | const x : ?bool = true; |
| 741 | 741 | ||
| 742 | if (const y ?= x) { | 742 | if (const y ?= x) { |
| ... | @@ -759,7 +759,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | ... | @@ -759,7 +759,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { |
| 759 | 759 | ||
| 760 | const final_x : ?i32 = 13; | 760 | const final_x : ?i32 = 13; |
| 761 | 761 | ||
| 762 | const num = final_x ?? unreachable; | 762 | const num = final_x ?? unreachable{}; |
| 763 | 763 | ||
| 764 | if (num != 13) { | 764 | if (num != 13) { |
| 765 | print_str("BAD\n"); | 765 | print_str("BAD\n"); |
| ... | @@ -771,26 +771,26 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | ... | @@ -771,26 +771,26 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { |
| 771 | 771 | ||
| 772 | add_simple_case("implicit cast after unreachable", R"SOURCE( | 772 | add_simple_case("implicit cast after unreachable", R"SOURCE( |
| 773 | use "std.zig"; | 773 | use "std.zig"; |
| 774 | pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { | 774 | pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => { |
| 775 | const x = outer(); | 775 | const x = outer(); |
| 776 | if (x == 1234) { | 776 | if (x == 1234) { |
| 777 | print_str("OK\n"); | 777 | print_str("OK\n"); |
| 778 | } | 778 | } |
| 779 | return 0; | 779 | return 0; |
| 780 | } | 780 | } |
| 781 | fn inner() -> i32 { 1234 } | 781 | fn inner() i32 => { 1234 } |
| 782 | fn outer() -> isize { | 782 | fn outer() isize => { |
| 783 | return inner(); | 783 | return inner(); |
| 784 | } | 784 | } |
| 785 | )SOURCE", "OK\n"); | 785 | )SOURCE", "OK\n"); |
| 786 | 786 | ||
| 787 | add_simple_case("#sizeof() and #typeof()", R"SOURCE( | 787 | add_simple_case("@sizeof() and @typeof()", R"SOURCE( |
| 788 | use "std.zig"; | 788 | use "std.zig"; |
| 789 | const x: u16 = 13; | 789 | const x: u16 = 13; |
| 790 | const z: #typeof(x) = 19; | 790 | const z: @typeof(x) = 19; |
| 791 | pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { | 791 | pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => { |
| 792 | const y: #typeof(x) = 120; | 792 | const y: @typeof(x) = 120; |
| 793 | print_u64(#sizeof(#typeof(y))); | 793 | print_u64(@sizeof(@typeof(y))); |
| 794 | print_str("\n"); | 794 | print_str("\n"); |
| 795 | return 0; | 795 | return 0; |
| 796 | } | 796 | } |
| ... | @@ -800,11 +800,11 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { | ... | @@ -800,11 +800,11 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { |
| 800 | use "std.zig"; | 800 | use "std.zig"; |
| 801 | struct Rand { | 801 | struct Rand { |
| 802 | seed: u32, | 802 | seed: u32, |
| 803 | pub fn get_seed(r: Rand) -> u32 { | 803 | pub fn get_seed(r: Rand) u32 => { |
| 804 | r.seed | 804 | r.seed |
| 805 | } | 805 | } |
| 806 | } | 806 | } |
| 807 | pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { | 807 | pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => { |
| 808 | const r = Rand {.seed = 1234}; | 808 | const r = Rand {.seed = 1234}; |
| 809 | if (r.get_seed() != 1234) { | 809 | if (r.get_seed() != 1234) { |
| 810 | print_str("BAD seed\n"); | 810 | print_str("BAD seed\n"); |
| ... | @@ -817,7 +817,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { | ... | @@ -817,7 +817,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { |
| 817 | add_simple_case("pointer dereferencing", R"SOURCE( | 817 | add_simple_case("pointer dereferencing", R"SOURCE( |
| 818 | use "std.zig"; | 818 | use "std.zig"; |
| 819 | 819 | ||
| 820 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 820 | pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { |
| 821 | var x = 3 as i32; | 821 | var x = 3 as i32; |
| 822 | const y = &x; | 822 | const y = &x; |
| 823 | 823 | ||
| ... | @@ -839,9 +839,9 @@ use "std.zig"; | ... | @@ -839,9 +839,9 @@ use "std.zig"; |
| 839 | 839 | ||
| 840 | const ARRAY_SIZE : u8 = 20; | 840 | const ARRAY_SIZE : u8 = 20; |
| 841 | 841 | ||
| 842 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 842 | pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { |
| 843 | var array : [ARRAY_SIZE]u8; | 843 | var array : [ARRAY_SIZE]u8; |
| 844 | print_u64(#sizeof(#typeof(array))); | 844 | print_u64(@sizeof(@typeof(array))); |
| 845 | print_str("\n"); | 845 | print_str("\n"); |
| 846 | return 0; | 846 | return 0; |
| 847 | } | 847 | } |
| ... | @@ -849,69 +849,69 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | ... | @@ -849,69 +849,69 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { |
| 849 | 849 | ||
| 850 | add_simple_case("#min_value() and #max_value()", R"SOURCE( | 850 | add_simple_case("#min_value() and #max_value()", R"SOURCE( |
| 851 | use "std.zig"; | 851 | use "std.zig"; |
| 852 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 852 | pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { |
| 853 | print_str("max u8: "); | 853 | print_str("max u8: "); |
| 854 | print_u64(#max_value(u8)); | 854 | print_u64(@max_value(u8)); |
| 855 | print_str("\n"); | 855 | print_str("\n"); |
| 856 | 856 | ||
| 857 | print_str("max u16: "); | 857 | print_str("max u16: "); |
| 858 | print_u64(#max_value(u16)); | 858 | print_u64(@max_value(u16)); |
| 859 | print_str("\n"); | 859 | print_str("\n"); |
| 860 | 860 | ||
| 861 | print_str("max u32: "); | 861 | print_str("max u32: "); |
| 862 | print_u64(#max_value(u32)); | 862 | print_u64(@max_value(u32)); |
| 863 | print_str("\n"); | 863 | print_str("\n"); |
| 864 | 864 | ||
| 865 | print_str("max u64: "); | 865 | print_str("max u64: "); |
| 866 | print_u64(#max_value(u64)); | 866 | print_u64(@max_value(u64)); |
| 867 | print_str("\n"); | 867 | print_str("\n"); |
| 868 | 868 | ||
| 869 | print_str("max i8: "); | 869 | print_str("max i8: "); |
| 870 | print_i64(#max_value(i8)); | 870 | print_i64(@max_value(i8)); |
| 871 | print_str("\n"); | 871 | print_str("\n"); |
| 872 | 872 | ||
| 873 | print_str("max i16: "); | 873 | print_str("max i16: "); |
| 874 | print_i64(#max_value(i16)); | 874 | print_i64(@max_value(i16)); |
| 875 | print_str("\n"); | 875 | print_str("\n"); |
| 876 | 876 | ||
| 877 | print_str("max i32: "); | 877 | print_str("max i32: "); |
| 878 | print_i64(#max_value(i32)); | 878 | print_i64(@max_value(i32)); |
| 879 | print_str("\n"); | 879 | print_str("\n"); |
| 880 | 880 | ||
| 881 | print_str("max i64: "); | 881 | print_str("max i64: "); |
| 882 | print_i64(#max_value(i64)); | 882 | print_i64(@max_value(i64)); |
| 883 | print_str("\n"); | 883 | print_str("\n"); |
| 884 | 884 | ||
| 885 | print_str("min u8: "); | 885 | print_str("min u8: "); |
| 886 | print_u64(#min_value(u8)); | 886 | print_u64(@min_value(u8)); |
| 887 | print_str("\n"); | 887 | print_str("\n"); |
| 888 | 888 | ||
| 889 | print_str("min u16: "); | 889 | print_str("min u16: "); |
| 890 | print_u64(#min_value(u16)); | 890 | print_u64(@min_value(u16)); |
| 891 | print_str("\n"); | 891 | print_str("\n"); |
| 892 | 892 | ||
| 893 | print_str("min u32: "); | 893 | print_str("min u32: "); |
| 894 | print_u64(#min_value(u32)); | 894 | print_u64(@min_value(u32)); |
| 895 | print_str("\n"); | 895 | print_str("\n"); |
| 896 | 896 | ||
| 897 | print_str("min u64: "); | 897 | print_str("min u64: "); |
| 898 | print_u64(#min_value(u64)); | 898 | print_u64(@min_value(u64)); |
| 899 | print_str("\n"); | 899 | print_str("\n"); |
| 900 | 900 | ||
| 901 | print_str("min i8: "); | 901 | print_str("min i8: "); |
| 902 | print_i64(#min_value(i8)); | 902 | print_i64(@min_value(i8)); |
| 903 | print_str("\n"); | 903 | print_str("\n"); |
| 904 | 904 | ||
| 905 | print_str("min i16: "); | 905 | print_str("min i16: "); |
| 906 | print_i64(#min_value(i16)); | 906 | print_i64(@min_value(i16)); |
| 907 | print_str("\n"); | 907 | print_str("\n"); |
| 908 | 908 | ||
| 909 | print_str("min i32: "); | 909 | print_str("min i32: "); |
| 910 | print_i64(#min_value(i32)); | 910 | print_i64(@min_value(i32)); |
| 911 | print_str("\n"); | 911 | print_str("\n"); |
| 912 | 912 | ||
| 913 | print_str("min i64: "); | 913 | print_str("min i64: "); |
| 914 | print_i64(#min_value(i64)); | 914 | print_i64(@min_value(i64)); |
| 915 | print_str("\n"); | 915 | print_str("\n"); |
| 916 | 916 | ||
| 917 | return 0; | 917 | return 0; |
| ... | @@ -937,7 +937,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | ... | @@ -937,7 +937,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { |
| 937 | 937 | ||
| 938 | add_simple_case("slicing", R"SOURCE( | 938 | add_simple_case("slicing", R"SOURCE( |
| 939 | use "std.zig"; | 939 | use "std.zig"; |
| 940 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 940 | pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { |
| 941 | var array : [20]i32; | 941 | var array : [20]i32; |
| 942 | 942 | ||
| 943 | array[5] = 1234; | 943 | array[5] = 1234; |
| ... | @@ -965,13 +965,13 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | ... | @@ -965,13 +965,13 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { |
| 965 | 965 | ||
| 966 | add_simple_case("else if expression", R"SOURCE( | 966 | add_simple_case("else if expression", R"SOURCE( |
| 967 | use "std.zig"; | 967 | use "std.zig"; |
| 968 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 968 | pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { |
| 969 | if (f(1) == 1) { | 969 | if (f(1) == 1) { |
| 970 | print_str("OK\n"); | 970 | print_str("OK\n"); |
| 971 | } | 971 | } |
| 972 | return 0; | 972 | return 0; |
| 973 | } | 973 | } |
| 974 | fn f(c: u8) -> u8 { | 974 | fn f(c: u8) u8 => { |
| 975 | if (c == 0) { | 975 | if (c == 0) { |
| 976 | 0 | 976 | 0 |
| 977 | } else if (c == 1) { | 977 | } else if (c == 1) { |
| ... | @@ -984,7 +984,7 @@ fn f(c: u8) -> u8 { | ... | @@ -984,7 +984,7 @@ fn f(c: u8) -> u8 { |
| 984 | 984 | ||
| 985 | add_simple_case("overflow intrinsics", R"SOURCE( | 985 | add_simple_case("overflow intrinsics", R"SOURCE( |
| 986 | use "std.zig"; | 986 | use "std.zig"; |
| 987 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 987 | pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { |
| 988 | var result: u8; | 988 | var result: u8; |
| 989 | if (!@add_with_overflow_u8(250, 100, &result)) { | 989 | if (!@add_with_overflow_u8(250, 100, &result)) { |
| 990 | print_str("BAD\n"); | 990 | print_str("BAD\n"); |
| ... | @@ -1002,7 +1002,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | ... | @@ -1002,7 +1002,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { |
| 1002 | 1002 | ||
| 1003 | add_simple_case("memcpy and memset intrinsics", R"SOURCE( | 1003 | add_simple_case("memcpy and memset intrinsics", R"SOURCE( |
| 1004 | use "std.zig"; | 1004 | use "std.zig"; |
| 1005 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 1005 | pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { |
| 1006 | var foo : [20]u8; | 1006 | var foo : [20]u8; |
| 1007 | var bar : [20]u8; | 1007 | var bar : [20]u8; |
| 1008 | 1008 | ||
| ... | @@ -1020,13 +1020,13 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | ... | @@ -1020,13 +1020,13 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { |
| 1020 | 1020 | ||
| 1021 | add_simple_case("order-independent declarations", R"SOURCE( | 1021 | add_simple_case("order-independent declarations", R"SOURCE( |
| 1022 | use "std.zig"; | 1022 | use "std.zig"; |
| 1023 | const z : #typeof(stdin_fileno) = 0; | 1023 | const z : @typeof(stdin_fileno) = 0; |
| 1024 | const x : #typeof(y) = 1234; | 1024 | const x : @typeof(y) = 1234; |
| 1025 | const y : u16 = 5678; | 1025 | const y : u16 = 5678; |
| 1026 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 1026 | pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { |
| 1027 | print_ok(x) | 1027 | print_ok(x) |
| 1028 | } | 1028 | } |
| 1029 | fn print_ok(val: #typeof(x)) -> #typeof(foo) { | 1029 | fn print_ok(val: @typeof(x)) @typeof(foo) => { |
| 1030 | print_str("OK\n"); | 1030 | print_str("OK\n"); |
| 1031 | return 0; | 1031 | return 0; |
| 1032 | } | 1032 | } |
| ... | @@ -1054,7 +1054,7 @@ enum Bar { | ... | @@ -1054,7 +1054,7 @@ enum Bar { |
| 1054 | D, | 1054 | D, |
| 1055 | } | 1055 | } |
| 1056 | 1056 | ||
| 1057 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | 1057 | pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { |
| 1058 | const foo1 = Foo.One(13); | 1058 | const foo1 = Foo.One(13); |
| 1059 | const foo2 = Foo.Two(Point { .x = 1234, .y = 5678, }); | 1059 | const foo2 = Foo.Two(Point { .x = 1234, .y = 5678, }); |
| 1060 | const bar = Bar.B; | 1060 | const bar = Bar.B; |
| ... | @@ -1063,18 +1063,18 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | ... | @@ -1063,18 +1063,18 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { |
| 1063 | print_str("BAD\n"); | 1063 | print_str("BAD\n"); |
| 1064 | } | 1064 | } |
| 1065 | 1065 | ||
| 1066 | if (#value_count(Foo) != 3) { | 1066 | if (@value_count(Foo) != 3) { |
| 1067 | print_str("BAD\n"); | 1067 | print_str("BAD\n"); |
| 1068 | } | 1068 | } |
| 1069 | 1069 | ||
| 1070 | if (#value_count(Bar) != 4) { | 1070 | if (@value_count(Bar) != 4) { |
| 1071 | print_str("BAD\n"); | 1071 | print_str("BAD\n"); |
| 1072 | } | 1072 | } |
| 1073 | 1073 | ||
| 1074 | if (#sizeof(Foo) != 17) { | 1074 | if (@sizeof(Foo) != 17) { |
| 1075 | print_str("BAD\n"); | 1075 | print_str("BAD\n"); |
| 1076 | } | 1076 | } |
| 1077 | if (#sizeof(Bar) != 1) { | 1077 | if (@sizeof(Bar) != 1) { |
| 1078 | print_str("BAD\n"); | 1078 | print_str("BAD\n"); |
| 1079 | } | 1079 | } |
| 1080 | 1080 | ||
| ... | @@ -1090,8 +1090,8 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | ... | @@ -1090,8 +1090,8 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { |
| 1090 | 1090 | ||
| 1091 | static void add_compile_failure_test_cases(void) { | 1091 | static void add_compile_failure_test_cases(void) { |
| 1092 | add_compile_fail_case("multiple function definitions", R"SOURCE( | 1092 | add_compile_fail_case("multiple function definitions", R"SOURCE( |
| 1093 | fn a() {} | 1093 | fn a() => {} |
| 1094 | fn a() {} | 1094 | fn a() => {} |
| 1095 | )SOURCE", 1, ".tmp_source.zig:3:1: error: redefinition of 'a'"); | 1095 | )SOURCE", 1, ".tmp_source.zig:3:1: error: redefinition of 'a'"); |
| 1096 | 1096 | ||
| 1097 | add_compile_fail_case("bad directive", R"SOURCE( | 1097 | add_compile_fail_case("bad directive", R"SOURCE( |
| ... | @@ -1100,46 +1100,46 @@ extern { | ... | @@ -1100,46 +1100,46 @@ extern { |
| 1100 | fn b(); | 1100 | fn b(); |
| 1101 | } | 1101 | } |
| 1102 | #bogus2("") | 1102 | #bogus2("") |
| 1103 | fn a() {} | 1103 | fn a() => {} |
| 1104 | )SOURCE", 2, ".tmp_source.zig:2:1: error: invalid directive: 'bogus1'", | 1104 | )SOURCE", 2, ".tmp_source.zig:2:1: error: invalid directive: 'bogus1'", |
| 1105 | ".tmp_source.zig:6:1: error: invalid directive: 'bogus2'"); | 1105 | ".tmp_source.zig:6:1: error: invalid directive: 'bogus2'"); |
| 1106 | 1106 | ||
| 1107 | add_compile_fail_case("unreachable with return", R"SOURCE( | 1107 | add_compile_fail_case("unreachable with return", R"SOURCE( |
| 1108 | fn a() -> unreachable {return;} | 1108 | fn a() unreachable => {return;} |
| 1109 | )SOURCE", 1, ".tmp_source.zig:2:24: error: expected type 'unreachable', got 'void'"); | 1109 | )SOURCE", 1, ".tmp_source.zig:2:24: error: expected type 'unreachable', got 'void'"); |
| 1110 | 1110 | ||
| 1111 | add_compile_fail_case("control reaches end of non-void function", R"SOURCE( | 1111 | add_compile_fail_case("control reaches end of non-void function", R"SOURCE( |
| 1112 | fn a() -> i32 {} | 1112 | fn a() i32 => {} |
| 1113 | )SOURCE", 1, ".tmp_source.zig:2:15: error: expected type 'i32', got 'void'"); | 1113 | )SOURCE", 1, ".tmp_source.zig:2:15: error: expected type 'i32', got 'void'"); |
| 1114 | 1114 | ||
| 1115 | add_compile_fail_case("undefined function call", R"SOURCE( | 1115 | add_compile_fail_case("undefined function call", R"SOURCE( |
| 1116 | fn a() { | 1116 | fn a() => { |
| 1117 | b(); | 1117 | b(); |
| 1118 | } | 1118 | } |
| 1119 | )SOURCE", 1, ".tmp_source.zig:3:5: error: undefined function: 'b'"); | 1119 | )SOURCE", 1, ".tmp_source.zig:3:5: error: undefined function: 'b'"); |
| 1120 | 1120 | ||
| 1121 | add_compile_fail_case("wrong number of arguments", R"SOURCE( | 1121 | add_compile_fail_case("wrong number of arguments", R"SOURCE( |
| 1122 | fn a() { | 1122 | fn a() => { |
| 1123 | b(1); | 1123 | b(1); |
| 1124 | } | 1124 | } |
| 1125 | fn b(a: i32, b: i32, c: i32) { } | 1125 | fn b(a: i32, b: i32, c: i32) => { } |
| 1126 | )SOURCE", 1, ".tmp_source.zig:3:6: error: expected 3 arguments, got 1"); | 1126 | )SOURCE", 1, ".tmp_source.zig:3:6: error: expected 3 arguments, got 1"); |
| 1127 | 1127 | ||
| 1128 | add_compile_fail_case("invalid type", R"SOURCE( | 1128 | add_compile_fail_case("invalid type", R"SOURCE( |
| 1129 | fn a() -> bogus {} | 1129 | fn a() bogus => {} |
| 1130 | )SOURCE", 1, ".tmp_source.zig:2:11: error: invalid type name: 'bogus'"); | 1130 | )SOURCE", 1, ".tmp_source.zig:2:8: error: use of undeclared identifier 'bogus'"); |
| 1131 | 1131 | ||
| 1132 | add_compile_fail_case("pointer to unreachable", R"SOURCE( | 1132 | add_compile_fail_case("pointer to unreachable", R"SOURCE( |
| 1133 | fn a() -> &unreachable {} | 1133 | fn a() &unreachable => {} |
| 1134 | )SOURCE", 1, ".tmp_source.zig:2:11: error: pointer to unreachable not allowed"); | 1134 | )SOURCE", 1, ".tmp_source.zig:2:8: error: pointer to unreachable not allowed"); |
| 1135 | 1135 | ||
| 1136 | add_compile_fail_case("unreachable code", R"SOURCE( | 1136 | add_compile_fail_case("unreachable code", R"SOURCE( |
| 1137 | fn a() { | 1137 | fn a() => { |
| 1138 | return; | 1138 | return; |
| 1139 | b(); | 1139 | b(); |
| 1140 | } | 1140 | } |
| 1141 | 1141 | ||
| 1142 | fn b() {} | 1142 | fn b() => {} |
| 1143 | )SOURCE", 1, ".tmp_source.zig:4:5: error: unreachable code"); | 1143 | )SOURCE", 1, ".tmp_source.zig:4:5: error: unreachable code"); |
| 1144 | 1144 | ||
| 1145 | add_compile_fail_case("bad version string", R"SOURCE( | 1145 | add_compile_fail_case("bad version string", R"SOURCE( |
| ... | @@ -1152,7 +1152,7 @@ use "bogus-does-not-exist.zig"; | ... | @@ -1152,7 +1152,7 @@ use "bogus-does-not-exist.zig"; |
| 1152 | )SOURCE", 1, ".tmp_source.zig:2:1: error: unable to find 'bogus-does-not-exist.zig'"); | 1152 | )SOURCE", 1, ".tmp_source.zig:2:1: error: unable to find 'bogus-does-not-exist.zig'"); |
| 1153 | 1153 | ||
| 1154 | add_compile_fail_case("undeclared identifier", R"SOURCE( | 1154 | add_compile_fail_case("undeclared identifier", R"SOURCE( |
| 1155 | fn a() { | 1155 | fn a() => { |
| 1156 | b + | 1156 | b + |
| 1157 | c | 1157 | c |
| 1158 | } | 1158 | } |
| ... | @@ -1161,99 +1161,99 @@ fn a() { | ... | @@ -1161,99 +1161,99 @@ fn a() { |
| 1161 | ".tmp_source.zig:4:5: error: use of undeclared identifier 'c'"); | 1161 | ".tmp_source.zig:4:5: error: use of undeclared identifier 'c'"); |
| 1162 | 1162 | ||
| 1163 | add_compile_fail_case("goto cause unreachable code", R"SOURCE( | 1163 | add_compile_fail_case("goto cause unreachable code", R"SOURCE( |
| 1164 | fn a() { | 1164 | fn a() => { |
| 1165 | goto done; | 1165 | goto done; |
| 1166 | b(); | 1166 | b(); |
| 1167 | done: | 1167 | done: |
| 1168 | return; | 1168 | return; |
| 1169 | } | 1169 | } |
| 1170 | fn b() {} | 1170 | fn b() => {} |
| 1171 | )SOURCE", 1, ".tmp_source.zig:4:5: error: unreachable code"); | 1171 | )SOURCE", 1, ".tmp_source.zig:4:5: error: unreachable code"); |
| 1172 | 1172 | ||
| 1173 | add_compile_fail_case("parameter redeclaration", R"SOURCE( | 1173 | add_compile_fail_case("parameter redeclaration", R"SOURCE( |
| 1174 | fn f(a : i32, a : i32) { | 1174 | fn f(a : i32, a : i32) => { |
| 1175 | } | 1175 | } |
| 1176 | )SOURCE", 1, ".tmp_source.zig:2:1: error: redeclaration of parameter 'a'"); | 1176 | )SOURCE", 1, ".tmp_source.zig:2:1: error: redeclaration of parameter 'a'"); |
| 1177 | 1177 | ||
| 1178 | add_compile_fail_case("local variable redeclaration", R"SOURCE( | 1178 | add_compile_fail_case("local variable redeclaration", R"SOURCE( |
| 1179 | fn f() { | 1179 | fn f() => { |
| 1180 | const a : i32 = 0; | 1180 | const a : i32 = 0; |
| 1181 | const a = 0; | 1181 | const a = 0; |
| 1182 | } | 1182 | } |
| 1183 | )SOURCE", 1, ".tmp_source.zig:4:5: error: redeclaration of variable 'a'"); | 1183 | )SOURCE", 1, ".tmp_source.zig:4:5: error: redeclaration of variable 'a'"); |
| 1184 | 1184 | ||
| 1185 | add_compile_fail_case("local variable redeclares parameter", R"SOURCE( | 1185 | add_compile_fail_case("local variable redeclares parameter", R"SOURCE( |
| 1186 | fn f(a : i32) { | 1186 | fn f(a : i32) => { |
| 1187 | const a = 0; | 1187 | const a = 0; |
| 1188 | } | 1188 | } |
| 1189 | )SOURCE", 1, ".tmp_source.zig:3:5: error: redeclaration of variable 'a'"); | 1189 | )SOURCE", 1, ".tmp_source.zig:3:5: error: redeclaration of variable 'a'"); |
| 1190 | 1190 | ||
| 1191 | add_compile_fail_case("variable has wrong type", R"SOURCE( | 1191 | add_compile_fail_case("variable has wrong type", R"SOURCE( |
| 1192 | fn f() -> i32 { | 1192 | fn f() i32 => { |
| 1193 | const a = c"a"; | 1193 | const a = c"a"; |
| 1194 | a | 1194 | a |
| 1195 | } | 1195 | } |
| 1196 | )SOURCE", 1, ".tmp_source.zig:2:15: error: expected type 'i32', got '&const u8'"); | 1196 | )SOURCE", 1, ".tmp_source.zig:2:15: error: expected type 'i32', got '&const u8'"); |
| 1197 | 1197 | ||
| 1198 | add_compile_fail_case("if condition is bool, not int", R"SOURCE( | 1198 | add_compile_fail_case("if condition is bool, not int", R"SOURCE( |
| 1199 | fn f() { | 1199 | fn f() => { |
| 1200 | if (0) {} | 1200 | if (0) {} |
| 1201 | } | 1201 | } |
| 1202 | )SOURCE", 1, ".tmp_source.zig:3:9: error: expected type 'bool', got '(u8 literal)'"); | 1202 | )SOURCE", 1, ".tmp_source.zig:3:9: error: expected type 'bool', got '(u8 literal)'"); |
| 1203 | 1203 | ||
| 1204 | add_compile_fail_case("assign unreachable", R"SOURCE( | 1204 | add_compile_fail_case("assign unreachable", R"SOURCE( |
| 1205 | fn f() { | 1205 | fn f() => { |
| 1206 | const a = return; | 1206 | const a = return; |
| 1207 | } | 1207 | } |
| 1208 | )SOURCE", 1, ".tmp_source.zig:3:5: error: variable initialization is unreachable"); | 1208 | )SOURCE", 1, ".tmp_source.zig:3:5: error: variable initialization is unreachable"); |
| 1209 | 1209 | ||
| 1210 | add_compile_fail_case("unreachable variable", R"SOURCE( | 1210 | add_compile_fail_case("unreachable variable", R"SOURCE( |
| 1211 | fn f() { | 1211 | fn f() => { |
| 1212 | const a : unreachable = return; | 1212 | const a : unreachable = return; |
| 1213 | } | 1213 | } |
| 1214 | )SOURCE", 1, ".tmp_source.zig:3:15: error: variable of type 'unreachable' not allowed"); | 1214 | )SOURCE", 1, ".tmp_source.zig:3:15: error: variable of type 'unreachable' not allowed"); |
| 1215 | 1215 | ||
| 1216 | add_compile_fail_case("unreachable parameter", R"SOURCE( | 1216 | add_compile_fail_case("unreachable parameter", R"SOURCE( |
| 1217 | fn f(a : unreachable) {} | 1217 | fn f(a : unreachable) => {} |
| 1218 | )SOURCE", 1, ".tmp_source.zig:2:10: error: parameter of type 'unreachable' not allowed"); | 1218 | )SOURCE", 1, ".tmp_source.zig:2:10: error: parameter of type 'unreachable' not allowed"); |
| 1219 | 1219 | ||
| 1220 | add_compile_fail_case("exporting a void parameter", R"SOURCE( | 1220 | add_compile_fail_case("exporting a void parameter", R"SOURCE( |
| 1221 | export fn f(a : void) {} | 1221 | export fn f(a : void) => {} |
| 1222 | )SOURCE", 1, ".tmp_source.zig:2:17: error: parameter of type 'void' not allowed on exported functions"); | 1222 | )SOURCE", 1, ".tmp_source.zig:2:17: error: parameter of type 'void' not allowed on exported functions"); |
| 1223 | 1223 | ||
| 1224 | add_compile_fail_case("unused label", R"SOURCE( | 1224 | add_compile_fail_case("unused label", R"SOURCE( |
| 1225 | fn f() { | 1225 | fn f() => { |
| 1226 | a_label: | 1226 | a_label: |
| 1227 | } | 1227 | } |
| 1228 | )SOURCE", 1, ".tmp_source.zig:3:1: error: label 'a_label' defined but not used"); | 1228 | )SOURCE", 1, ".tmp_source.zig:3:1: error: label 'a_label' defined but not used"); |
| 1229 | 1229 | ||
| 1230 | add_compile_fail_case("bad assignment target", R"SOURCE( | 1230 | add_compile_fail_case("bad assignment target", R"SOURCE( |
| 1231 | fn f() { | 1231 | fn f() => { |
| 1232 | 3 = 3; | 1232 | 3 = 3; |
| 1233 | } | 1233 | } |
| 1234 | )SOURCE", 1, ".tmp_source.zig:3:5: error: invalid assignment target"); | 1234 | )SOURCE", 1, ".tmp_source.zig:3:5: error: invalid assignment target"); |
| 1235 | 1235 | ||
| 1236 | add_compile_fail_case("assign to constant variable", R"SOURCE( | 1236 | add_compile_fail_case("assign to constant variable", R"SOURCE( |
| 1237 | fn f() { | 1237 | fn f() => { |
| 1238 | const a = 3; | 1238 | const a = 3; |
| 1239 | a = 4; | 1239 | a = 4; |
| 1240 | } | 1240 | } |
| 1241 | )SOURCE", 1, ".tmp_source.zig:4:5: error: cannot assign to constant"); | 1241 | )SOURCE", 1, ".tmp_source.zig:4:5: error: cannot assign to constant"); |
| 1242 | 1242 | ||
| 1243 | add_compile_fail_case("use of undeclared identifier", R"SOURCE( | 1243 | add_compile_fail_case("use of undeclared identifier", R"SOURCE( |
| 1244 | fn f() { | 1244 | fn f() => { |
| 1245 | b = 3; | 1245 | b = 3; |
| 1246 | } | 1246 | } |
| 1247 | )SOURCE", 1, ".tmp_source.zig:3:5: error: use of undeclared identifier 'b'"); | 1247 | )SOURCE", 1, ".tmp_source.zig:3:5: error: use of undeclared identifier 'b'"); |
| 1248 | 1248 | ||
| 1249 | add_compile_fail_case("const is a statement, not an expression", R"SOURCE( | 1249 | add_compile_fail_case("const is a statement, not an expression", R"SOURCE( |
| 1250 | fn f() { | 1250 | fn f() => { |
| 1251 | (const a = 0); | 1251 | (const a = 0); |
| 1252 | } | 1252 | } |
| 1253 | )SOURCE", 1, ".tmp_source.zig:3:6: error: invalid token: 'const'"); | 1253 | )SOURCE", 1, ".tmp_source.zig:3:6: error: invalid token: 'const'"); |
| 1254 | 1254 | ||
| 1255 | add_compile_fail_case("array access errors", R"SOURCE( | 1255 | add_compile_fail_case("array access errors", R"SOURCE( |
| 1256 | fn f() { | 1256 | fn f() => { |
| 1257 | var bad : bool; | 1257 | var bad : bool; |
| 1258 | i[i] = i[i]; | 1258 | i[i] = i[i]; |
| 1259 | bad[bad] = bad[bad]; | 1259 | bad[bad] = bad[bad]; |
| ... | @@ -1268,19 +1268,19 @@ fn f() { | ... | @@ -1268,19 +1268,19 @@ fn f() { |
| 1268 | ".tmp_source.zig:5:20: error: expected type 'usize', got 'bool'"); | 1268 | ".tmp_source.zig:5:20: error: expected type 'usize', got 'bool'"); |
| 1269 | 1269 | ||
| 1270 | add_compile_fail_case("variadic functions only allowed in extern", R"SOURCE( | 1270 | add_compile_fail_case("variadic functions only allowed in extern", R"SOURCE( |
| 1271 | fn f(...) {} | 1271 | fn f(...) => {} |
| 1272 | )SOURCE", 1, ".tmp_source.zig:2:1: error: variadic arguments only allowed in extern functions"); | 1272 | )SOURCE", 1, ".tmp_source.zig:2:1: error: variadic arguments only allowed in extern functions"); |
| 1273 | 1273 | ||
| 1274 | add_compile_fail_case("write to const global variable", R"SOURCE( | 1274 | add_compile_fail_case("write to const global variable", R"SOURCE( |
| 1275 | const x : i32 = 99; | 1275 | const x : i32 = 99; |
| 1276 | fn f() { | 1276 | fn f() => { |
| 1277 | x = 1; | 1277 | x = 1; |
| 1278 | } | 1278 | } |
| 1279 | )SOURCE", 1, ".tmp_source.zig:4:5: error: cannot assign to constant"); | 1279 | )SOURCE", 1, ".tmp_source.zig:4:5: error: cannot assign to constant"); |
| 1280 | 1280 | ||
| 1281 | 1281 | ||
| 1282 | add_compile_fail_case("missing else clause", R"SOURCE( | 1282 | add_compile_fail_case("missing else clause", R"SOURCE( |
| 1283 | fn f() { | 1283 | fn f() => { |
| 1284 | const x : i32 = if (true) { 1 }; | 1284 | const x : i32 = if (true) { 1 }; |
| 1285 | const y = if (true) { 1 as i32 }; | 1285 | const y = if (true) { 1 as i32 }; |
| 1286 | } | 1286 | } |
| ... | @@ -1299,7 +1299,7 @@ struct C { a : A, } | ... | @@ -1299,7 +1299,7 @@ struct C { a : A, } |
| 1299 | 1299 | ||
| 1300 | add_compile_fail_case("invalid struct field", R"SOURCE( | 1300 | add_compile_fail_case("invalid struct field", R"SOURCE( |
| 1301 | struct A { x : i32, } | 1301 | struct A { x : i32, } |
| 1302 | fn f() { | 1302 | fn f() => { |
| 1303 | var a : A; | 1303 | var a : A; |
| 1304 | a.foo = 1; | 1304 | a.foo = 1; |
| 1305 | const y = a.bar; | 1305 | const y = a.bar; |
| ... | @@ -1315,7 +1315,7 @@ struct A { y : i32, } | ... | @@ -1315,7 +1315,7 @@ struct A { y : i32, } |
| 1315 | 1315 | ||
| 1316 | add_compile_fail_case("byvalue struct on exported functions", R"SOURCE( | 1316 | add_compile_fail_case("byvalue struct on exported functions", R"SOURCE( |
| 1317 | struct A { x : i32, } | 1317 | struct A { x : i32, } |
| 1318 | export fn f(a : A) {} | 1318 | export fn f(a : A) => {} |
| 1319 | )SOURCE", 1, ".tmp_source.zig:3:13: error: byvalue struct parameters not yet supported on exported functions"); | 1319 | )SOURCE", 1, ".tmp_source.zig:3:13: error: byvalue struct parameters not yet supported on exported functions"); |
| 1320 | 1320 | ||
| 1321 | add_compile_fail_case("duplicate field in struct value expression", R"SOURCE( | 1321 | add_compile_fail_case("duplicate field in struct value expression", R"SOURCE( |
| ... | @@ -1324,7 +1324,7 @@ struct A { | ... | @@ -1324,7 +1324,7 @@ struct A { |
| 1324 | y : i32, | 1324 | y : i32, |
| 1325 | z : i32, | 1325 | z : i32, |
| 1326 | } | 1326 | } |
| 1327 | fn f() { | 1327 | fn f() => { |
| 1328 | const a = A { | 1328 | const a = A { |
| 1329 | .z = 1, | 1329 | .z = 1, |
| 1330 | .y = 2, | 1330 | .y = 2, |
| ... | @@ -1340,13 +1340,13 @@ struct A { | ... | @@ -1340,13 +1340,13 @@ struct A { |
| 1340 | y : i32, | 1340 | y : i32, |
| 1341 | z : i32, | 1341 | z : i32, |
| 1342 | } | 1342 | } |
| 1343 | fn f() { | 1343 | fn f() => { |
| 1344 | const a = A { | 1344 | const a = A { |
| 1345 | .z = 4, | 1345 | .z = 4, |
| 1346 | .y = 2, | 1346 | .y = 2, |
| 1347 | }; | 1347 | }; |
| 1348 | } | 1348 | } |
| 1349 | )SOURCE", 1, ".tmp_source.zig:8:15: error: missing field: 'x'"); | 1349 | )SOURCE", 1, ".tmp_source.zig:8:17: error: missing field: 'x'"); |
| 1350 | 1350 | ||
| 1351 | add_compile_fail_case("invalid field in struct value expression", R"SOURCE( | 1351 | add_compile_fail_case("invalid field in struct value expression", R"SOURCE( |
| 1352 | struct A { | 1352 | struct A { |
| ... | @@ -1354,7 +1354,7 @@ struct A { | ... | @@ -1354,7 +1354,7 @@ struct A { |
| 1354 | y : i32, | 1354 | y : i32, |
| 1355 | z : i32, | 1355 | z : i32, |
| 1356 | } | 1356 | } |
| 1357 | fn f() { | 1357 | fn f() => { |
| 1358 | const a = A { | 1358 | const a = A { |
| 1359 | .z = 4, | 1359 | .z = 4, |
| 1360 | .y = 2, | 1360 | .y = 2, |
| ... | @@ -1364,37 +1364,37 @@ fn f() { | ... | @@ -1364,37 +1364,37 @@ fn f() { |
| 1364 | )SOURCE", 1, ".tmp_source.zig:11:9: error: no member named 'foo' in 'A'"); | 1364 | )SOURCE", 1, ".tmp_source.zig:11:9: error: no member named 'foo' in 'A'"); |
| 1365 | 1365 | ||
| 1366 | add_compile_fail_case("invalid break expression", R"SOURCE( | 1366 | add_compile_fail_case("invalid break expression", R"SOURCE( |
| 1367 | fn f() { | 1367 | fn f() => { |
| 1368 | break; | 1368 | break; |
| 1369 | } | 1369 | } |
| 1370 | )SOURCE", 1, ".tmp_source.zig:3:5: error: 'break' expression outside loop"); | 1370 | )SOURCE", 1, ".tmp_source.zig:3:5: error: 'break' expression outside loop"); |
| 1371 | 1371 | ||
| 1372 | add_compile_fail_case("invalid continue expression", R"SOURCE( | 1372 | add_compile_fail_case("invalid continue expression", R"SOURCE( |
| 1373 | fn f() { | 1373 | fn f() => { |
| 1374 | continue; | 1374 | continue; |
| 1375 | } | 1375 | } |
| 1376 | )SOURCE", 1, ".tmp_source.zig:3:5: error: 'continue' expression outside loop"); | 1376 | )SOURCE", 1, ".tmp_source.zig:3:5: error: 'continue' expression outside loop"); |
| 1377 | 1377 | ||
| 1378 | add_compile_fail_case("invalid maybe type", R"SOURCE( | 1378 | add_compile_fail_case("invalid maybe type", R"SOURCE( |
| 1379 | fn f() { | 1379 | fn f() => { |
| 1380 | if (const x ?= true) { } | 1380 | if (const x ?= true) { } |
| 1381 | } | 1381 | } |
| 1382 | )SOURCE", 1, ".tmp_source.zig:3:20: error: expected maybe type"); | 1382 | )SOURCE", 1, ".tmp_source.zig:3:20: error: expected maybe type"); |
| 1383 | 1383 | ||
| 1384 | add_compile_fail_case("cast unreachable", R"SOURCE( | 1384 | add_compile_fail_case("cast unreachable", R"SOURCE( |
| 1385 | fn f() -> i32 { | 1385 | fn f() i32 => { |
| 1386 | (return 1) as i32 | 1386 | (return 1) as i32 |
| 1387 | } | 1387 | } |
| 1388 | )SOURCE", 1, ".tmp_source.zig:3:16: error: invalid cast from type 'unreachable' to 'i32'"); | 1388 | )SOURCE", 1, ".tmp_source.zig:3:16: error: invalid cast from type 'unreachable' to 'i32'"); |
| 1389 | 1389 | ||
| 1390 | add_compile_fail_case("invalid compiler fn", R"SOURCE( | 1390 | add_compile_fail_case("invalid builtin fn", R"SOURCE( |
| 1391 | fn f() -> #bogus(foo) { | 1391 | fn f() @bogus(foo) => { |
| 1392 | } | 1392 | } |
| 1393 | )SOURCE", 1, ".tmp_source.zig:2:11: error: invalid compiler function: 'bogus'"); | 1393 | )SOURCE", 1, ".tmp_source.zig:2:8: error: invalid builtin function: 'bogus'"); |
| 1394 | 1394 | ||
| 1395 | add_compile_fail_case("top level decl dependency loop", R"SOURCE( | 1395 | add_compile_fail_case("top level decl dependency loop", R"SOURCE( |
| 1396 | const a : #typeof(b) = 0; | 1396 | const a : @typeof(b) = 0; |
| 1397 | const b : #typeof(a) = 0; | 1397 | const b : @typeof(a) = 0; |
| 1398 | )SOURCE", 1, ".tmp_source.zig:3:19: error: use of undeclared identifier 'a'"); | 1398 | )SOURCE", 1, ".tmp_source.zig:3:19: error: use of undeclared identifier 'a'"); |
| 1399 | } | 1399 | } |
| 1400 | 1400 |