mirror of
https://github.com/ziglang/zig.git
synced 2026-02-21 16:54:52 +00:00
parent
bcb18338cd
commit
6db6609df8
@ -59,9 +59,13 @@ AsmInputItem : "[" "Symbol" "]" "String" "(" Expression ")"
|
||||
|
||||
AsmClobbers: ":" list("String", ",")
|
||||
|
||||
UnwrapMaybeExpression : BoolOrExpression "??" BoolOrExpression | BoolOrExpression
|
||||
UnwrapExpression : BoolOrExpression (UnwrapMaybe | UnwrapError) | BoolOrExpression
|
||||
|
||||
AssignmentExpression : UnwrapMaybeExpression AssignmentOperator UnwrapMaybeExpression | UnwrapMaybeExpression
|
||||
UnwrapMaybe : "??" BoolOrExpression
|
||||
|
||||
UnwrapError : "%%" option("|" "Symbol" "|") BoolOrExpression
|
||||
|
||||
AssignmentExpression : UnwrapExpression AssignmentOperator UnwrapExpression | UnwrapExpression
|
||||
|
||||
AssignmentOperator : "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | "&=" | "^=" | "|=" | "&&=" | "||="
|
||||
|
||||
@ -161,7 +165,7 @@ x{}
|
||||
== != < > <= >=
|
||||
&&
|
||||
||
|
||||
??
|
||||
?? %%
|
||||
= *= /= %= += -= <<= >>= &= ^= |= &&= ||=
|
||||
```
|
||||
|
||||
|
||||
@ -4,9 +4,7 @@ import "std.zig";
|
||||
|
||||
// Things to do to make this work:
|
||||
// * var args printing
|
||||
// * update std API
|
||||
// * defer
|
||||
// * %return
|
||||
// * %% binary operator
|
||||
// * %% prefix operator
|
||||
// * cast err type to string
|
||||
|
||||
@ -8,7 +8,7 @@ pub fn main(args: [][]u8) %void => {
|
||||
|
||||
var seed : u32;
|
||||
const seed_bytes = (&u8)(&seed)[0...4];
|
||||
os_get_random_bytes(seed_bytes);
|
||||
os_get_random_bytes(seed_bytes) %% unreachable{};
|
||||
|
||||
var rand = rand_new(seed);
|
||||
|
||||
@ -18,13 +18,16 @@ pub fn main(args: [][]u8) %void => {
|
||||
stderr.print_str("\nGuess a number between 1 and 100: ");
|
||||
var line_buf : [20]u8;
|
||||
|
||||
// TODO print error message instead of returning
|
||||
const line_len = %return stdin.readline(line_buf);
|
||||
const line_len = stdin.read(line_buf) %% |err| {
|
||||
stderr.print_str("Unable to read from stdin.\n");
|
||||
return err;
|
||||
};
|
||||
|
||||
var guess : u64;
|
||||
if (parse_u64(line_buf[0...line_len - 1], 10, &guess)) {
|
||||
stderr.print_str("Invalid number format.\n");
|
||||
} else if (guess > answer) {
|
||||
const guess = parse_u64(line_buf[0...line_len - 1], 10) %% {
|
||||
stderr.print_str("Invalid number.\n");
|
||||
continue;
|
||||
};
|
||||
if (guess > answer) {
|
||||
stderr.print_str("Guess lower.\n");
|
||||
} else if (guess < answer) {
|
||||
stderr.print_str("Guess higher.\n");
|
||||
|
||||
@ -130,6 +130,7 @@ enum NodeType {
|
||||
NodeTypeVariableDeclaration,
|
||||
NodeTypeErrorValueDecl,
|
||||
NodeTypeBinOpExpr,
|
||||
NodeTypeUnwrapErrorExpr,
|
||||
NodeTypeNumberLiteral,
|
||||
NodeTypeStringLiteral,
|
||||
NodeTypeCharLiteral,
|
||||
@ -310,6 +311,16 @@ struct AstNodeBinOpExpr {
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeUnwrapErrorExpr {
|
||||
AstNode *op1;
|
||||
AstNode *symbol; // can be null
|
||||
AstNode *op2;
|
||||
|
||||
// populated by semantic analyzer:
|
||||
Expr resolved_expr;
|
||||
VariableTableEntry *var;
|
||||
};
|
||||
|
||||
enum CastOp {
|
||||
CastOpNoCast, // signifies the function call expression is not a cast
|
||||
CastOpNoop, // fn call expr is a cast, but does nothing
|
||||
@ -684,6 +695,7 @@ struct AstNode {
|
||||
AstNodeVariableDeclaration variable_declaration;
|
||||
AstNodeErrorValueDecl error_value_decl;
|
||||
AstNodeBinOpExpr bin_op_expr;
|
||||
AstNodeUnwrapErrorExpr unwrap_err_expr;
|
||||
AstNodeExternBlock extern_block;
|
||||
AstNodeDirective directive;
|
||||
AstNodePrefixOpExpr prefix_op_expr;
|
||||
|
||||
@ -28,6 +28,8 @@ static AstNode *first_executing_node(AstNode *node) {
|
||||
return first_executing_node(node->data.fn_call_expr.fn_ref_expr);
|
||||
case NodeTypeBinOpExpr:
|
||||
return first_executing_node(node->data.bin_op_expr.op1);
|
||||
case NodeTypeUnwrapErrorExpr:
|
||||
return first_executing_node(node->data.unwrap_err_expr.op1);
|
||||
case NodeTypeArrayAccessExpr:
|
||||
return first_executing_node(node->data.array_access_expr.array_ref_expr);
|
||||
case NodeTypeSliceExpr:
|
||||
@ -1076,6 +1078,7 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
|
||||
case NodeTypeRoot:
|
||||
case NodeTypeBlock:
|
||||
case NodeTypeBinOpExpr:
|
||||
case NodeTypeUnwrapErrorExpr:
|
||||
case NodeTypeFnCallExpr:
|
||||
case NodeTypeArrayAccessExpr:
|
||||
case NodeTypeSliceExpr:
|
||||
@ -2502,6 +2505,38 @@ static VariableTableEntry *add_local_var(CodeGen *g, AstNode *source_node, Block
|
||||
return variable_entry;
|
||||
}
|
||||
|
||||
static TypeTableEntry *analyze_unwrap_error_expr(CodeGen *g, ImportTableEntry *import,
|
||||
BlockContext *parent_context, TypeTableEntry *expected_type, AstNode *node)
|
||||
{
|
||||
AstNode *op1 = node->data.unwrap_err_expr.op1;
|
||||
AstNode *op2 = node->data.unwrap_err_expr.op2;
|
||||
AstNode *var_node = node->data.unwrap_err_expr.symbol;
|
||||
|
||||
TypeTableEntry *lhs_type = analyze_expression(g, import, parent_context, nullptr, op1);
|
||||
if (lhs_type->id == TypeTableEntryIdInvalid) {
|
||||
return lhs_type;
|
||||
} else if (lhs_type->id == TypeTableEntryIdErrorUnion) {
|
||||
TypeTableEntry *child_type = lhs_type->data.error.child_type;
|
||||
BlockContext *child_context;
|
||||
if (var_node) {
|
||||
child_context = new_block_context(node, parent_context);
|
||||
Buf *var_name = &var_node->data.symbol_expr.symbol;
|
||||
node->data.unwrap_err_expr.var = add_local_var(g, var_node, child_context, var_name,
|
||||
g->builtin_types.entry_pure_error, true);
|
||||
} else {
|
||||
child_context = parent_context;
|
||||
}
|
||||
|
||||
analyze_expression(g, import, child_context, child_type, op2);
|
||||
return child_type;
|
||||
} else {
|
||||
add_node_error(g, op1,
|
||||
buf_sprintf("expected error type, got '%s'", buf_ptr(&lhs_type->name)));
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import,
|
||||
BlockContext *context, AstNode *source_node,
|
||||
AstNodeVariableDeclaration *variable_declaration,
|
||||
@ -3845,7 +3880,9 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import,
|
||||
case NodeTypeBinOpExpr:
|
||||
return_type = analyze_bin_op_expr(g, import, context, expected_type, node);
|
||||
break;
|
||||
|
||||
case NodeTypeUnwrapErrorExpr:
|
||||
return_type = analyze_unwrap_error_expr(g, import, context, expected_type, node);
|
||||
break;
|
||||
case NodeTypeFnCallExpr:
|
||||
return_type = analyze_fn_call_expr(g, import, context, expected_type, node);
|
||||
break;
|
||||
@ -4035,6 +4072,7 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
|
||||
case NodeTypeRoot:
|
||||
case NodeTypeBlock:
|
||||
case NodeTypeBinOpExpr:
|
||||
case NodeTypeUnwrapErrorExpr:
|
||||
case NodeTypeFnCallExpr:
|
||||
case NodeTypeArrayAccessExpr:
|
||||
case NodeTypeSliceExpr:
|
||||
@ -4101,6 +4139,10 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
|
||||
collect_expr_decl_deps(g, import, node->data.bin_op_expr.op1, decl_node);
|
||||
collect_expr_decl_deps(g, import, node->data.bin_op_expr.op2, decl_node);
|
||||
break;
|
||||
case NodeTypeUnwrapErrorExpr:
|
||||
collect_expr_decl_deps(g, import, node->data.unwrap_err_expr.op1, decl_node);
|
||||
collect_expr_decl_deps(g, import, node->data.unwrap_err_expr.op2, decl_node);
|
||||
break;
|
||||
case NodeTypeReturnExpr:
|
||||
collect_expr_decl_deps(g, import, node->data.return_expr.expr, decl_node);
|
||||
break;
|
||||
@ -4388,6 +4430,7 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
|
||||
case NodeTypeRoot:
|
||||
case NodeTypeBlock:
|
||||
case NodeTypeBinOpExpr:
|
||||
case NodeTypeUnwrapErrorExpr:
|
||||
case NodeTypeFnCallExpr:
|
||||
case NodeTypeArrayAccessExpr:
|
||||
case NodeTypeSliceExpr:
|
||||
@ -4582,6 +4625,8 @@ Expr *get_resolved_expr(AstNode *node) {
|
||||
return &node->data.return_expr.resolved_expr;
|
||||
case NodeTypeBinOpExpr:
|
||||
return &node->data.bin_op_expr.resolved_expr;
|
||||
case NodeTypeUnwrapErrorExpr:
|
||||
return &node->data.unwrap_err_expr.resolved_expr;
|
||||
case NodeTypePrefixOpExpr:
|
||||
return &node->data.prefix_op_expr.resolved_expr;
|
||||
case NodeTypeFnCallExpr:
|
||||
@ -4669,6 +4714,7 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) {
|
||||
case NodeTypeNumberLiteral:
|
||||
case NodeTypeReturnExpr:
|
||||
case NodeTypeBinOpExpr:
|
||||
case NodeTypeUnwrapErrorExpr:
|
||||
case NodeTypePrefixOpExpr:
|
||||
case NodeTypeFnCallExpr:
|
||||
case NodeTypeArrayAccessExpr:
|
||||
@ -4747,10 +4793,30 @@ TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, int size_in_bits) {
|
||||
}
|
||||
|
||||
bool handle_is_ptr(TypeTableEntry *type_entry) {
|
||||
return type_entry->id == TypeTableEntryIdStruct ||
|
||||
(type_entry->id == TypeTableEntryIdEnum && type_entry->data.enumeration.gen_field_count != 0) ||
|
||||
type_entry->id == TypeTableEntryIdMaybe ||
|
||||
type_entry->id == TypeTableEntryIdArray ||
|
||||
(type_entry->id == TypeTableEntryIdErrorUnion && type_entry->data.error.child_type->size_in_bits > 0);
|
||||
switch (type_entry->id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdMetaType:
|
||||
case TypeTableEntryIdNumLitFloat:
|
||||
case TypeTableEntryIdNumLitInt:
|
||||
case TypeTableEntryIdUndefLit:
|
||||
zig_unreachable();
|
||||
case TypeTableEntryIdUnreachable:
|
||||
case TypeTableEntryIdVoid:
|
||||
case TypeTableEntryIdBool:
|
||||
case TypeTableEntryIdInt:
|
||||
case TypeTableEntryIdFloat:
|
||||
case TypeTableEntryIdPointer:
|
||||
case TypeTableEntryIdPureError:
|
||||
case TypeTableEntryIdFn:
|
||||
return false;
|
||||
case TypeTableEntryIdArray:
|
||||
case TypeTableEntryIdStruct:
|
||||
case TypeTableEntryIdMaybe:
|
||||
return true;
|
||||
case TypeTableEntryIdErrorUnion:
|
||||
return type_entry->data.error.child_type->size_in_bits > 0;
|
||||
case TypeTableEntryIdEnum:
|
||||
return type_entry->data.enumeration.gen_field_count != 0;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
|
||||
@ -1255,6 +1255,78 @@ static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_unwrap_err_expr(CodeGen *g, AstNode *node) {
|
||||
assert(node->type == NodeTypeUnwrapErrorExpr);
|
||||
|
||||
AstNode *op1 = node->data.unwrap_err_expr.op1;
|
||||
AstNode *op2 = node->data.unwrap_err_expr.op2;
|
||||
VariableTableEntry *var = node->data.unwrap_err_expr.var;
|
||||
|
||||
LLVMValueRef expr_val = gen_expr(g, op1);
|
||||
TypeTableEntry *expr_type = get_expr_type(op1);
|
||||
TypeTableEntry *op2_type = get_expr_type(op2);
|
||||
assert(expr_type->id == TypeTableEntryIdErrorUnion);
|
||||
TypeTableEntry *child_type = expr_type->data.error.child_type;
|
||||
LLVMValueRef err_val;
|
||||
add_debug_source_node(g, node);
|
||||
if (handle_is_ptr(expr_type)) {
|
||||
LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, expr_val, 0, "");
|
||||
err_val = LLVMBuildLoad(g->builder, err_val_ptr, "");
|
||||
} else {
|
||||
err_val = expr_val;
|
||||
}
|
||||
LLVMValueRef zero = LLVMConstNull(g->err_tag_type->type_ref);
|
||||
LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, zero, "");
|
||||
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapErrOk");
|
||||
LLVMBasicBlockRef err_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapErrError");
|
||||
LLVMBasicBlockRef end_block;
|
||||
bool err_reachable = op2_type->id != TypeTableEntryIdUnreachable;
|
||||
bool have_end_block = err_reachable && (child_type->size_in_bits > 0);
|
||||
if (have_end_block) {
|
||||
end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapErrEnd");
|
||||
}
|
||||
|
||||
LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block);
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, err_block);
|
||||
if (var) {
|
||||
LLVMBuildStore(g->builder, err_val, var->value_ref);
|
||||
}
|
||||
LLVMValueRef err_result = gen_expr(g, op2);
|
||||
add_debug_source_node(g, node);
|
||||
if (have_end_block) {
|
||||
LLVMBuildBr(g->builder, end_block);
|
||||
} else if (err_reachable) {
|
||||
LLVMBuildBr(g->builder, ok_block);
|
||||
}
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, ok_block);
|
||||
if (child_type->size_in_bits == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
LLVMValueRef child_val_ptr = LLVMBuildStructGEP(g->builder, expr_val, 1, "");
|
||||
LLVMValueRef child_val;
|
||||
if (handle_is_ptr(child_type)) {
|
||||
child_val = child_val_ptr;
|
||||
} else {
|
||||
child_val = LLVMBuildLoad(g->builder, child_val_ptr, "");
|
||||
}
|
||||
|
||||
if (!have_end_block) {
|
||||
return child_val;
|
||||
}
|
||||
|
||||
LLVMBuildBr(g->builder, end_block);
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, end_block);
|
||||
LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(err_result), "");
|
||||
LLVMValueRef incoming_values[2] = {child_val, err_result};
|
||||
LLVMBasicBlockRef incoming_blocks[2] = {ok_block, err_block};
|
||||
LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
|
||||
return phi;
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_return(CodeGen *g, AstNode *source_node, LLVMValueRef value) {
|
||||
TypeTableEntry *return_type = g->cur_fn->type_entry->data.fn.src_return_type;
|
||||
if (handle_is_ptr(return_type)) {
|
||||
@ -2047,6 +2119,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
|
||||
switch (node->type) {
|
||||
case NodeTypeBinOpExpr:
|
||||
return gen_bin_op_expr(g, node);
|
||||
case NodeTypeUnwrapErrorExpr:
|
||||
return gen_unwrap_err_expr(g, node);
|
||||
case NodeTypeReturnExpr:
|
||||
return gen_return_expr(g, node);
|
||||
case NodeTypeVariableDeclaration:
|
||||
|
||||
@ -95,6 +95,8 @@ const char *node_type_str(NodeType node_type) {
|
||||
return "Block";
|
||||
case NodeTypeBinOpExpr:
|
||||
return "BinOpExpr";
|
||||
case NodeTypeUnwrapErrorExpr:
|
||||
return "UnwrapErrorExpr";
|
||||
case NodeTypeFnCallExpr:
|
||||
return "FnCallExpr";
|
||||
case NodeTypeArrayAccessExpr:
|
||||
@ -273,6 +275,14 @@ void ast_print(AstNode *node, int indent) {
|
||||
ast_print(node->data.bin_op_expr.op1, indent + 2);
|
||||
ast_print(node->data.bin_op_expr.op2, indent + 2);
|
||||
break;
|
||||
case NodeTypeUnwrapErrorExpr:
|
||||
fprintf(stderr, "%s\n", node_type_str(node->type));
|
||||
ast_print(node->data.unwrap_err_expr.op1, indent + 2);
|
||||
if (node->data.unwrap_err_expr.symbol) {
|
||||
ast_print(node->data.unwrap_err_expr.symbol, indent + 2);
|
||||
}
|
||||
ast_print(node->data.unwrap_err_expr.op2, indent + 2);
|
||||
break;
|
||||
case NodeTypeFnCallExpr:
|
||||
fprintf(stderr, "%s\n", node_type_str(node->type));
|
||||
ast_print(node->data.fn_call_expr.fn_ref_expr, indent + 2);
|
||||
@ -964,7 +974,7 @@ static AstNode *ast_parse_expression(ParseContext *pc, int *token_index, bool ma
|
||||
static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandatory);
|
||||
static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool mandatory);
|
||||
static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool mandatory);
|
||||
static AstNode *ast_parse_unwrap_maybe_expr(ParseContext *pc, int *token_index, bool mandatory);
|
||||
static AstNode *ast_parse_unwrap_expr(ParseContext *pc, int *token_index, bool mandatory);
|
||||
static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, bool mandatory);
|
||||
|
||||
static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) {
|
||||
@ -1032,7 +1042,7 @@ static void ast_parse_directives(ParseContext *pc, int *token_index,
|
||||
}
|
||||
|
||||
/*
|
||||
ParamDecl : option(token(NoAlias)) token(Symbol) token(Colon) UnwrapMaybeExpression | token(Ellipsis)
|
||||
ParamDecl : option("noalias") "Symbol" ":" PrefixOpExpression | "..."
|
||||
*/
|
||||
static AstNode *ast_parse_param_decl(ParseContext *pc, int *token_index) {
|
||||
Token *first_token = &pc->tokens->at(*token_index);
|
||||
@ -1154,7 +1164,7 @@ static AstNode *ast_parse_grouped_expr(ParseContext *pc, int *token_index, bool
|
||||
}
|
||||
|
||||
/*
|
||||
ArrayType : token(LBracket) option(Expression) token(RBracket) option(token(Const)) UnwrapMaybeExpression
|
||||
ArrayType : "[" option(Expression) "]" option("const") PrefixOpExpression
|
||||
*/
|
||||
static AstNode *ast_parse_array_type_expr(ParseContext *pc, int *token_index, bool mandatory) {
|
||||
Token *l_bracket = &pc->tokens->at(*token_index);
|
||||
@ -1207,7 +1217,7 @@ static void ast_parse_asm_input_item(ParseContext *pc, int *token_index, AstNode
|
||||
}
|
||||
|
||||
/*
|
||||
AsmOutputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) (token(Symbol) | token(Arrow) UnwrapMaybeExpression token(RParen)
|
||||
AsmOutputItem : "[" "Symbol" "]" "String" "(" ("Symbol" | "->" PrefixOpExpression) ")"
|
||||
*/
|
||||
static void ast_parse_asm_output_item(ParseContext *pc, int *token_index, AstNode *node) {
|
||||
ast_eat_token(pc, token_index, TokenIdLBracket);
|
||||
@ -2132,7 +2142,7 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool m
|
||||
}
|
||||
|
||||
/*
|
||||
VariableDeclaration : option(FnVisibleMod) (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) UnwrapMaybeExpression option(token(Eq) Expression))
|
||||
VariableDeclaration : option(FnVisibleMod) ("var" | "const") "Symbol" ("=" Expression | ":" PrefixOpExpression option("=" Expression))
|
||||
*/
|
||||
static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token_index, bool mandatory) {
|
||||
Token *first_token = &pc->tokens->at(*token_index);
|
||||
@ -2454,38 +2464,55 @@ static BinOpType ast_parse_ass_op(ParseContext *pc, int *token_index, bool manda
|
||||
}
|
||||
|
||||
/*
|
||||
UnwrapMaybeExpression : BoolOrExpression token(DoubleQuestion) BoolOrExpression | BoolOrExpression
|
||||
UnwrapExpression : BoolOrExpression (UnwrapMaybe | UnwrapError) | BoolOrExpression
|
||||
UnwrapMaybe : "??" BoolOrExpression
|
||||
UnwrapError : "%%" option("|" "Symbol" "|") BoolOrExpression
|
||||
*/
|
||||
// this is currently the first child expression of assignment
|
||||
static AstNode *ast_parse_unwrap_maybe_expr(ParseContext *pc, int *token_index, bool mandatory) {
|
||||
static AstNode *ast_parse_unwrap_expr(ParseContext *pc, int *token_index, bool mandatory) {
|
||||
AstNode *lhs = ast_parse_bool_or_expr(pc, token_index, mandatory);
|
||||
if (!lhs)
|
||||
return nullptr;
|
||||
|
||||
Token *token = &pc->tokens->at(*token_index);
|
||||
|
||||
if (token->id != TokenIdDoubleQuestion) {
|
||||
if (token->id == TokenIdDoubleQuestion) {
|
||||
*token_index += 1;
|
||||
|
||||
AstNode *rhs = ast_parse_bool_or_expr(pc, token_index, true);
|
||||
|
||||
AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
|
||||
node->data.bin_op_expr.op1 = lhs;
|
||||
node->data.bin_op_expr.bin_op = BinOpTypeUnwrapMaybe;
|
||||
node->data.bin_op_expr.op2 = rhs;
|
||||
|
||||
normalize_parent_ptrs(node);
|
||||
return node;
|
||||
} else if (token->id == TokenIdPercentPercent) {
|
||||
*token_index += 1;
|
||||
|
||||
AstNode *node = ast_create_node(pc, NodeTypeUnwrapErrorExpr, token);
|
||||
node->data.unwrap_err_expr.op1 = lhs;
|
||||
|
||||
Token *maybe_bar_tok = &pc->tokens->at(*token_index);
|
||||
if (maybe_bar_tok->id == TokenIdBinOr) {
|
||||
*token_index += 1;
|
||||
node->data.unwrap_err_expr.symbol = ast_parse_symbol(pc, token_index);
|
||||
ast_eat_token(pc, token_index, TokenIdBinOr);
|
||||
}
|
||||
node->data.unwrap_err_expr.op2 = ast_parse_expression(pc, token_index, true);
|
||||
|
||||
normalize_parent_ptrs(node);
|
||||
return node;
|
||||
} else {
|
||||
return lhs;
|
||||
}
|
||||
|
||||
*token_index += 1;
|
||||
|
||||
AstNode *rhs = ast_parse_bool_or_expr(pc, token_index, true);
|
||||
|
||||
AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
|
||||
node->data.bin_op_expr.op1 = lhs;
|
||||
node->data.bin_op_expr.bin_op = BinOpTypeUnwrapMaybe;
|
||||
node->data.bin_op_expr.op2 = rhs;
|
||||
|
||||
normalize_parent_ptrs(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
/*
|
||||
AssignmentExpression : UnwrapMaybeExpression AssignmentOperator UnwrapMaybeExpression | UnwrapMaybeExpression
|
||||
AssignmentExpression : UnwrapExpression AssignmentOperator UnwrapExpression | UnwrapExpression
|
||||
*/
|
||||
static AstNode *ast_parse_ass_expr(ParseContext *pc, int *token_index, bool mandatory) {
|
||||
AstNode *lhs = ast_parse_unwrap_maybe_expr(pc, token_index, mandatory);
|
||||
AstNode *lhs = ast_parse_unwrap_expr(pc, token_index, mandatory);
|
||||
if (!lhs)
|
||||
return nullptr;
|
||||
|
||||
@ -2494,7 +2521,7 @@ static AstNode *ast_parse_ass_expr(ParseContext *pc, int *token_index, bool mand
|
||||
if (ass_op == BinOpTypeInvalid)
|
||||
return lhs;
|
||||
|
||||
AstNode *rhs = ast_parse_unwrap_maybe_expr(pc, token_index, true);
|
||||
AstNode *rhs = ast_parse_unwrap_expr(pc, token_index, true);
|
||||
|
||||
AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
|
||||
node->data.bin_op_expr.op1 = lhs;
|
||||
@ -2646,7 +2673,7 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato
|
||||
}
|
||||
|
||||
/*
|
||||
FnProto : many(Directive) option(FnVisibleMod) token(Fn) token(Symbol) ParamDeclList option(UnwrapMaybeExpression)
|
||||
FnProto : many(Directive) option(FnVisibleMod) "fn" "Symbol" ParamDeclList option(PrefixOpExpression)
|
||||
*/
|
||||
static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mandatory) {
|
||||
Token *first_token = &pc->tokens->at(*token_index);
|
||||
@ -3164,6 +3191,11 @@ void normalize_parent_ptrs(AstNode *node) {
|
||||
set_field(&node->data.bin_op_expr.op1);
|
||||
set_field(&node->data.bin_op_expr.op2);
|
||||
break;
|
||||
case NodeTypeUnwrapErrorExpr:
|
||||
set_field(&node->data.unwrap_err_expr.op1);
|
||||
set_field(&node->data.unwrap_err_expr.symbol);
|
||||
set_field(&node->data.unwrap_err_expr.op2);
|
||||
break;
|
||||
case NodeTypeNumberLiteral:
|
||||
// none
|
||||
break;
|
||||
|
||||
@ -593,6 +593,11 @@ void tokenize(Buf *buf, Tokenization *out) {
|
||||
end_token(&t);
|
||||
t.state = TokenizeStateStart;
|
||||
break;
|
||||
case '%':
|
||||
t.cur_tok->id = TokenIdPercentPercent;
|
||||
end_token(&t);
|
||||
t.state = TokenizeStateStart;
|
||||
break;
|
||||
default:
|
||||
t.pos -= 1;
|
||||
end_token(&t);
|
||||
@ -1097,6 +1102,7 @@ const char * token_name(TokenId id) {
|
||||
case TokenIdBitShiftRight: return ">>";
|
||||
case TokenIdSlash: return "/";
|
||||
case TokenIdPercent: return "%";
|
||||
case TokenIdPercentPercent: return "%%";
|
||||
case TokenIdDot: return ".";
|
||||
case TokenIdEllipsis: return "...";
|
||||
case TokenIdMaybe: return "?";
|
||||
|
||||
@ -87,6 +87,7 @@ enum TokenId {
|
||||
TokenIdBitShiftRight,
|
||||
TokenIdSlash,
|
||||
TokenIdPercent,
|
||||
TokenIdPercentPercent,
|
||||
TokenIdDot,
|
||||
TokenIdEllipsis,
|
||||
TokenIdMaybe,
|
||||
|
||||
18
std/std.zig
18
std/std.zig
@ -130,7 +130,7 @@ pub struct OutStream {
|
||||
pub struct InStream {
|
||||
fd: isize,
|
||||
|
||||
pub fn readline(is: &InStream, buf: []u8) %isize => {
|
||||
pub fn read(is: &InStream, buf: []u8) %isize => {
|
||||
const amt_read = read(is.fd, buf.ptr, buf.len);
|
||||
if (amt_read < 0) {
|
||||
return switch (-amt_read) {
|
||||
@ -144,7 +144,6 @@ pub struct InStream {
|
||||
}
|
||||
return amt_read;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub fn os_get_random_bytes(buf: []u8) %void => {
|
||||
@ -160,30 +159,31 @@ pub fn os_get_random_bytes(buf: []u8) %void => {
|
||||
}
|
||||
|
||||
|
||||
// TODO return %u64 when we support errors
|
||||
pub fn parse_u64(buf: []u8, radix: u8, result: &u64) bool => {
|
||||
pub error InvalidChar;
|
||||
pub error Overflow;
|
||||
|
||||
pub fn parse_u64(buf: []u8, radix: u8) %u64 => {
|
||||
var x : u64 = 0;
|
||||
|
||||
for (c, buf) {
|
||||
const digit = char_to_digit(c);
|
||||
|
||||
if (digit > radix) {
|
||||
return true;
|
||||
return error.InvalidChar;
|
||||
}
|
||||
|
||||
// x *= radix
|
||||
if (@mul_with_overflow(u64, x, radix, &x)) {
|
||||
return true;
|
||||
return error.Overflow;
|
||||
}
|
||||
|
||||
// x += digit
|
||||
if (@add_with_overflow(u64, x, digit, &x)) {
|
||||
return true;
|
||||
return error.Overflow;
|
||||
}
|
||||
}
|
||||
|
||||
*result = x;
|
||||
return false;
|
||||
return x;
|
||||
}
|
||||
|
||||
fn char_to_digit(c: u8) u8 => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user