diff options
| -rw-r--r-- | doc/langref.md | 4 | ||||
| -rw-r--r-- | doc/vim/syntax/zig.vim | 2 | ||||
| -rw-r--r-- | src/all_types.hpp | 12 | ||||
| -rw-r--r-- | src/analyze.cpp | 1 | ||||
| -rw-r--r-- | src/ast_render.cpp | 21 | ||||
| -rw-r--r-- | src/ir.cpp | 94 | ||||
| -rw-r--r-- | src/parser.cpp | 76 | ||||
| -rw-r--r-- | src/tokenizer.cpp | 170 | ||||
| -rw-r--r-- | src/tokenizer.hpp | 1 | ||||
| -rw-r--r-- | std/debug.zig | 4 | ||||
| -rw-r--r-- | test/cases/try.zig | 33 | ||||
| -rw-r--r-- | test/self_hosted.zig | 1 |
12 files changed, 330 insertions, 89 deletions
diff --git a/doc/langref.md b/doc/langref.md index 5851232504..78904d8325 100644 --- a/doc/langref.md +++ b/doc/langref.md @@ -69,7 +69,7 @@ AssignmentExpression = UnwrapExpression AssignmentOperator UnwrapExpression | Un AssignmentOperator = "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | "&=" | "^=" | "|=" | "&&=" | "||=" | "*%=" | "+%=" | "-%=" | "<<%=" -BlockExpression = IfExpression | Block | WhileExpression | ForExpression | SwitchExpression | CompTimeExpression +BlockExpression = IfExpression | Block | WhileExpression | ForExpression | SwitchExpression | CompTimeExpression | TryExpression CompTimeExpression = option("comptime") Expression @@ -93,6 +93,8 @@ IfExpression = IfVarExpression | IfBoolExpression IfBoolExpression = "if" "(" Expression ")" Expression option(Else) +TryExpression = "try" "(" ("const" | "var") option("*") Symbol "=" Expression ")" Expression option("else" option("|" Symbol "|") Expression) + IfVarExpression = "if" "(" ("const" | "var") option("*") Symbol option(":" TypeExpr) "?=" Expression ")" Expression Option(Else) Else = "else" Expression diff --git a/doc/vim/syntax/zig.vim b/doc/vim/syntax/zig.vim index 8071b465ba..ccae0a6f14 100644 --- a/doc/vim/syntax/zig.vim +++ b/doc/vim/syntax/zig.vim @@ -11,7 +11,7 @@ let b:current_syntax = "zig" syn keyword zigStorage const var extern export pub noalias inline comptime nakedcc coldcc syn keyword zigStructure struct enum union syn keyword zigStatement goto break return continue asm defer -syn keyword zigConditional if else switch +syn keyword zigConditional if else switch try syn keyword zigRepeat while for syn keyword zigConstant null undefined zeroes this diff --git a/src/all_types.hpp b/src/all_types.hpp index 98a6d31dcf..7eaca8c45a 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -299,6 +299,7 @@ enum NodeType { NodeTypeErrorType, NodeTypeTypeLiteral, NodeTypeVarLiteral, + NodeTypeTryExpr, }; struct AstNodeRoot { @@ -511,6 +512,16 @@ struct AstNodeIfBoolExpr { AstNode *else_node; // null, block node, or other if expr node }; +struct AstNodeTryExpr { + bool var_is_const; + Buf *var_symbol; + bool var_is_ptr; + AstNode *target_node; + AstNode *then_node; + AstNode *else_node; + Buf *err_symbol; +}; + struct AstNodeIfVarExpr { AstNodeVariableDeclaration var_decl; AstNode *then_block; @@ -721,6 +732,7 @@ struct AstNode { AstNodeUse use; AstNodeIfBoolExpr if_bool_expr; AstNodeIfVarExpr if_var_expr; + AstNodeTryExpr try_expr; AstNodeWhileExpr while_expr; AstNodeForExpr for_expr; AstNodeSwitchExpr switch_expr; diff --git a/src/analyze.cpp b/src/analyze.cpp index 9278ddd555..506d5e1db3 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1769,6 +1769,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { case NodeTypeErrorType: case NodeTypeTypeLiteral: case NodeTypeVarLiteral: + case NodeTypeTryExpr: zig_unreachable(); } } diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 12642c71e2..4689f723ee 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -223,6 +223,8 @@ static const char *node_type_str(NodeType node_type) { return "TypeLiteral"; case NodeTypeVarLiteral: return "VarLiteral"; + case NodeTypeTryExpr: + return "TryExpr"; } zig_unreachable(); } @@ -769,6 +771,25 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { } break; } + case NodeTypeTryExpr: + { + const char *var_str = node->data.try_expr.var_is_const ? "const" : "var"; + const char *var_name = buf_ptr(node->data.try_expr.var_symbol); + const char *ptr_str = node->data.try_expr.var_is_ptr ? "*" : ""; + fprintf(ar->f, "try (%s %s%s", var_str, ptr_str, var_name); + fprintf(ar->f, " = "); + render_node_grouped(ar, node->data.try_expr.target_node); + fprintf(ar->f, ") "); + render_node_grouped(ar, node->data.try_expr.then_node); + if (node->data.try_expr.else_node) { + fprintf(ar->f, " else "); + if (node->data.try_expr.err_symbol) { + fprintf(ar->f, "|%s| ", buf_ptr(node->data.try_expr.err_symbol)); + } + render_node_grouped(ar, node->data.try_expr.else_node); + } + break; + } case NodeTypeSwitchExpr: { AstNodeSwitchExpr *switch_expr = &node->data.switch_expr; diff --git a/src/ir.cpp b/src/ir.cpp index e37cee2e07..bf85a20f7a 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -4748,6 +4748,98 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, Scope *scope, AstNode * return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values); } +static IrInstruction *ir_gen_try_expr(IrBuilder *irb, Scope *scope, AstNode *node) { + assert(node->type == NodeTypeTryExpr); + + AstNode *target_node = node->data.try_expr.target_node; + AstNode *then_node = node->data.try_expr.then_node; + AstNode *else_node = node->data.try_expr.else_node; + bool var_is_ptr = node->data.try_expr.var_is_ptr; + bool var_is_const = node->data.try_expr.var_is_const; + Buf *var_symbol = node->data.try_expr.var_symbol; + Buf *err_symbol = node->data.try_expr.err_symbol; + + IrInstruction *err_val_ptr = ir_gen_node_extra(irb, target_node, scope, LValPurposeAddressOf); + if (err_val_ptr == irb->codegen->invalid_instruction) + return err_val_ptr; + + IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr); + IrInstruction *is_err = ir_build_test_err(irb, scope, node, err_val); + + IrBasicBlock *ok_block = ir_build_basic_block(irb, scope, "TryOk"); + IrBasicBlock *else_block = ir_build_basic_block(irb, scope, "TryElse"); + IrBasicBlock *endif_block = ir_build_basic_block(irb, scope, "TryEnd"); + + IrInstruction *is_comptime; + if (ir_should_inline(irb->exec, scope)) { + is_comptime = ir_build_const_bool(irb, scope, node, true); + } else { + is_comptime = ir_build_test_comptime(irb, scope, node, is_err); + } + ir_build_cond_br(irb, scope, node, is_err, else_block, ok_block, is_comptime); + + ir_set_cursor_at_end(irb, ok_block); + + Scope *var_scope; + if (var_symbol) { + IrInstruction *var_type = nullptr; + bool is_shadowable = false; + VariableTableEntry *var = ir_create_var(irb, node, scope, + var_symbol, var_is_const, var_is_const, is_shadowable, is_comptime); + + IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, scope, node, err_val_ptr, false); + IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, node, var_ptr_value); + ir_build_var_decl(irb, scope, node, var, var_type, var_value); + var_scope = var->child_scope; + } else { + var_scope = scope; + } + IrInstruction *then_expr_result = ir_gen_node(irb, then_node, var_scope); + if (then_expr_result == irb->codegen->invalid_instruction) + return then_expr_result; + IrBasicBlock *after_then_block = irb->current_basic_block; + if (!instr_is_unreachable(then_expr_result)) + ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime)); + + ir_set_cursor_at_end(irb, else_block); + + IrInstruction *else_expr_result; + if (else_node) { + Scope *err_var_scope; + if (err_symbol) { + IrInstruction *var_type = nullptr; + bool is_shadowable = false; + bool is_const = true; + VariableTableEntry *var = ir_create_var(irb, node, scope, + err_symbol, is_const, is_const, is_shadowable, is_comptime); + + IrInstruction *var_value = ir_build_unwrap_err_code(irb, scope, node, err_val_ptr); + ir_build_var_decl(irb, scope, node, var, var_type, var_value); + err_var_scope = var->child_scope; + } else { + err_var_scope = scope; + } + else_expr_result = ir_gen_node(irb, else_node, err_var_scope); + if (else_expr_result == irb->codegen->invalid_instruction) + return else_expr_result; + } else { + else_expr_result = ir_build_const_void(irb, scope, node); + } + IrBasicBlock *after_else_block = irb->current_basic_block; + if (!instr_is_unreachable(else_expr_result)) + ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime)); + + ir_set_cursor_at_end(irb, endif_block); + IrInstruction **incoming_values = allocate<IrInstruction *>(2); + incoming_values[0] = then_expr_result; + incoming_values[1] = else_expr_result; + IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2); + incoming_blocks[0] = after_then_block; + incoming_blocks[1] = after_else_block; + + return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values); +} + static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *switch_node, AstNode *prong_node, IrBasicBlock *end_block, IrInstruction *is_comptime, IrInstruction *target_value_ptr, IrInstruction *prong_value, ZigList<IrBasicBlock *> *incoming_blocks, ZigList<IrInstruction *> *incoming_values) @@ -5291,6 +5383,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop return ir_lval_wrap(irb, scope, ir_gen_var_literal(irb, scope, node), lval); case NodeTypeIfVarExpr: return ir_lval_wrap(irb, scope, ir_gen_if_var_expr(irb, scope, node), lval); + case NodeTypeTryExpr: + return ir_lval_wrap(irb, scope, ir_gen_try_expr(irb, scope, node), lval); case NodeTypeSwitchExpr: return ir_lval_wrap(irb, scope, ir_gen_switch_expr(irb, scope, node), lval); case NodeTypeGoto: diff --git a/src/parser.cpp b/src/parser.cpp index 1b79da9b2b..54081d91a7 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -624,6 +624,71 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b } /* +TryExpression = "try" "(" ("const" | "var") option("*") Symbol "=" Expression ")" Expression option("else" option("|" Symbol "|") Expression) +*/ +static AstNode *ast_parse_try_expr(ParseContext *pc, size_t *token_index, bool mandatory) { + Token *try_token = &pc->tokens->at(*token_index); + if (try_token->id == TokenIdKeywordTry) { + *token_index += 1; + } else if (mandatory) { + ast_expect_token(pc, try_token, TokenIdKeywordTry); + zig_unreachable(); + } else { + return nullptr; + } + + AstNode *node = ast_create_node(pc, NodeTypeTryExpr, try_token); + + ast_eat_token(pc, token_index, TokenIdLParen); + + Token *var_token = &pc->tokens->at(*token_index); + if (var_token->id == TokenIdKeywordVar) { + node->data.try_expr.var_is_const = false; + *token_index += 1; + } else if (var_token->id == TokenIdKeywordConst) { + node->data.try_expr.var_is_const = true; + *token_index += 1; + } else { + ast_invalid_token_error(pc, var_token); + } + + Token *star_token = &pc->tokens->at(*token_index); + if (star_token->id == TokenIdStar) { + node->data.try_expr.var_is_ptr = true; + *token_index += 1; + } + + Token *var_name_tok = ast_eat_token(pc, token_index, TokenIdSymbol); + node->data.try_expr.var_symbol = token_buf(var_name_tok); + + ast_eat_token(pc, token_index, TokenIdEq); + + node->data.try_expr.target_node = ast_parse_expression(pc, token_index, true); + + ast_eat_token(pc, token_index, TokenIdRParen); + + node->data.try_expr.then_node = ast_parse_expression(pc, token_index, true); + + Token *else_token = &pc->tokens->at(*token_index); + if (else_token->id != TokenIdKeywordElse) + return node; + + *token_index += 1; + Token *open_bar_tok = &pc->tokens->at(*token_index); + if (open_bar_tok->id == TokenIdBinOr) { + *token_index += 1; + + Token *err_name_tok = ast_eat_token(pc, token_index, TokenIdSymbol); + node->data.try_expr.err_symbol = token_buf(err_name_tok); + + ast_eat_token(pc, token_index, TokenIdBinOr); + } + + node->data.try_expr.else_node = ast_parse_expression(pc, token_index, true); + return node; +} + +/* PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl 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 } /* -BlockExpression = IfExpression | Block | WhileExpression | ForExpression | SwitchExpression | CompTimeExpression +BlockExpression = IfExpression | Block | WhileExpression | ForExpression | SwitchExpression | CompTimeExpression | TryExpression */ static AstNode *ast_parse_block_expr(ParseContext *pc, size_t *token_index, bool mandatory) { Token *token = &pc->tokens->at(*token_index); @@ -1804,6 +1869,10 @@ static AstNode *ast_parse_block_expr(ParseContext *pc, size_t *token_index, bool if (comptime_node) return comptime_node; + AstNode *try_node = ast_parse_try_expr(pc, token_index, false); + if (try_node) + return try_node; + if (mandatory) ast_invalid_token_error(pc, token); @@ -2555,6 +2624,11 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont visit_field(&node->data.if_var_expr.then_block, visit, context); visit_field(&node->data.if_var_expr.else_node, visit, context); break; + case NodeTypeTryExpr: + visit_field(&node->data.try_expr.target_node, visit, context); + visit_field(&node->data.try_expr.then_node, visit, context); + visit_field(&node->data.try_expr.else_node, visit, context); + break; case NodeTypeWhileExpr: visit_field(&node->data.while_expr.condition, visit, context); visit_field(&node->data.while_expr.body, visit, context); diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 5ed5fcf884..769e8c9d8d 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -134,6 +134,7 @@ static const struct ZigKeyword zig_keywords[] = { {"switch", TokenIdKeywordSwitch}, {"this", TokenIdKeywordThis}, {"true", TokenIdKeywordTrue}, + {"try", TokenIdKeywordTry}, {"type", TokenIdKeywordType}, {"undefined", TokenIdKeywordUndefined}, {"union", TokenIdKeywordUnion}, @@ -1444,108 +1445,109 @@ void tokenize(Buf *buf, Tokenization *out) { const char * token_name(TokenId id) { switch (id) { - case TokenIdEof: return "EOF"; - case TokenIdSymbol: return "Symbol"; - case TokenIdKeywordFn: return "fn"; - case TokenIdKeywordConst: return "const"; - case TokenIdKeywordVar: return "var"; - case TokenIdKeywordReturn: return "return"; - case TokenIdKeywordExtern: return "extern"; - case TokenIdKeywordPub: return "pub"; - case TokenIdKeywordExport: return "export"; - case TokenIdKeywordUse: return "use"; - case TokenIdKeywordTrue: return "true"; - case TokenIdKeywordFalse: return "false"; - case TokenIdKeywordIf: return "if"; - case TokenIdKeywordElse: return "else"; - case TokenIdKeywordGoto: return "goto"; - case TokenIdKeywordVolatile: return "volatile"; - case TokenIdKeywordAsm: return "asm"; - case TokenIdKeywordStruct: return "struct"; - case TokenIdKeywordEnum: return "enum"; - case TokenIdKeywordUnion: return "union"; - case TokenIdKeywordWhile: return "while"; - case TokenIdKeywordFor: return "for"; - case TokenIdKeywordContinue: return "continue"; - case TokenIdKeywordBreak: return "break"; - case TokenIdKeywordNull: return "null"; - case TokenIdKeywordNoAlias: return "noalias"; - case TokenIdKeywordSwitch: return "switch"; - case TokenIdKeywordUndefined: return "undefined"; - case TokenIdKeywordThis: return "this"; - case TokenIdKeywordError: return "error"; - case TokenIdKeywordType: return "type"; - case TokenIdKeywordInline: return "inline"; - case TokenIdKeywordCompTime: return "comptime"; - case TokenIdKeywordDefer: return "defer"; - case TokenIdKeywordColdCC: return "coldcc"; - case TokenIdKeywordNakedCC: return "nakedcc"; - case TokenIdLParen: return "("; - case TokenIdRParen: return ")"; - case TokenIdComma: return ","; - case TokenIdStar: return "*"; - case TokenIdStarStar: return "**"; - case TokenIdLBrace: return "{"; - case TokenIdRBrace: return "}"; - case TokenIdLBracket: return "["; - case TokenIdRBracket: return "]"; - case TokenIdStringLiteral: return "StringLiteral"; - case TokenIdCharLiteral: return "CharLiteral"; - case TokenIdSemicolon: return ";"; - case TokenIdNumberLiteral: return "NumberLiteral"; - case TokenIdPlus: return "+"; - case TokenIdPlusPlus: return "++"; - case TokenIdColon: return ":"; + case TokenIdAmpersand: return "&"; case TokenIdArrow: return "->"; - case TokenIdFatArrow: return "=>"; - case TokenIdDash: return "-"; - case TokenIdNumberSign: return "#"; + case TokenIdAtSign: return "@"; + case TokenIdBang: return "!"; case TokenIdBinOr: return "|"; - case TokenIdAmpersand: return "&"; case TokenIdBinXor: return "^"; - case TokenIdBoolOr: return "||"; - case TokenIdBoolAnd: return "&&"; - case TokenIdEq: return "="; - case TokenIdTimesEq: return "*="; - case TokenIdDivEq: return "/="; - case TokenIdModEq: return "%="; - case TokenIdPlusEq: return "+="; - case TokenIdMinusEq: return "-="; + case TokenIdBitAndEq: return "&="; + case TokenIdBitOrEq: return "|="; + case TokenIdBitShiftLeft: return "<<"; case TokenIdBitShiftLeftEq: return "<<="; + case TokenIdBitShiftLeftPercent: return "<<%"; + case TokenIdBitShiftLeftPercentEq: return "<<%="; + case TokenIdBitShiftRight: return ">>"; case TokenIdBitShiftRightEq: return ">>="; - case TokenIdBitAndEq: return "&="; case TokenIdBitXorEq: return "^="; - case TokenIdBitOrEq: return "|="; + case TokenIdBoolAnd: return "&&"; case TokenIdBoolAndEq: return "&&="; + case TokenIdBoolOr: return "||"; case TokenIdBoolOrEq: return "||="; - case TokenIdBang: return "!"; - case TokenIdTilde: return "~"; + case TokenIdCharLiteral: return "CharLiteral"; case TokenIdCmpEq: return "=="; - case TokenIdCmpNotEq: return "!="; - case TokenIdCmpLessThan: return "<"; + case TokenIdCmpGreaterOrEq: return ">="; case TokenIdCmpGreaterThan: return ">"; case TokenIdCmpLessOrEq: return "<="; - case TokenIdCmpGreaterOrEq: return ">="; - case TokenIdBitShiftLeft: return "<<"; - case TokenIdBitShiftRight: return ">>"; - case TokenIdSlash: return "/"; - case TokenIdPercent: return "%"; - case TokenIdPercentPercent: return "%%"; + case TokenIdCmpLessThan: return "<"; + case TokenIdCmpNotEq: return "!="; + case TokenIdColon: return ":"; + case TokenIdComma: return ","; + case TokenIdDash: return "-"; + case TokenIdDivEq: return "/="; case TokenIdDot: return "."; + case TokenIdDoubleQuestion: return "??"; case TokenIdEllipsis: return "..."; + case TokenIdEof: return "EOF"; + case TokenIdEq: return "="; + case TokenIdFatArrow: return "=>"; + case TokenIdKeywordAsm: return "asm"; + case TokenIdKeywordBreak: return "break"; + case TokenIdKeywordColdCC: return "coldcc"; + case TokenIdKeywordCompTime: return "comptime"; + case TokenIdKeywordConst: return "const"; + case TokenIdKeywordContinue: return "continue"; + case TokenIdKeywordDefer: return "defer"; + case TokenIdKeywordElse: return "else"; + case TokenIdKeywordEnum: return "enum"; + case TokenIdKeywordError: return "error"; + case TokenIdKeywordExport: return "export"; + case TokenIdKeywordExtern: return "extern"; + case TokenIdKeywordFalse: return "false"; + case TokenIdKeywordFn: return "fn"; + case TokenIdKeywordFor: return "for"; + case TokenIdKeywordGoto: return "goto"; + case TokenIdKeywordIf: return "if"; + case TokenIdKeywordInline: return "inline"; + case TokenIdKeywordNakedCC: return "nakedcc"; + case TokenIdKeywordNoAlias: return "noalias"; + case TokenIdKeywordNull: return "null"; + case TokenIdKeywordPub: return "pub"; + case TokenIdKeywordReturn: return "return"; + case TokenIdKeywordStruct: return "struct"; + case TokenIdKeywordSwitch: return "switch"; + case TokenIdKeywordThis: return "this"; + case TokenIdKeywordTrue: return "true"; + case TokenIdKeywordTry: return "try"; + case TokenIdKeywordType: return "type"; + case TokenIdKeywordUndefined: return "undefined"; + case TokenIdKeywordUnion: return "union"; + case TokenIdKeywordUse: return "use"; + case TokenIdKeywordVar: return "var"; + case TokenIdKeywordVolatile: return "volatile"; + case TokenIdKeywordWhile: return "while"; + case TokenIdLBrace: return "{"; + case TokenIdLBracket: return "["; + case TokenIdLParen: return "("; case TokenIdMaybe: return "?"; - case TokenIdDoubleQuestion: return "??"; case TokenIdMaybeAssign: return "?="; - case TokenIdAtSign: return "@"; + case TokenIdMinusEq: return "-="; + case TokenIdMinusPercent: return "-%"; + case TokenIdMinusPercentEq: return "-%="; + case TokenIdModEq: return "%="; + case TokenIdNumberLiteral: return "NumberLiteral"; + case TokenIdNumberSign: return "#"; + case TokenIdPercent: return "%"; case TokenIdPercentDot: return "%."; - case TokenIdTimesPercent: return "*%"; - case TokenIdTimesPercentEq: return "*%="; + case TokenIdPercentPercent: return "%%"; + case TokenIdPlus: return "+"; + case TokenIdPlusEq: return "+="; case TokenIdPlusPercent: return "+%"; case TokenIdPlusPercentEq: return "+%="; - case TokenIdMinusPercent: return "-%"; - case TokenIdMinusPercentEq: return "-%="; - case TokenIdBitShiftLeftPercent: return "<<%"; - case TokenIdBitShiftLeftPercentEq: return "<<%="; + case TokenIdPlusPlus: return "++"; + case TokenIdRBrace: return "}"; + case TokenIdRBracket: return "]"; + case TokenIdRParen: return ")"; + case TokenIdSemicolon: return ";"; + case TokenIdSlash: return "/"; + case TokenIdStar: return "*"; + case TokenIdStarStar: return "**"; + case TokenIdStringLiteral: return "StringLiteral"; + case TokenIdSymbol: return "Symbol"; + case TokenIdTilde: return "~"; + case TokenIdTimesEq: return "*="; + case TokenIdTimesPercent: return "*%"; + case TokenIdTimesPercentEq: return "*%="; } return "(invalid token)"; } diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index ed57288b74..d004ad4241 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -25,6 +25,7 @@ enum TokenId { TokenIdKeywordTrue, TokenIdKeywordFalse, TokenIdKeywordIf, + TokenIdKeywordTry, TokenIdKeywordElse, TokenIdKeywordGoto, TokenIdKeywordAsm, diff --git a/std/debug.zig b/std/debug.zig index 15aebf3a23..85e5503fa8 100644 --- a/std/debug.zig +++ b/std/debug.zig @@ -9,8 +9,8 @@ error MissingDebugInfo; error InvalidDebugInfo; error UnsupportedDebugInfo; -pub fn assert(b: bool) { - if (!b) @unreachable() +pub fn assert(ok: bool) { + if (!ok) @unreachable() } pub fn printStackTrace() -> %void { diff --git a/test/cases/try.zig b/test/cases/try.zig new file mode 100644 index 0000000000..17b78b2115 --- /dev/null +++ b/test/cases/try.zig @@ -0,0 +1,33 @@ +const assert = @import("std").debug.assert; + +fn tryOnErrorUnion() { + @setFnTest(this); + + const x = try (const val = returnsTen()) { + val + 1 + } else |err| switch (err) { + error.ItBroke, error.NoMem => 1, + error.CrappedOut => i32(2), + }; + assert(x == 11); +} + +fn tryOnErrorUnionComptime() { + @setFnTest(this); + + comptime { + const x = try (const val = returnsTen()) { + val + 1 + } else |err| switch (err) { + error.ItBroke, error.NoMem => 1, + error.CrappedOut => i32(2), + }; + assert(x == 11); + } +} +error ItBroke; +error NoMem; +error CrappedOut; +fn returnsTen() -> %i32 { + 10 +} diff --git a/test/self_hosted.zig b/test/self_hosted.zig index 6276633fd4..fd63addf09 100644 --- a/test/self_hosted.zig +++ b/test/self_hosted.zig @@ -28,6 +28,7 @@ const test_switch = @import("cases/switch.zig"); const test_switch_prong_err_enum = @import("cases/switch_prong_err_enum.zig"); const test_switch_prong_implicit_cast = @import("cases/switch_prong_implicit_cast.zig"); const test_this = @import("cases/this.zig"); +const test_try = @import("cases/try.zig"); const test_undefined = @import("cases/undefined.zig"); const test_var_args = @import("cases/var_args.zig"); const test_while = @import("cases/while.zig"); |
