Commit c0b37e8514
Changed files (12)
doc
vim
syntax
std
test
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
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
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;
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();
}
}
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;
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:
src/parser.cpp
@@ -623,6 +623,71 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b
return node;
}
+/*
+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);
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)";
}
src/tokenizer.hpp
@@ -25,6 +25,7 @@ enum TokenId {
TokenIdKeywordTrue,
TokenIdKeywordFalse,
TokenIdKeywordIf,
+ TokenIdKeywordTry,
TokenIdKeywordElse,
TokenIdKeywordGoto,
TokenIdKeywordAsm,
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 {
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
+}
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");