| author | |
| committer | |
| log | c0b37e8514a26f56e3596f86b01771b1ae2bf299 |
| tree | b24c7fd04b2e8582d4e79455455e740ef58ca864 |
| parent | 8b1c6d8b76ad1861f963fc7a2a079af5d8729a70 |
See #8312 files changed, 330 insertions(+), 89 deletions(-)
doc/langref.md+3-1| ... | ... | @@ -69,7 +69,7 @@ AssignmentExpression = UnwrapExpression AssignmentOperator UnwrapExpression | Un |
| 69 | 69 | |
| 70 | 70 | AssignmentOperator = "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | "&=" | "^=" | "|=" | "&&=" | "||=" | "*%=" | "+%=" | "-%=" | "<<%=" |
| 71 | 71 | |
| 72 | BlockExpression = IfExpression | Block | WhileExpression | ForExpression | SwitchExpression | CompTimeExpression | |
| 72 | BlockExpression = IfExpression | Block | WhileExpression | ForExpression | SwitchExpression | CompTimeExpression | TryExpression | |
| 73 | 73 | |
| 74 | 74 | CompTimeExpression = option("comptime") Expression |
| 75 | 75 | |
| ... | ... | @@ -93,6 +93,8 @@ IfExpression = IfVarExpression | IfBoolExpression |
| 93 | 93 | |
| 94 | 94 | IfBoolExpression = "if" "(" Expression ")" Expression option(Else) |
| 95 | 95 | |
| 96 | TryExpression = "try" "(" ("const" | "var") option("*") Symbol "=" Expression ")" Expression option("else" option("|" Symbol "|") Expression) | |
| 97 | ||
| 96 | 98 | IfVarExpression = "if" "(" ("const" | "var") option("*") Symbol option(":" TypeExpr) "?=" Expression ")" Expression Option(Else) |
| 97 | 99 | |
| 98 | 100 | Else = "else" Expression |
doc/vim/syntax/zig.vim+1-1| ... | ... | @@ -11,7 +11,7 @@ let b:current_syntax = "zig" |
| 11 | 11 | syn keyword zigStorage const var extern export pub noalias inline comptime nakedcc coldcc |
| 12 | 12 | syn keyword zigStructure struct enum union |
| 13 | 13 | syn keyword zigStatement goto break return continue asm defer |
| 14 | syn keyword zigConditional if else switch | |
| 14 | syn keyword zigConditional if else switch try | |
| 15 | 15 | syn keyword zigRepeat while for |
| 16 | 16 | |
| 17 | 17 | syn keyword zigConstant null undefined zeroes this |
src/all_types.hpp+12| ... | ... | @@ -299,6 +299,7 @@ enum NodeType { |
| 299 | 299 | NodeTypeErrorType, |
| 300 | 300 | NodeTypeTypeLiteral, |
| 301 | 301 | NodeTypeVarLiteral, |
| 302 | NodeTypeTryExpr, | |
| 302 | 303 | }; |
| 303 | 304 | |
| 304 | 305 | struct AstNodeRoot { |
| ... | ... | @@ -511,6 +512,16 @@ struct AstNodeIfBoolExpr { |
| 511 | 512 | AstNode *else_node; // null, block node, or other if expr node |
| 512 | 513 | }; |
| 513 | 514 | |
| 515 | struct AstNodeTryExpr { | |
| 516 | bool var_is_const; | |
| 517 | Buf *var_symbol; | |
| 518 | bool var_is_ptr; | |
| 519 | AstNode *target_node; | |
| 520 | AstNode *then_node; | |
| 521 | AstNode *else_node; | |
| 522 | Buf *err_symbol; | |
| 523 | }; | |
| 524 | ||
| 514 | 525 | struct AstNodeIfVarExpr { |
| 515 | 526 | AstNodeVariableDeclaration var_decl; |
| 516 | 527 | AstNode *then_block; |
| ... | ... | @@ -721,6 +732,7 @@ struct AstNode { |
| 721 | 732 | AstNodeUse use; |
| 722 | 733 | AstNodeIfBoolExpr if_bool_expr; |
| 723 | 734 | AstNodeIfVarExpr if_var_expr; |
| 735 | AstNodeTryExpr try_expr; | |
| 724 | 736 | AstNodeWhileExpr while_expr; |
| 725 | 737 | AstNodeForExpr for_expr; |
| 726 | 738 | AstNodeSwitchExpr switch_expr; |
src/analyze.cpp+1| ... | ... | @@ -1769,6 +1769,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { |
| 1769 | 1769 | case NodeTypeErrorType: |
| 1770 | 1770 | case NodeTypeTypeLiteral: |
| 1771 | 1771 | case NodeTypeVarLiteral: |
| 1772 | case NodeTypeTryExpr: | |
| 1772 | 1773 | zig_unreachable(); |
| 1773 | 1774 | } |
| 1774 | 1775 | } |
src/ast_render.cpp+21| ... | ... | @@ -223,6 +223,8 @@ static const char *node_type_str(NodeType node_type) { |
| 223 | 223 | return "TypeLiteral"; |
| 224 | 224 | case NodeTypeVarLiteral: |
| 225 | 225 | return "VarLiteral"; |
| 226 | case NodeTypeTryExpr: | |
| 227 | return "TryExpr"; | |
| 226 | 228 | } |
| 227 | 229 | zig_unreachable(); |
| 228 | 230 | } |
| ... | ... | @@ -769,6 +771,25 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 769 | 771 | } |
| 770 | 772 | break; |
| 771 | 773 | } |
| 774 | case NodeTypeTryExpr: | |
| 775 | { | |
| 776 | const char *var_str = node->data.try_expr.var_is_const ? "const" : "var"; | |
| 777 | const char *var_name = buf_ptr(node->data.try_expr.var_symbol); | |
| 778 | const char *ptr_str = node->data.try_expr.var_is_ptr ? "*" : ""; | |
| 779 | fprintf(ar->f, "try (%s %s%s", var_str, ptr_str, var_name); | |
| 780 | fprintf(ar->f, " = "); | |
| 781 | render_node_grouped(ar, node->data.try_expr.target_node); | |
| 782 | fprintf(ar->f, ") "); | |
| 783 | render_node_grouped(ar, node->data.try_expr.then_node); | |
| 784 | if (node->data.try_expr.else_node) { | |
| 785 | fprintf(ar->f, " else "); | |
| 786 | if (node->data.try_expr.err_symbol) { | |
| 787 | fprintf(ar->f, "|%s| ", buf_ptr(node->data.try_expr.err_symbol)); | |
| 788 | } | |
| 789 | render_node_grouped(ar, node->data.try_expr.else_node); | |
| 790 | } | |
| 791 | break; | |
| 792 | } | |
| 772 | 793 | case NodeTypeSwitchExpr: |
| 773 | 794 | { |
| 774 | 795 | AstNodeSwitchExpr *switch_expr = &node->data.switch_expr; |
src/ir.cpp+94| ... | ... | @@ -4748,6 +4748,98 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 4748 | 4748 | return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values); |
| 4749 | 4749 | } |
| 4750 | 4750 | |
| 4751 | static IrInstruction *ir_gen_try_expr(IrBuilder *irb, Scope *scope, AstNode *node) { | |
| 4752 | assert(node->type == NodeTypeTryExpr); | |
| 4753 | ||
| 4754 | AstNode *target_node = node->data.try_expr.target_node; | |
| 4755 | AstNode *then_node = node->data.try_expr.then_node; | |
| 4756 | AstNode *else_node = node->data.try_expr.else_node; | |
| 4757 | bool var_is_ptr = node->data.try_expr.var_is_ptr; | |
| 4758 | bool var_is_const = node->data.try_expr.var_is_const; | |
| 4759 | Buf *var_symbol = node->data.try_expr.var_symbol; | |
| 4760 | Buf *err_symbol = node->data.try_expr.err_symbol; | |
| 4761 | ||
| 4762 | IrInstruction *err_val_ptr = ir_gen_node_extra(irb, target_node, scope, LValPurposeAddressOf); | |
| 4763 | if (err_val_ptr == irb->codegen->invalid_instruction) | |
| 4764 | return err_val_ptr; | |
| 4765 | ||
| 4766 | IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr); | |
| 4767 | IrInstruction *is_err = ir_build_test_err(irb, scope, node, err_val); | |
| 4768 | ||
| 4769 | IrBasicBlock *ok_block = ir_build_basic_block(irb, scope, "TryOk"); | |
| 4770 | IrBasicBlock *else_block = ir_build_basic_block(irb, scope, "TryElse"); | |
| 4771 | IrBasicBlock *endif_block = ir_build_basic_block(irb, scope, "TryEnd"); | |
| 4772 | ||
| 4773 | IrInstruction *is_comptime; | |
| 4774 | if (ir_should_inline(irb->exec, scope)) { | |
| 4775 | is_comptime = ir_build_const_bool(irb, scope, node, true); | |
| 4776 | } else { | |
| 4777 | is_comptime = ir_build_test_comptime(irb, scope, node, is_err); | |
| 4778 | } | |
| 4779 | ir_build_cond_br(irb, scope, node, is_err, else_block, ok_block, is_comptime); | |
| 4780 | ||
| 4781 | ir_set_cursor_at_end(irb, ok_block); | |
| 4782 | ||
| 4783 | Scope *var_scope; | |
| 4784 | if (var_symbol) { | |
| 4785 | IrInstruction *var_type = nullptr; | |
| 4786 | bool is_shadowable = false; | |
| 4787 | VariableTableEntry *var = ir_create_var(irb, node, scope, | |
| 4788 | var_symbol, var_is_const, var_is_const, is_shadowable, is_comptime); | |
| 4789 | ||
| 4790 | IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, scope, node, err_val_ptr, false); | |
| 4791 | IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, node, var_ptr_value); | |
| 4792 | ir_build_var_decl(irb, scope, node, var, var_type, var_value); | |
| 4793 | var_scope = var->child_scope; | |
| 4794 | } else { | |
| 4795 | var_scope = scope; | |
| 4796 | } | |
| 4797 | IrInstruction *then_expr_result = ir_gen_node(irb, then_node, var_scope); | |
| 4798 | if (then_expr_result == irb->codegen->invalid_instruction) | |
| 4799 | return then_expr_result; | |
| 4800 | IrBasicBlock *after_then_block = irb->current_basic_block; | |
| 4801 | if (!instr_is_unreachable(then_expr_result)) | |
| 4802 | ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime)); | |
| 4803 | ||
| 4804 | ir_set_cursor_at_end(irb, else_block); | |
| 4805 | ||
| 4806 | IrInstruction *else_expr_result; | |
| 4807 | if (else_node) { | |
| 4808 | Scope *err_var_scope; | |
| 4809 | if (err_symbol) { | |
| 4810 | IrInstruction *var_type = nullptr; | |
| 4811 | bool is_shadowable = false; | |
| 4812 | bool is_const = true; | |
| 4813 | VariableTableEntry *var = ir_create_var(irb, node, scope, | |
| 4814 | err_symbol, is_const, is_const, is_shadowable, is_comptime); | |
| 4815 | ||
| 4816 | IrInstruction *var_value = ir_build_unwrap_err_code(irb, scope, node, err_val_ptr); | |
| 4817 | ir_build_var_decl(irb, scope, node, var, var_type, var_value); | |
| 4818 | err_var_scope = var->child_scope; | |
| 4819 | } else { | |
| 4820 | err_var_scope = scope; | |
| 4821 | } | |
| 4822 | else_expr_result = ir_gen_node(irb, else_node, err_var_scope); | |
| 4823 | if (else_expr_result == irb->codegen->invalid_instruction) | |
| 4824 | return else_expr_result; | |
| 4825 | } else { | |
| 4826 | else_expr_result = ir_build_const_void(irb, scope, node); | |
| 4827 | } | |
| 4828 | IrBasicBlock *after_else_block = irb->current_basic_block; | |
| 4829 | if (!instr_is_unreachable(else_expr_result)) | |
| 4830 | ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime)); | |
| 4831 | ||
| 4832 | ir_set_cursor_at_end(irb, endif_block); | |
| 4833 | IrInstruction **incoming_values = allocate<IrInstruction *>(2); | |
| 4834 | incoming_values[0] = then_expr_result; | |
| 4835 | incoming_values[1] = else_expr_result; | |
| 4836 | IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2); | |
| 4837 | incoming_blocks[0] = after_then_block; | |
| 4838 | incoming_blocks[1] = after_else_block; | |
| 4839 | ||
| 4840 | return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values); | |
| 4841 | } | |
| 4842 | ||
| 4751 | 4843 | static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *switch_node, AstNode *prong_node, |
| 4752 | 4844 | IrBasicBlock *end_block, IrInstruction *is_comptime, IrInstruction *target_value_ptr, IrInstruction *prong_value, |
| 4753 | 4845 | ZigList<IrBasicBlock *> *incoming_blocks, ZigList<IrInstruction *> *incoming_values) |
| ... | ... | @@ -5291,6 +5383,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop |
| 5291 | 5383 | return ir_lval_wrap(irb, scope, ir_gen_var_literal(irb, scope, node), lval); |
| 5292 | 5384 | case NodeTypeIfVarExpr: |
| 5293 | 5385 | return ir_lval_wrap(irb, scope, ir_gen_if_var_expr(irb, scope, node), lval); |
| 5386 | case NodeTypeTryExpr: | |
| 5387 | return ir_lval_wrap(irb, scope, ir_gen_try_expr(irb, scope, node), lval); | |
| 5294 | 5388 | case NodeTypeSwitchExpr: |
| 5295 | 5389 | return ir_lval_wrap(irb, scope, ir_gen_switch_expr(irb, scope, node), lval); |
| 5296 | 5390 | case NodeTypeGoto: |
src/parser.cpp+75-1| ... | ... | @@ -623,6 +623,71 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b |
| 623 | 623 | return node; |
| 624 | 624 | } |
| 625 | 625 | |
| 626 | /* | |
| 627 | TryExpression = "try" "(" ("const" | "var") option("*") Symbol "=" Expression ")" Expression option("else" option("|" Symbol "|") Expression) | |
| 628 | */ | |
| 629 | static AstNode *ast_parse_try_expr(ParseContext *pc, size_t *token_index, bool mandatory) { | |
| 630 | Token *try_token = &pc->tokens->at(*token_index); | |
| 631 | if (try_token->id == TokenIdKeywordTry) { | |
| 632 | *token_index += 1; | |
| 633 | } else if (mandatory) { | |
| 634 | ast_expect_token(pc, try_token, TokenIdKeywordTry); | |
| 635 | zig_unreachable(); | |
| 636 | } else { | |
| 637 | return nullptr; | |
| 638 | } | |
| 639 | ||
| 640 | AstNode *node = ast_create_node(pc, NodeTypeTryExpr, try_token); | |
| 641 | ||
| 642 | ast_eat_token(pc, token_index, TokenIdLParen); | |
| 643 | ||
| 644 | Token *var_token = &pc->tokens->at(*token_index); | |
| 645 | if (var_token->id == TokenIdKeywordVar) { | |
| 646 | node->data.try_expr.var_is_const = false; | |
| 647 | *token_index += 1; | |
| 648 | } else if (var_token->id == TokenIdKeywordConst) { | |
| 649 | node->data.try_expr.var_is_const = true; | |
| 650 | *token_index += 1; | |
| 651 | } else { | |
| 652 | ast_invalid_token_error(pc, var_token); | |
| 653 | } | |
| 654 | ||
| 655 | Token *star_token = &pc->tokens->at(*token_index); | |
| 656 | if (star_token->id == TokenIdStar) { | |
| 657 | node->data.try_expr.var_is_ptr = true; | |
| 658 | *token_index += 1; | |
| 659 | } | |
| 660 | ||
| 661 | Token *var_name_tok = ast_eat_token(pc, token_index, TokenIdSymbol); | |
| 662 | node->data.try_expr.var_symbol = token_buf(var_name_tok); | |
| 663 | ||
| 664 | ast_eat_token(pc, token_index, TokenIdEq); | |
| 665 | ||
| 666 | node->data.try_expr.target_node = ast_parse_expression(pc, token_index, true); | |
| 667 | ||
| 668 | ast_eat_token(pc, token_index, TokenIdRParen); | |
| 669 | ||
| 670 | node->data.try_expr.then_node = ast_parse_expression(pc, token_index, true); | |
| 671 | ||
| 672 | Token *else_token = &pc->tokens->at(*token_index); | |
| 673 | if (else_token->id != TokenIdKeywordElse) | |
| 674 | return node; | |
| 675 | ||
| 676 | *token_index += 1; | |
| 677 | Token *open_bar_tok = &pc->tokens->at(*token_index); | |
| 678 | if (open_bar_tok->id == TokenIdBinOr) { | |
| 679 | *token_index += 1; | |
| 680 | ||
| 681 | Token *err_name_tok = ast_eat_token(pc, token_index, TokenIdSymbol); | |
| 682 | node->data.try_expr.err_symbol = token_buf(err_name_tok); | |
| 683 | ||
| 684 | ast_eat_token(pc, token_index, TokenIdBinOr); | |
| 685 | } | |
| 686 | ||
| 687 | node->data.try_expr.else_node = ast_parse_expression(pc, token_index, true); | |
| 688 | return node; | |
| 689 | } | |
| 690 | ||
| 626 | 691 | /* |
| 627 | 692 | PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl |
| 628 | 693 | KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" | "type" | "this" |
| ... | ... | @@ -1775,7 +1840,7 @@ static AstNode *ast_parse_switch_expr(ParseContext *pc, size_t *token_index, boo |
| 1775 | 1840 | } |
| 1776 | 1841 | |
| 1777 | 1842 | /* |
| 1778 | BlockExpression = IfExpression | Block | WhileExpression | ForExpression | SwitchExpression | CompTimeExpression | |
| 1843 | BlockExpression = IfExpression | Block | WhileExpression | ForExpression | SwitchExpression | CompTimeExpression | TryExpression | |
| 1779 | 1844 | */ |
| 1780 | 1845 | static AstNode *ast_parse_block_expr(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 1781 | 1846 | Token *token = &pc->tokens->at(*token_index); |
| ... | ... | @@ -1804,6 +1869,10 @@ static AstNode *ast_parse_block_expr(ParseContext *pc, size_t *token_index, bool |
| 1804 | 1869 | if (comptime_node) |
| 1805 | 1870 | return comptime_node; |
| 1806 | 1871 | |
| 1872 | AstNode *try_node = ast_parse_try_expr(pc, token_index, false); | |
| 1873 | if (try_node) | |
| 1874 | return try_node; | |
| 1875 | ||
| 1807 | 1876 | if (mandatory) |
| 1808 | 1877 | ast_invalid_token_error(pc, token); |
| 1809 | 1878 | |
| ... | ... | @@ -2555,6 +2624,11 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont |
| 2555 | 2624 | visit_field(&node->data.if_var_expr.then_block, visit, context); |
| 2556 | 2625 | visit_field(&node->data.if_var_expr.else_node, visit, context); |
| 2557 | 2626 | break; |
| 2627 | case NodeTypeTryExpr: | |
| 2628 | visit_field(&node->data.try_expr.target_node, visit, context); | |
| 2629 | visit_field(&node->data.try_expr.then_node, visit, context); | |
| 2630 | visit_field(&node->data.try_expr.else_node, visit, context); | |
| 2631 | break; | |
| 2558 | 2632 | case NodeTypeWhileExpr: |
| 2559 | 2633 | visit_field(&node->data.while_expr.condition, visit, context); |
| 2560 | 2634 | visit_field(&node->data.while_expr.body, visit, context); |
src/tokenizer.cpp+86-84| ... | ... | @@ -134,6 +134,7 @@ static const struct ZigKeyword zig_keywords[] = { |
| 134 | 134 | {"switch", TokenIdKeywordSwitch}, |
| 135 | 135 | {"this", TokenIdKeywordThis}, |
| 136 | 136 | {"true", TokenIdKeywordTrue}, |
| 137 | {"try", TokenIdKeywordTry}, | |
| 137 | 138 | {"type", TokenIdKeywordType}, |
| 138 | 139 | {"undefined", TokenIdKeywordUndefined}, |
| 139 | 140 | {"union", TokenIdKeywordUnion}, |
| ... | ... | @@ -1444,108 +1445,109 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 1444 | 1445 | |
| 1445 | 1446 | const char * token_name(TokenId id) { |
| 1446 | 1447 | switch (id) { |
| 1447 | case TokenIdEof: return "EOF"; | |
| 1448 | case TokenIdSymbol: return "Symbol"; | |
| 1449 | case TokenIdKeywordFn: return "fn"; | |
| 1450 | case TokenIdKeywordConst: return "const"; | |
| 1451 | case TokenIdKeywordVar: return "var"; | |
| 1452 | case TokenIdKeywordReturn: return "return"; | |
| 1453 | case TokenIdKeywordExtern: return "extern"; | |
| 1454 | case TokenIdKeywordPub: return "pub"; | |
| 1455 | case TokenIdKeywordExport: return "export"; | |
| 1456 | case TokenIdKeywordUse: return "use"; | |
| 1457 | case TokenIdKeywordTrue: return "true"; | |
| 1458 | case TokenIdKeywordFalse: return "false"; | |
| 1459 | case TokenIdKeywordIf: return "if"; | |
| 1460 | case TokenIdKeywordElse: return "else"; | |
| 1461 | case TokenIdKeywordGoto: return "goto"; | |
| 1462 | case TokenIdKeywordVolatile: return "volatile"; | |
| 1463 | case TokenIdKeywordAsm: return "asm"; | |
| 1464 | case TokenIdKeywordStruct: return "struct"; | |
| 1465 | case TokenIdKeywordEnum: return "enum"; | |
| 1466 | case TokenIdKeywordUnion: return "union"; | |
| 1467 | case TokenIdKeywordWhile: return "while"; | |
| 1468 | case TokenIdKeywordFor: return "for"; | |
| 1469 | case TokenIdKeywordContinue: return "continue"; | |
| 1470 | case TokenIdKeywordBreak: return "break"; | |
| 1471 | case TokenIdKeywordNull: return "null"; | |
| 1472 | case TokenIdKeywordNoAlias: return "noalias"; | |
| 1473 | case TokenIdKeywordSwitch: return "switch"; | |
| 1474 | case TokenIdKeywordUndefined: return "undefined"; | |
| 1475 | case TokenIdKeywordThis: return "this"; | |
| 1476 | case TokenIdKeywordError: return "error"; | |
| 1477 | case TokenIdKeywordType: return "type"; | |
| 1478 | case TokenIdKeywordInline: return "inline"; | |
| 1479 | case TokenIdKeywordCompTime: return "comptime"; | |
| 1480 | case TokenIdKeywordDefer: return "defer"; | |
| 1481 | case TokenIdKeywordColdCC: return "coldcc"; | |
| 1482 | case TokenIdKeywordNakedCC: return "nakedcc"; | |
| 1483 | case TokenIdLParen: return "("; | |
| 1484 | case TokenIdRParen: return ")"; | |
| 1485 | case TokenIdComma: return ","; | |
| 1486 | case TokenIdStar: return "*"; | |
| 1487 | case TokenIdStarStar: return "**"; | |
| 1488 | case TokenIdLBrace: return "{"; | |
| 1489 | case TokenIdRBrace: return "}"; | |
| 1490 | case TokenIdLBracket: return "["; | |
| 1491 | case TokenIdRBracket: return "]"; | |
| 1492 | case TokenIdStringLiteral: return "StringLiteral"; | |
| 1493 | case TokenIdCharLiteral: return "CharLiteral"; | |
| 1494 | case TokenIdSemicolon: return ";"; | |
| 1495 | case TokenIdNumberLiteral: return "NumberLiteral"; | |
| 1496 | case TokenIdPlus: return "+"; | |
| 1497 | case TokenIdPlusPlus: return "++"; | |
| 1498 | case TokenIdColon: return ":"; | |
| 1448 | case TokenIdAmpersand: return "&"; | |
| 1499 | 1449 | case TokenIdArrow: return "->"; |
| 1500 | case TokenIdFatArrow: return "=>"; | |
| 1501 | case TokenIdDash: return "-"; | |
| 1502 | case TokenIdNumberSign: return "#"; | |
| 1450 | case TokenIdAtSign: return "@"; | |
| 1451 | case TokenIdBang: return "!"; | |
| 1503 | 1452 | case TokenIdBinOr: return "|"; |
| 1504 | case TokenIdAmpersand: return "&"; | |
| 1505 | 1453 | case TokenIdBinXor: return "^"; |
| 1506 | case TokenIdBoolOr: return "||"; | |
| 1507 | case TokenIdBoolAnd: return "&&"; | |
| 1508 | case TokenIdEq: return "="; | |
| 1509 | case TokenIdTimesEq: return "*="; | |
| 1510 | case TokenIdDivEq: return "/="; | |
| 1511 | case TokenIdModEq: return "%="; | |
| 1512 | case TokenIdPlusEq: return "+="; | |
| 1513 | case TokenIdMinusEq: return "-="; | |
| 1454 | case TokenIdBitAndEq: return "&="; | |
| 1455 | case TokenIdBitOrEq: return "|="; | |
| 1456 | case TokenIdBitShiftLeft: return "<<"; | |
| 1514 | 1457 | case TokenIdBitShiftLeftEq: return "<<="; |
| 1458 | case TokenIdBitShiftLeftPercent: return "<<%"; | |
| 1459 | case TokenIdBitShiftLeftPercentEq: return "<<%="; | |
| 1460 | case TokenIdBitShiftRight: return ">>"; | |
| 1515 | 1461 | case TokenIdBitShiftRightEq: return ">>="; |
| 1516 | case TokenIdBitAndEq: return "&="; | |
| 1517 | 1462 | case TokenIdBitXorEq: return "^="; |
| 1518 | case TokenIdBitOrEq: return "|="; | |
| 1463 | case TokenIdBoolAnd: return "&&"; | |
| 1519 | 1464 | case TokenIdBoolAndEq: return "&&="; |
| 1465 | case TokenIdBoolOr: return "||"; | |
| 1520 | 1466 | case TokenIdBoolOrEq: return "||="; |
| 1521 | case TokenIdBang: return "!"; | |
| 1522 | case TokenIdTilde: return "~"; | |
| 1467 | case TokenIdCharLiteral: return "CharLiteral"; | |
| 1523 | 1468 | case TokenIdCmpEq: return "=="; |
| 1524 | case TokenIdCmpNotEq: return "!="; | |
| 1525 | case TokenIdCmpLessThan: return "<"; | |
| 1469 | case TokenIdCmpGreaterOrEq: return ">="; | |
| 1526 | 1470 | case TokenIdCmpGreaterThan: return ">"; |
| 1527 | 1471 | case TokenIdCmpLessOrEq: return "<="; |
| 1528 | case TokenIdCmpGreaterOrEq: return ">="; | |
| 1529 | case TokenIdBitShiftLeft: return "<<"; | |
| 1530 | case TokenIdBitShiftRight: return ">>"; | |
| 1531 | case TokenIdSlash: return "/"; | |
| 1532 | case TokenIdPercent: return "%"; | |
| 1533 | case TokenIdPercentPercent: return "%%"; | |
| 1472 | case TokenIdCmpLessThan: return "<"; | |
| 1473 | case TokenIdCmpNotEq: return "!="; | |
| 1474 | case TokenIdColon: return ":"; | |
| 1475 | case TokenIdComma: return ","; | |
| 1476 | case TokenIdDash: return "-"; | |
| 1477 | case TokenIdDivEq: return "/="; | |
| 1534 | 1478 | case TokenIdDot: return "."; |
| 1479 | case TokenIdDoubleQuestion: return "??"; | |
| 1535 | 1480 | case TokenIdEllipsis: return "..."; |
| 1481 | case TokenIdEof: return "EOF"; | |
| 1482 | case TokenIdEq: return "="; | |
| 1483 | case TokenIdFatArrow: return "=>"; | |
| 1484 | case TokenIdKeywordAsm: return "asm"; | |
| 1485 | case TokenIdKeywordBreak: return "break"; | |
| 1486 | case TokenIdKeywordColdCC: return "coldcc"; | |
| 1487 | case TokenIdKeywordCompTime: return "comptime"; | |
| 1488 | case TokenIdKeywordConst: return "const"; | |
| 1489 | case TokenIdKeywordContinue: return "continue"; | |
| 1490 | case TokenIdKeywordDefer: return "defer"; | |
| 1491 | case TokenIdKeywordElse: return "else"; | |
| 1492 | case TokenIdKeywordEnum: return "enum"; | |
| 1493 | case TokenIdKeywordError: return "error"; | |
| 1494 | case TokenIdKeywordExport: return "export"; | |
| 1495 | case TokenIdKeywordExtern: return "extern"; | |
| 1496 | case TokenIdKeywordFalse: return "false"; | |
| 1497 | case TokenIdKeywordFn: return "fn"; | |
| 1498 | case TokenIdKeywordFor: return "for"; | |
| 1499 | case TokenIdKeywordGoto: return "goto"; | |
| 1500 | case TokenIdKeywordIf: return "if"; | |
| 1501 | case TokenIdKeywordInline: return "inline"; | |
| 1502 | case TokenIdKeywordNakedCC: return "nakedcc"; | |
| 1503 | case TokenIdKeywordNoAlias: return "noalias"; | |
| 1504 | case TokenIdKeywordNull: return "null"; | |
| 1505 | case TokenIdKeywordPub: return "pub"; | |
| 1506 | case TokenIdKeywordReturn: return "return"; | |
| 1507 | case TokenIdKeywordStruct: return "struct"; | |
| 1508 | case TokenIdKeywordSwitch: return "switch"; | |
| 1509 | case TokenIdKeywordThis: return "this"; | |
| 1510 | case TokenIdKeywordTrue: return "true"; | |
| 1511 | case TokenIdKeywordTry: return "try"; | |
| 1512 | case TokenIdKeywordType: return "type"; | |
| 1513 | case TokenIdKeywordUndefined: return "undefined"; | |
| 1514 | case TokenIdKeywordUnion: return "union"; | |
| 1515 | case TokenIdKeywordUse: return "use"; | |
| 1516 | case TokenIdKeywordVar: return "var"; | |
| 1517 | case TokenIdKeywordVolatile: return "volatile"; | |
| 1518 | case TokenIdKeywordWhile: return "while"; | |
| 1519 | case TokenIdLBrace: return "{"; | |
| 1520 | case TokenIdLBracket: return "["; | |
| 1521 | case TokenIdLParen: return "("; | |
| 1536 | 1522 | case TokenIdMaybe: return "?"; |
| 1537 | case TokenIdDoubleQuestion: return "??"; | |
| 1538 | 1523 | case TokenIdMaybeAssign: return "?="; |
| 1539 | case TokenIdAtSign: return "@"; | |
| 1524 | case TokenIdMinusEq: return "-="; | |
| 1525 | case TokenIdMinusPercent: return "-%"; | |
| 1526 | case TokenIdMinusPercentEq: return "-%="; | |
| 1527 | case TokenIdModEq: return "%="; | |
| 1528 | case TokenIdNumberLiteral: return "NumberLiteral"; | |
| 1529 | case TokenIdNumberSign: return "#"; | |
| 1530 | case TokenIdPercent: return "%"; | |
| 1540 | 1531 | case TokenIdPercentDot: return "%."; |
| 1541 | case TokenIdTimesPercent: return "*%"; | |
| 1542 | case TokenIdTimesPercentEq: return "*%="; | |
| 1532 | case TokenIdPercentPercent: return "%%"; | |
| 1533 | case TokenIdPlus: return "+"; | |
| 1534 | case TokenIdPlusEq: return "+="; | |
| 1543 | 1535 | case TokenIdPlusPercent: return "+%"; |
| 1544 | 1536 | case TokenIdPlusPercentEq: return "+%="; |
| 1545 | case TokenIdMinusPercent: return "-%"; | |
| 1546 | case TokenIdMinusPercentEq: return "-%="; | |
| 1547 | case TokenIdBitShiftLeftPercent: return "<<%"; | |
| 1548 | case TokenIdBitShiftLeftPercentEq: return "<<%="; | |
| 1537 | case TokenIdPlusPlus: return "++"; | |
| 1538 | case TokenIdRBrace: return "}"; | |
| 1539 | case TokenIdRBracket: return "]"; | |
| 1540 | case TokenIdRParen: return ")"; | |
| 1541 | case TokenIdSemicolon: return ";"; | |
| 1542 | case TokenIdSlash: return "/"; | |
| 1543 | case TokenIdStar: return "*"; | |
| 1544 | case TokenIdStarStar: return "**"; | |
| 1545 | case TokenIdStringLiteral: return "StringLiteral"; | |
| 1546 | case TokenIdSymbol: return "Symbol"; | |
| 1547 | case TokenIdTilde: return "~"; | |
| 1548 | case TokenIdTimesEq: return "*="; | |
| 1549 | case TokenIdTimesPercent: return "*%"; | |
| 1550 | case TokenIdTimesPercentEq: return "*%="; | |
| 1549 | 1551 | } |
| 1550 | 1552 | return "(invalid token)"; |
| 1551 | 1553 | } |
src/tokenizer.hpp+1| ... | ... | @@ -25,6 +25,7 @@ enum TokenId { |
| 25 | 25 | TokenIdKeywordTrue, |
| 26 | 26 | TokenIdKeywordFalse, |
| 27 | 27 | TokenIdKeywordIf, |
| 28 | TokenIdKeywordTry, | |
| 28 | 29 | TokenIdKeywordElse, |
| 29 | 30 | TokenIdKeywordGoto, |
| 30 | 31 | TokenIdKeywordAsm, |
std/debug.zig+2-2| ... | ... | @@ -9,8 +9,8 @@ error MissingDebugInfo; |
| 9 | 9 | error InvalidDebugInfo; |
| 10 | 10 | error UnsupportedDebugInfo; |
| 11 | 11 | |
| 12 | pub fn assert(b: bool) { | |
| 13 | if (!b) @unreachable() | |
| 12 | pub fn assert(ok: bool) { | |
| 13 | if (!ok) @unreachable() | |
| 14 | 14 | } |
| 15 | 15 | |
| 16 | 16 | pub fn printStackTrace() -> %void { |
test/cases/try.zig created+33| ... | ... | @@ -0,0 +1,33 @@ |
| 1 | const assert = @import("std").debug.assert; | |
| 2 | ||
| 3 | fn tryOnErrorUnion() { | |
| 4 | @setFnTest(this); | |
| 5 | ||
| 6 | const x = try (const val = returnsTen()) { | |
| 7 | val + 1 | |
| 8 | } else |err| switch (err) { | |
| 9 | error.ItBroke, error.NoMem => 1, | |
| 10 | error.CrappedOut => i32(2), | |
| 11 | }; | |
| 12 | assert(x == 11); | |
| 13 | } | |
| 14 | ||
| 15 | fn tryOnErrorUnionComptime() { | |
| 16 | @setFnTest(this); | |
| 17 | ||
| 18 | comptime { | |
| 19 | const x = try (const val = returnsTen()) { | |
| 20 | val + 1 | |
| 21 | } else |err| switch (err) { | |
| 22 | error.ItBroke, error.NoMem => 1, | |
| 23 | error.CrappedOut => i32(2), | |
| 24 | }; | |
| 25 | assert(x == 11); | |
| 26 | } | |
| 27 | } | |
| 28 | error ItBroke; | |
| 29 | error NoMem; | |
| 30 | error CrappedOut; | |
| 31 | fn returnsTen() -> %i32 { | |
| 32 | 10 | |
| 33 | } |
test/self_hosted.zig+1| ... | ... | @@ -28,6 +28,7 @@ const test_switch = @import("cases/switch.zig"); |
| 28 | 28 | const test_switch_prong_err_enum = @import("cases/switch_prong_err_enum.zig"); |
| 29 | 29 | const test_switch_prong_implicit_cast = @import("cases/switch_prong_implicit_cast.zig"); |
| 30 | 30 | const test_this = @import("cases/this.zig"); |
| 31 | const test_try = @import("cases/try.zig"); | |
| 31 | 32 | const test_undefined = @import("cases/undefined.zig"); |
| 32 | 33 | const test_var_args = @import("cases/var_args.zig"); |
| 33 | 34 | const test_while = @import("cases/while.zig"); |