| author | |
| committer | |
| log | 304941026013e6310c9362849610c32d98d1332a |
| tree | e1c82472dfe7e887020b306dbd37aa89491426a5 |
| parent | 8b727557d31714e87e489522f452cef9880ba30d |
closes #349 files changed, 82 insertions(+), 92 deletions(-)
doc/langref.md+1-1| ... | ... | @@ -70,7 +70,7 @@ Statement : Label | VariableDeclaration token(Semicolon) | NonBlockExpression to |
| 70 | 70 | |
| 71 | 71 | Label: token(Symbol) token(Colon) |
| 72 | 72 | |
| 73 | VariableDeclaration : token(Let) option(token(Mut)) token(Symbol) (token(Eq) Expression | token(Colon) Type option(token(Eq) Expression)) | |
| 73 | VariableDeclaration : (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) Type option(token(Eq) Expression)) | |
| 74 | 74 | |
| 75 | 75 | Expression : BlockExpression | NonBlockExpression |
| 76 | 76 |
example/arrays/arrays.zig+3-3| ... | ... | @@ -3,9 +3,9 @@ export executable "arrays"; |
| 3 | 3 | use "std.zig"; |
| 4 | 4 | |
| 5 | 5 | export fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { |
| 6 | let mut array : [i32; 5]; | |
| 6 | var array : [i32; 5]; | |
| 7 | 7 | |
| 8 | let mut i : i32 = 0; | |
| 8 | var i : i32 = 0; | |
| 9 | 9 | loop_start: |
| 10 | 10 | if i == 5 { |
| 11 | 11 | goto loop_end; |
| ... | ... | @@ -17,7 +17,7 @@ loop_start: |
| 17 | 17 | loop_end: |
| 18 | 18 | |
| 19 | 19 | i = 0; |
| 20 | let mut accumulator : i32 = 0; | |
| 20 | var accumulator : i32 = 0; | |
| 21 | 21 | loop_2_start: |
| 22 | 22 | if i == 5 { |
| 23 | 23 | goto loop_2_end; |
example/expressions/expressions.zig+12-12| ... | ... | @@ -13,17 +13,17 @@ fn other_exit() -> unreachable { |
| 13 | 13 | } |
| 14 | 14 | |
| 15 | 15 | export fn _start() -> unreachable { |
| 16 | let a : i32 = 1; | |
| 17 | let b = 2 as i32; | |
| 18 | // let c : i32; // not yet support for const variables | |
| 19 | // let d; // parse error | |
| 16 | const a : i32 = 1; | |
| 17 | const b = 2 as i32; | |
| 18 | // const c : i32; // not yet support for const variables | |
| 19 | // const d; // parse error | |
| 20 | 20 | if (a + b == 3) { |
| 21 | let no_conflict : i32 = 5; | |
| 21 | const no_conflict : i32 = 5; | |
| 22 | 22 | if (no_conflict == 5) { puts(c"OK 1"); } |
| 23 | 23 | } |
| 24 | 24 | |
| 25 | let c = { | |
| 26 | let no_conflict : i32 = 10; | |
| 25 | const c = { | |
| 26 | const no_conflict : i32 = 10; | |
| 27 | 27 | no_conflict |
| 28 | 28 | }; |
| 29 | 29 | if (c == 10) { puts(c"OK 2"); } |
| ... | ... | @@ -36,15 +36,15 @@ export fn _start() -> unreachable { |
| 36 | 36 | } |
| 37 | 37 | |
| 38 | 38 | fn void_fun(a : i32, b : void, c : i32) -> void { |
| 39 | let x = a + 1; // i32 | |
| 40 | let y = c + 1; // i32 | |
| 41 | let z = b; // void | |
| 42 | let w : void = z; // void | |
| 39 | const x = a + 1; // i32 | |
| 40 | const y = c + 1; // i32 | |
| 41 | const z = b; // void | |
| 42 | const w : void = z; // void | |
| 43 | 43 | if (x + y == 4) { return w; } |
| 44 | 44 | } |
| 45 | 45 | |
| 46 | 46 | fn test_mutable_vars() { |
| 47 | let mut i : i32 = 0; | |
| 47 | var i : i32 = 0; | |
| 48 | 48 | loop_start: |
| 49 | 49 | if i == 3 { |
| 50 | 50 | goto done; |
example/structs/structs.zig+1-1| ... | ... | @@ -3,7 +3,7 @@ export executable "structs"; |
| 3 | 3 | use "std.zig"; |
| 4 | 4 | |
| 5 | 5 | export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { |
| 6 | let mut foo : Foo; | |
| 6 | var foo : Foo; | |
| 7 | 7 | |
| 8 | 8 | foo.a = foo.a + 1; |
| 9 | 9 |
src/parser.cpp+32-38| ... | ... | @@ -1561,53 +1561,47 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool m |
| 1561 | 1561 | } |
| 1562 | 1562 | |
| 1563 | 1563 | /* |
| 1564 | VariableDeclaration : token(Let) option(token(Mut)) token(Symbol) (token(Eq) Expression | token(Colon) Type option(token(Eq) Expression)) | |
| 1564 | VariableDeclaration : (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) Type option(token(Eq) Expression)) | |
| 1565 | 1565 | */ |
| 1566 | 1566 | static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token_index, bool mandatory) { |
| 1567 | Token *let_tok = &pc->tokens->at(*token_index); | |
| 1568 | if (let_tok->id == TokenIdKeywordLet) { | |
| 1569 | *token_index += 1; | |
| 1570 | AstNode *node = ast_create_node(pc, NodeTypeVariableDeclaration, let_tok); | |
| 1567 | Token *var_or_const_tok = &pc->tokens->at(*token_index); | |
| 1571 | 1568 | |
| 1572 | Token *name_token; | |
| 1573 | Token *token = &pc->tokens->at(*token_index); | |
| 1574 | if (token->id == TokenIdKeywordMut) { | |
| 1575 | node->data.variable_declaration.is_const = false; | |
| 1576 | *token_index += 1; | |
| 1577 | name_token = &pc->tokens->at(*token_index); | |
| 1578 | ast_expect_token(pc, name_token, TokenIdSymbol); | |
| 1579 | } else if (token->id == TokenIdSymbol) { | |
| 1580 | node->data.variable_declaration.is_const = true; | |
| 1581 | name_token = token; | |
| 1582 | } else { | |
| 1583 | ast_invalid_token_error(pc, token); | |
| 1584 | } | |
| 1569 | bool is_const; | |
| 1570 | if (var_or_const_tok->id == TokenIdKeywordVar) { | |
| 1571 | is_const = false; | |
| 1572 | } else if (var_or_const_tok->id == TokenIdKeywordConst) { | |
| 1573 | is_const = true; | |
| 1574 | } else if (mandatory) { | |
| 1575 | ast_invalid_token_error(pc, var_or_const_tok); | |
| 1576 | } else { | |
| 1577 | return nullptr; | |
| 1578 | } | |
| 1585 | 1579 | |
| 1586 | *token_index += 1; | |
| 1587 | ast_buf_from_token(pc, name_token, &node->data.variable_declaration.symbol); | |
| 1580 | *token_index += 1; | |
| 1581 | AstNode *node = ast_create_node(pc, NodeTypeVariableDeclaration, var_or_const_tok); | |
| 1588 | 1582 | |
| 1589 | Token *eq_or_colon = &pc->tokens->at(*token_index); | |
| 1590 | *token_index += 1; | |
| 1591 | if (eq_or_colon->id == TokenIdEq) { | |
| 1592 | node->data.variable_declaration.expr = ast_parse_expression(pc, token_index, true); | |
| 1593 | return node; | |
| 1594 | } else if (eq_or_colon->id == TokenIdColon) { | |
| 1595 | node->data.variable_declaration.type = ast_parse_type(pc, token_index); | |
| 1583 | node->data.variable_declaration.is_const = is_const; | |
| 1596 | 1584 | |
| 1597 | Token *eq_token = &pc->tokens->at(*token_index); | |
| 1598 | if (eq_token->id == TokenIdEq) { | |
| 1599 | *token_index += 1; | |
| 1585 | Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol); | |
| 1586 | ast_buf_from_token(pc, name_token, &node->data.variable_declaration.symbol); | |
| 1600 | 1587 | |
| 1601 | node->data.variable_declaration.expr = ast_parse_expression(pc, token_index, true); | |
| 1602 | } | |
| 1603 | return node; | |
| 1604 | } else { | |
| 1605 | ast_invalid_token_error(pc, eq_or_colon); | |
| 1588 | Token *eq_or_colon = &pc->tokens->at(*token_index); | |
| 1589 | *token_index += 1; | |
| 1590 | if (eq_or_colon->id == TokenIdEq) { | |
| 1591 | node->data.variable_declaration.expr = ast_parse_expression(pc, token_index, true); | |
| 1592 | return node; | |
| 1593 | } else if (eq_or_colon->id == TokenIdColon) { | |
| 1594 | node->data.variable_declaration.type = ast_parse_type(pc, token_index); | |
| 1595 | ||
| 1596 | Token *eq_token = &pc->tokens->at(*token_index); | |
| 1597 | if (eq_token->id == TokenIdEq) { | |
| 1598 | *token_index += 1; | |
| 1599 | ||
| 1600 | node->data.variable_declaration.expr = ast_parse_expression(pc, token_index, true); | |
| 1606 | 1601 | } |
| 1607 | } else if (mandatory) { | |
| 1608 | ast_invalid_token_error(pc, let_tok); | |
| 1602 | return node; | |
| 1609 | 1603 | } else { |
| 1610 | return nullptr; | |
| 1604 | ast_invalid_token_error(pc, eq_or_colon); | |
| 1611 | 1605 | } |
| 1612 | 1606 | } |
| 1613 | 1607 |
src/tokenizer.cpp+3-6| ... | ... | @@ -179,10 +179,8 @@ static void end_token(Tokenize *t) { |
| 179 | 179 | t->cur_tok->id = TokenIdKeywordFn; |
| 180 | 180 | } else if (mem_eql_str(token_mem, token_len, "return")) { |
| 181 | 181 | t->cur_tok->id = TokenIdKeywordReturn; |
| 182 | } else if (mem_eql_str(token_mem, token_len, "let")) { | |
| 183 | t->cur_tok->id = TokenIdKeywordLet; | |
| 184 | } else if (mem_eql_str(token_mem, token_len, "mut")) { | |
| 185 | t->cur_tok->id = TokenIdKeywordMut; | |
| 182 | } else if (mem_eql_str(token_mem, token_len, "var")) { | |
| 183 | t->cur_tok->id = TokenIdKeywordVar; | |
| 186 | 184 | } else if (mem_eql_str(token_mem, token_len, "const")) { |
| 187 | 185 | t->cur_tok->id = TokenIdKeywordConst; |
| 188 | 186 | } else if (mem_eql_str(token_mem, token_len, "extern")) { |
| ... | ... | @@ -797,9 +795,8 @@ static const char * token_name(Token *token) { |
| 797 | 795 | case TokenIdSymbol: return "Symbol"; |
| 798 | 796 | case TokenIdKeywordFn: return "Fn"; |
| 799 | 797 | case TokenIdKeywordConst: return "Const"; |
| 800 | case TokenIdKeywordMut: return "Mut"; | |
| 798 | case TokenIdKeywordVar: return "Var"; | |
| 801 | 799 | case TokenIdKeywordReturn: return "Return"; |
| 802 | case TokenIdKeywordLet: return "Let"; | |
| 803 | 800 | case TokenIdKeywordExtern: return "Extern"; |
| 804 | 801 | case TokenIdKeywordUnreachable: return "Unreachable"; |
| 805 | 802 | case TokenIdKeywordPub: return "Pub"; |
src/tokenizer.hpp+1-2| ... | ... | @@ -15,8 +15,7 @@ enum TokenId { |
| 15 | 15 | TokenIdSymbol, |
| 16 | 16 | TokenIdKeywordFn, |
| 17 | 17 | TokenIdKeywordReturn, |
| 18 | TokenIdKeywordLet, | |
| 19 | TokenIdKeywordMut, | |
| 18 | TokenIdKeywordVar, | |
| 20 | 19 | TokenIdKeywordConst, |
| 21 | 20 | TokenIdKeywordExtern, |
| 22 | 21 | TokenIdKeywordUnreachable, |
std/std.zig+3-3| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize { |
| 2 | let mut result : isize; | |
| 2 | var result : isize; | |
| 3 | 3 | asm volatile (" |
| 4 | 4 | mov %[number], %%rax |
| 5 | 5 | mov %[arg1], %%rdi |
| ... | ... | @@ -15,13 +15,13 @@ fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize { |
| 15 | 15 | |
| 16 | 16 | // TODO constants for SYS_write and stdout_fileno |
| 17 | 17 | pub fn write(fd: isize, buf: &const u8, count: usize) -> isize { |
| 18 | let SYS_write : isize = 1; | |
| 18 | const SYS_write : isize = 1; | |
| 19 | 19 | return syscall3(SYS_write, fd, buf as isize, count as isize); |
| 20 | 20 | } |
| 21 | 21 | |
| 22 | 22 | // TODO error handling |
| 23 | 23 | // TODO handle buffering and flushing |
| 24 | 24 | pub fn print_str(str : string) -> isize { |
| 25 | let stdout_fileno : isize = 1; | |
| 25 | const stdout_fileno : isize = 1; | |
| 26 | 26 | return write(stdout_fileno, str.ptr, str.len); |
| 27 | 27 | } |
test/run_tests.cpp+26-26| ... | ... | @@ -265,8 +265,8 @@ extern { |
| 265 | 265 | } |
| 266 | 266 | |
| 267 | 267 | export fn _start() -> unreachable { |
| 268 | let a : i32 = 1; | |
| 269 | let b = 2 as i32; | |
| 268 | const a : i32 = 1; | |
| 269 | const b = 2 as i32; | |
| 270 | 270 | if (a + b == 3) { |
| 271 | 271 | puts(c"OK"); |
| 272 | 272 | } |
| ... | ... | @@ -299,12 +299,12 @@ extern { |
| 299 | 299 | |
| 300 | 300 | export fn _start() -> unreachable { |
| 301 | 301 | if (true) { |
| 302 | let no_conflict : i32 = 5; | |
| 302 | const no_conflict : i32 = 5; | |
| 303 | 303 | if (no_conflict == 5) { puts(c"OK 1"); } |
| 304 | 304 | } |
| 305 | 305 | |
| 306 | let c = { | |
| 307 | let no_conflict = 10 as i32; | |
| 306 | const c = { | |
| 307 | const no_conflict = 10 as i32; | |
| 308 | 308 | no_conflict |
| 309 | 309 | }; |
| 310 | 310 | if (c == 10) { puts(c"OK 2"); } |
| ... | ... | @@ -325,8 +325,8 @@ export fn _start() -> unreachable { |
| 325 | 325 | } |
| 326 | 326 | |
| 327 | 327 | fn void_fun(a : i32, b : void, c : i32) { |
| 328 | let v = b; | |
| 329 | let vv : void = if (a == 1) {v} else {}; | |
| 328 | const v = b; | |
| 329 | const vv : void = if (a == 1) {v} else {}; | |
| 330 | 330 | if (a + c == 3) { puts(c"OK"); } |
| 331 | 331 | return vv; |
| 332 | 332 | } |
| ... | ... | @@ -340,10 +340,10 @@ extern { |
| 340 | 340 | } |
| 341 | 341 | |
| 342 | 342 | export fn _start() -> unreachable { |
| 343 | let mut zero : i32; | |
| 343 | var zero : i32; | |
| 344 | 344 | if (zero == 0) { puts(c"zero"); } |
| 345 | 345 | |
| 346 | let mut i = 0 as i32; | |
| 346 | var i = 0 as i32; | |
| 347 | 347 | loop_start: |
| 348 | 348 | if i == 3 { |
| 349 | 349 | goto done; |
| ... | ... | @@ -364,9 +364,9 @@ extern { |
| 364 | 364 | } |
| 365 | 365 | |
| 366 | 366 | export fn _start() -> unreachable { |
| 367 | let mut array : [i32; 5]; | |
| 367 | var array : [i32; 5]; | |
| 368 | 368 | |
| 369 | let mut i : i32 = 0; | |
| 369 | var i : i32 = 0; | |
| 370 | 370 | loop_start: |
| 371 | 371 | if i == 5 { |
| 372 | 372 | goto loop_end; |
| ... | ... | @@ -378,7 +378,7 @@ loop_start: |
| 378 | 378 | loop_end: |
| 379 | 379 | |
| 380 | 380 | i = 0; |
| 381 | let mut accumulator = 0 as i32; | |
| 381 | var accumulator = 0 as i32; | |
| 382 | 382 | loop_2_start: |
| 383 | 383 | if i == 5 { |
| 384 | 384 | goto loop_2_end; |
| ... | ... | @@ -458,7 +458,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { |
| 458 | 458 | use "std.zig"; |
| 459 | 459 | |
| 460 | 460 | export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { |
| 461 | let mut i : i32 = 0; | |
| 461 | var i : i32 = 0; | |
| 462 | 462 | i += 5; if i != 5 { print_str("BAD +=\n" as string); } |
| 463 | 463 | i -= 2; if i != 3 { print_str("BAD -=\n" as string); } |
| 464 | 464 | i *= 20; if i != 60 { print_str("BAD *=\n" as string); } |
| ... | ... | @@ -481,7 +481,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { |
| 481 | 481 | use "std.zig"; |
| 482 | 482 | |
| 483 | 483 | export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { |
| 484 | let mut foo : Foo; | |
| 484 | var foo : Foo; | |
| 485 | 485 | foo.a = foo.a + 1; |
| 486 | 486 | foo.b = foo.a == 1; |
| 487 | 487 | test_foo(foo); |
| ... | ... | @@ -589,20 +589,20 @@ fn f(a : i32, a : i32) { |
| 589 | 589 | |
| 590 | 590 | add_compile_fail_case("local variable redeclaration", R"SOURCE( |
| 591 | 591 | fn f() { |
| 592 | let a : i32 = 0; | |
| 593 | let a = 0; | |
| 592 | const a : i32 = 0; | |
| 593 | const a = 0; | |
| 594 | 594 | } |
| 595 | 595 | )SOURCE", 1, ".tmp_source.zig:4:5: error: redeclaration of variable 'a'"); |
| 596 | 596 | |
| 597 | 597 | add_compile_fail_case("local variable redeclares parameter", R"SOURCE( |
| 598 | 598 | fn f(a : i32) { |
| 599 | let a = 0; | |
| 599 | const a = 0; | |
| 600 | 600 | } |
| 601 | 601 | )SOURCE", 1, ".tmp_source.zig:3:5: error: redeclaration of variable 'a'"); |
| 602 | 602 | |
| 603 | 603 | add_compile_fail_case("variable has wrong type", R"SOURCE( |
| 604 | 604 | fn f() -> i32 { |
| 605 | let a = c"a"; | |
| 605 | const a = c"a"; | |
| 606 | 606 | a |
| 607 | 607 | } |
| 608 | 608 | )SOURCE", 1, ".tmp_source.zig:2:15: error: expected type 'i32', got '&const u8'"); |
| ... | ... | @@ -615,15 +615,15 @@ fn f() { |
| 615 | 615 | |
| 616 | 616 | add_compile_fail_case("assign unreachable", R"SOURCE( |
| 617 | 617 | fn f() { |
| 618 | let a = return; | |
| 618 | const a = return; | |
| 619 | 619 | } |
| 620 | 620 | )SOURCE", 1, ".tmp_source.zig:3:5: error: variable initialization is unreachable"); |
| 621 | 621 | |
| 622 | 622 | add_compile_fail_case("unreachable variable", R"SOURCE( |
| 623 | 623 | fn f() { |
| 624 | let a : unreachable = return; | |
| 624 | const a : unreachable = return; | |
| 625 | 625 | } |
| 626 | )SOURCE", 1, ".tmp_source.zig:3:13: error: variable of type 'unreachable' not allowed"); | |
| 626 | )SOURCE", 1, ".tmp_source.zig:3:15: error: variable of type 'unreachable' not allowed"); | |
| 627 | 627 | |
| 628 | 628 | add_compile_fail_case("unreachable parameter", R"SOURCE( |
| 629 | 629 | fn f(a : unreachable) {} |
| ... | ... | @@ -647,7 +647,7 @@ fn f() { |
| 647 | 647 | |
| 648 | 648 | add_compile_fail_case("assign to constant variable", R"SOURCE( |
| 649 | 649 | fn f() { |
| 650 | let a = 3; | |
| 650 | const a = 3; | |
| 651 | 651 | a = 4; |
| 652 | 652 | } |
| 653 | 653 | )SOURCE", 1, ".tmp_source.zig:4:5: error: cannot assign to constant variable"); |
| ... | ... | @@ -658,15 +658,15 @@ fn f() { |
| 658 | 658 | } |
| 659 | 659 | )SOURCE", 1, ".tmp_source.zig:3:5: error: use of undeclared identifier 'b'"); |
| 660 | 660 | |
| 661 | add_compile_fail_case("let is a statement, not an expression", R"SOURCE( | |
| 661 | add_compile_fail_case("const is a statement, not an expression", R"SOURCE( | |
| 662 | 662 | fn f() { |
| 663 | (let a = 0); | |
| 663 | (const a = 0); | |
| 664 | 664 | } |
| 665 | )SOURCE", 1, ".tmp_source.zig:3:6: error: invalid token: 'let'"); | |
| 665 | )SOURCE", 1, ".tmp_source.zig:3:6: error: invalid token: 'const'"); | |
| 666 | 666 | |
| 667 | 667 | add_compile_fail_case("array access errors", R"SOURCE( |
| 668 | 668 | fn f() { |
| 669 | let mut bad : bool; | |
| 669 | var bad : bool; | |
| 670 | 670 | i[i] = i[i]; |
| 671 | 671 | bad[bad] = bad[bad]; |
| 672 | 672 | } |