authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-25 13:53:40-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-25 13:53:40-07:00
log6db6609df84bedafebc709bc5865e7f18c862cc6
treeecaf2701dd8b0e9a6022b1592e212d748e287b85
parentbcb18338cd15dfd7a4e3e80e74d1fe395870fa48

implement %% operator

See #23

10 files changed, 247 insertions(+), 51 deletions(-)

doc/langref.md+7-3
...@@ -59,9 +59,13 @@ AsmInputItem : "[" "Symbol" "]" "String" "(" Expression ")"...@@ -59,9 +59,13 @@ AsmInputItem : "[" "Symbol" "]" "String" "(" Expression ")"
5959
60AsmClobbers: ":" list("String", ",")60AsmClobbers: ":" list("String", ",")
6161
62UnwrapMaybeExpression : BoolOrExpression "??" BoolOrExpression | BoolOrExpression62UnwrapExpression : BoolOrExpression (UnwrapMaybe | UnwrapError) | BoolOrExpression
6363
64AssignmentExpression : UnwrapMaybeExpression AssignmentOperator UnwrapMaybeExpression | UnwrapMaybeExpression64UnwrapMaybe : "??" BoolOrExpression
65
66UnwrapError : "%%" option("|" "Symbol" "|") BoolOrExpression
67
68AssignmentExpression : UnwrapExpression AssignmentOperator UnwrapExpression | UnwrapExpression
6569
66AssignmentOperator : "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | "&=" | "^=" | "|=" | "&&=" | "||="70AssignmentOperator : "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | "&=" | "^=" | "|=" | "&&=" | "||="
6771
...@@ -161,7 +165,7 @@ x{}...@@ -161,7 +165,7 @@ x{}
161== != < > <= >=165== != < > <= >=
162&&166&&
163||167||
164??168?? %%
165= *= /= %= += -= <<= >>= &= ^= |= &&= ||=169= *= /= %= += -= <<= >>= &= ^= |= &&= ||=
166```170```
167171
example/cat/main.zig-2
...@@ -4,9 +4,7 @@ import "std.zig";...@@ -4,9 +4,7 @@ import "std.zig";
44
5// Things to do to make this work:5// Things to do to make this work:
6// * var args printing6// * var args printing
7// * update std API
8// * defer7// * defer
9// * %return
10// * %% binary operator8// * %% binary operator
11// * %% prefix operator9// * %% prefix operator
12// * cast err type to string10// * cast err type to string
example/guess_number/main.zig+10-7
...@@ -8,7 +8,7 @@ pub fn main(args: [][]u8) %void => {...@@ -8,7 +8,7 @@ pub fn main(args: [][]u8) %void => {
88
9 var seed : u32;9 var seed : u32;
10 const seed_bytes = (&u8)(&seed)[0...4];10 const seed_bytes = (&u8)(&seed)[0...4];
11 os_get_random_bytes(seed_bytes);11 os_get_random_bytes(seed_bytes) %% unreachable{};
1212
13 var rand = rand_new(seed);13 var rand = rand_new(seed);
1414
...@@ -18,13 +18,16 @@ pub fn main(args: [][]u8) %void => {...@@ -18,13 +18,16 @@ pub fn main(args: [][]u8) %void => {
18 stderr.print_str("\nGuess a number between 1 and 100: ");18 stderr.print_str("\nGuess a number between 1 and 100: ");
19 var line_buf : [20]u8;19 var line_buf : [20]u8;
2020
21 // TODO print error message instead of returning21 const line_len = stdin.read(line_buf) %% |err| {
22 const line_len = %return stdin.readline(line_buf);22 stderr.print_str("Unable to read from stdin.\n");
23 return err;
24 };
2325
24 var guess : u64;26 const guess = parse_u64(line_buf[0...line_len - 1], 10) %% {
25 if (parse_u64(line_buf[0...line_len - 1], 10, &guess)) {27 stderr.print_str("Invalid number.\n");
26 stderr.print_str("Invalid number format.\n");28 continue;
27 } else if (guess > answer) {29 };
30 if (guess > answer) {
28 stderr.print_str("Guess lower.\n");31 stderr.print_str("Guess lower.\n");
29 } else if (guess < answer) {32 } else if (guess < answer) {
30 stderr.print_str("Guess higher.\n");33 stderr.print_str("Guess higher.\n");
src/all_types.hpp+12
...@@ -130,6 +130,7 @@ enum NodeType {...@@ -130,6 +130,7 @@ enum NodeType {
130 NodeTypeVariableDeclaration,130 NodeTypeVariableDeclaration,
131 NodeTypeErrorValueDecl,131 NodeTypeErrorValueDecl,
132 NodeTypeBinOpExpr,132 NodeTypeBinOpExpr,
133 NodeTypeUnwrapErrorExpr,
133 NodeTypeNumberLiteral,134 NodeTypeNumberLiteral,
134 NodeTypeStringLiteral,135 NodeTypeStringLiteral,
135 NodeTypeCharLiteral,136 NodeTypeCharLiteral,
...@@ -310,6 +311,16 @@ struct AstNodeBinOpExpr {...@@ -310,6 +311,16 @@ struct AstNodeBinOpExpr {
310 Expr resolved_expr;311 Expr resolved_expr;
311};312};
312313
314struct AstNodeUnwrapErrorExpr {
315 AstNode *op1;
316 AstNode *symbol; // can be null
317 AstNode *op2;
318
319 // populated by semantic analyzer:
320 Expr resolved_expr;
321 VariableTableEntry *var;
322};
323
313enum CastOp {324enum CastOp {
314 CastOpNoCast, // signifies the function call expression is not a cast325 CastOpNoCast, // signifies the function call expression is not a cast
315 CastOpNoop, // fn call expr is a cast, but does nothing326 CastOpNoop, // fn call expr is a cast, but does nothing
...@@ -684,6 +695,7 @@ struct AstNode {...@@ -684,6 +695,7 @@ struct AstNode {
684 AstNodeVariableDeclaration variable_declaration;695 AstNodeVariableDeclaration variable_declaration;
685 AstNodeErrorValueDecl error_value_decl;696 AstNodeErrorValueDecl error_value_decl;
686 AstNodeBinOpExpr bin_op_expr;697 AstNodeBinOpExpr bin_op_expr;
698 AstNodeUnwrapErrorExpr unwrap_err_expr;
687 AstNodeExternBlock extern_block;699 AstNodeExternBlock extern_block;
688 AstNodeDirective directive;700 AstNodeDirective directive;
689 AstNodePrefixOpExpr prefix_op_expr;701 AstNodePrefixOpExpr prefix_op_expr;
src/analyze.cpp+73-7
...@@ -28,6 +28,8 @@ static AstNode *first_executing_node(AstNode *node) {...@@ -28,6 +28,8 @@ static AstNode *first_executing_node(AstNode *node) {
28 return first_executing_node(node->data.fn_call_expr.fn_ref_expr);28 return first_executing_node(node->data.fn_call_expr.fn_ref_expr);
29 case NodeTypeBinOpExpr:29 case NodeTypeBinOpExpr:
30 return first_executing_node(node->data.bin_op_expr.op1);30 return first_executing_node(node->data.bin_op_expr.op1);
31 case NodeTypeUnwrapErrorExpr:
32 return first_executing_node(node->data.unwrap_err_expr.op1);
31 case NodeTypeArrayAccessExpr:33 case NodeTypeArrayAccessExpr:
32 return first_executing_node(node->data.array_access_expr.array_ref_expr);34 return first_executing_node(node->data.array_access_expr.array_ref_expr);
33 case NodeTypeSliceExpr:35 case NodeTypeSliceExpr:
...@@ -1076,6 +1078,7 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode...@@ -1076,6 +1078,7 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
1076 case NodeTypeRoot:1078 case NodeTypeRoot:
1077 case NodeTypeBlock:1079 case NodeTypeBlock:
1078 case NodeTypeBinOpExpr:1080 case NodeTypeBinOpExpr:
1081 case NodeTypeUnwrapErrorExpr:
1079 case NodeTypeFnCallExpr:1082 case NodeTypeFnCallExpr:
1080 case NodeTypeArrayAccessExpr:1083 case NodeTypeArrayAccessExpr:
1081 case NodeTypeSliceExpr:1084 case NodeTypeSliceExpr:
...@@ -2502,6 +2505,38 @@ static VariableTableEntry *add_local_var(CodeGen *g, AstNode *source_node, Block...@@ -2502,6 +2505,38 @@ static VariableTableEntry *add_local_var(CodeGen *g, AstNode *source_node, Block
2502 return variable_entry;2505 return variable_entry;
2503}2506}
25042507
2508static TypeTableEntry *analyze_unwrap_error_expr(CodeGen *g, ImportTableEntry *import,
2509 BlockContext *parent_context, TypeTableEntry *expected_type, AstNode *node)
2510{
2511 AstNode *op1 = node->data.unwrap_err_expr.op1;
2512 AstNode *op2 = node->data.unwrap_err_expr.op2;
2513 AstNode *var_node = node->data.unwrap_err_expr.symbol;
2514
2515 TypeTableEntry *lhs_type = analyze_expression(g, import, parent_context, nullptr, op1);
2516 if (lhs_type->id == TypeTableEntryIdInvalid) {
2517 return lhs_type;
2518 } else if (lhs_type->id == TypeTableEntryIdErrorUnion) {
2519 TypeTableEntry *child_type = lhs_type->data.error.child_type;
2520 BlockContext *child_context;
2521 if (var_node) {
2522 child_context = new_block_context(node, parent_context);
2523 Buf *var_name = &var_node->data.symbol_expr.symbol;
2524 node->data.unwrap_err_expr.var = add_local_var(g, var_node, child_context, var_name,
2525 g->builtin_types.entry_pure_error, true);
2526 } else {
2527 child_context = parent_context;
2528 }
2529
2530 analyze_expression(g, import, child_context, child_type, op2);
2531 return child_type;
2532 } else {
2533 add_node_error(g, op1,
2534 buf_sprintf("expected error type, got '%s'", buf_ptr(&lhs_type->name)));
2535 return g->builtin_types.entry_invalid;
2536 }
2537}
2538
2539
2505static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import,2540static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import,
2506 BlockContext *context, AstNode *source_node,2541 BlockContext *context, AstNode *source_node,
2507 AstNodeVariableDeclaration *variable_declaration,2542 AstNodeVariableDeclaration *variable_declaration,
...@@ -3845,7 +3880,9 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -3845,7 +3880,9 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import,
3845 case NodeTypeBinOpExpr:3880 case NodeTypeBinOpExpr:
3846 return_type = analyze_bin_op_expr(g, import, context, expected_type, node);3881 return_type = analyze_bin_op_expr(g, import, context, expected_type, node);
3847 break;3882 break;
38483883 case NodeTypeUnwrapErrorExpr:
3884 return_type = analyze_unwrap_error_expr(g, import, context, expected_type, node);
3885 break;
3849 case NodeTypeFnCallExpr:3886 case NodeTypeFnCallExpr:
3850 return_type = analyze_fn_call_expr(g, import, context, expected_type, node);3887 return_type = analyze_fn_call_expr(g, import, context, expected_type, node);
3851 break;3888 break;
...@@ -4035,6 +4072,7 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode...@@ -4035,6 +4072,7 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
4035 case NodeTypeRoot:4072 case NodeTypeRoot:
4036 case NodeTypeBlock:4073 case NodeTypeBlock:
4037 case NodeTypeBinOpExpr:4074 case NodeTypeBinOpExpr:
4075 case NodeTypeUnwrapErrorExpr:
4038 case NodeTypeFnCallExpr:4076 case NodeTypeFnCallExpr:
4039 case NodeTypeArrayAccessExpr:4077 case NodeTypeArrayAccessExpr:
4040 case NodeTypeSliceExpr:4078 case NodeTypeSliceExpr:
...@@ -4101,6 +4139,10 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode...@@ -4101,6 +4139,10 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
4101 collect_expr_decl_deps(g, import, node->data.bin_op_expr.op1, decl_node);4139 collect_expr_decl_deps(g, import, node->data.bin_op_expr.op1, decl_node);
4102 collect_expr_decl_deps(g, import, node->data.bin_op_expr.op2, decl_node);4140 collect_expr_decl_deps(g, import, node->data.bin_op_expr.op2, decl_node);
4103 break;4141 break;
4142 case NodeTypeUnwrapErrorExpr:
4143 collect_expr_decl_deps(g, import, node->data.unwrap_err_expr.op1, decl_node);
4144 collect_expr_decl_deps(g, import, node->data.unwrap_err_expr.op2, decl_node);
4145 break;
4104 case NodeTypeReturnExpr:4146 case NodeTypeReturnExpr:
4105 collect_expr_decl_deps(g, import, node->data.return_expr.expr, decl_node);4147 collect_expr_decl_deps(g, import, node->data.return_expr.expr, decl_node);
4106 break;4148 break;
...@@ -4388,6 +4430,7 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast...@@ -4388,6 +4430,7 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
4388 case NodeTypeRoot:4430 case NodeTypeRoot:
4389 case NodeTypeBlock:4431 case NodeTypeBlock:
4390 case NodeTypeBinOpExpr:4432 case NodeTypeBinOpExpr:
4433 case NodeTypeUnwrapErrorExpr:
4391 case NodeTypeFnCallExpr:4434 case NodeTypeFnCallExpr:
4392 case NodeTypeArrayAccessExpr:4435 case NodeTypeArrayAccessExpr:
4393 case NodeTypeSliceExpr:4436 case NodeTypeSliceExpr:
...@@ -4582,6 +4625,8 @@ Expr *get_resolved_expr(AstNode *node) {...@@ -4582,6 +4625,8 @@ Expr *get_resolved_expr(AstNode *node) {
4582 return &node->data.return_expr.resolved_expr;4625 return &node->data.return_expr.resolved_expr;
4583 case NodeTypeBinOpExpr:4626 case NodeTypeBinOpExpr:
4584 return &node->data.bin_op_expr.resolved_expr;4627 return &node->data.bin_op_expr.resolved_expr;
4628 case NodeTypeUnwrapErrorExpr:
4629 return &node->data.unwrap_err_expr.resolved_expr;
4585 case NodeTypePrefixOpExpr:4630 case NodeTypePrefixOpExpr:
4586 return &node->data.prefix_op_expr.resolved_expr;4631 return &node->data.prefix_op_expr.resolved_expr;
4587 case NodeTypeFnCallExpr:4632 case NodeTypeFnCallExpr:
...@@ -4669,6 +4714,7 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) {...@@ -4669,6 +4714,7 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) {
4669 case NodeTypeNumberLiteral:4714 case NodeTypeNumberLiteral:
4670 case NodeTypeReturnExpr:4715 case NodeTypeReturnExpr:
4671 case NodeTypeBinOpExpr:4716 case NodeTypeBinOpExpr:
4717 case NodeTypeUnwrapErrorExpr:
4672 case NodeTypePrefixOpExpr:4718 case NodeTypePrefixOpExpr:
4673 case NodeTypeFnCallExpr:4719 case NodeTypeFnCallExpr:
4674 case NodeTypeArrayAccessExpr:4720 case NodeTypeArrayAccessExpr:
...@@ -4747,10 +4793,30 @@ TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, int size_in_bits) {...@@ -4747,10 +4793,30 @@ TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, int size_in_bits) {
4747}4793}
47484794
4749bool handle_is_ptr(TypeTableEntry *type_entry) {4795bool handle_is_ptr(TypeTableEntry *type_entry) {
4750 return type_entry->id == TypeTableEntryIdStruct ||4796 switch (type_entry->id) {
4751 (type_entry->id == TypeTableEntryIdEnum && type_entry->data.enumeration.gen_field_count != 0) ||4797 case TypeTableEntryIdInvalid:
4752 type_entry->id == TypeTableEntryIdMaybe ||4798 case TypeTableEntryIdMetaType:
4753 type_entry->id == TypeTableEntryIdArray ||4799 case TypeTableEntryIdNumLitFloat:
4754 (type_entry->id == TypeTableEntryIdErrorUnion && type_entry->data.error.child_type->size_in_bits > 0);4800 case TypeTableEntryIdNumLitInt:
4801 case TypeTableEntryIdUndefLit:
4802 zig_unreachable();
4803 case TypeTableEntryIdUnreachable:
4804 case TypeTableEntryIdVoid:
4805 case TypeTableEntryIdBool:
4806 case TypeTableEntryIdInt:
4807 case TypeTableEntryIdFloat:
4808 case TypeTableEntryIdPointer:
4809 case TypeTableEntryIdPureError:
4810 case TypeTableEntryIdFn:
4811 return false;
4812 case TypeTableEntryIdArray:
4813 case TypeTableEntryIdStruct:
4814 case TypeTableEntryIdMaybe:
4815 return true;
4816 case TypeTableEntryIdErrorUnion:
4817 return type_entry->data.error.child_type->size_in_bits > 0;
4818 case TypeTableEntryIdEnum:
4819 return type_entry->data.enumeration.gen_field_count != 0;
4820 }
4821 zig_unreachable();
4755}4822}
4756
src/codegen.cpp+74
...@@ -1255,6 +1255,78 @@ static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) {...@@ -1255,6 +1255,78 @@ static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) {
1255 zig_unreachable();1255 zig_unreachable();
1256}1256}
12571257
1258static LLVMValueRef gen_unwrap_err_expr(CodeGen *g, AstNode *node) {
1259 assert(node->type == NodeTypeUnwrapErrorExpr);
1260
1261 AstNode *op1 = node->data.unwrap_err_expr.op1;
1262 AstNode *op2 = node->data.unwrap_err_expr.op2;
1263 VariableTableEntry *var = node->data.unwrap_err_expr.var;
1264
1265 LLVMValueRef expr_val = gen_expr(g, op1);
1266 TypeTableEntry *expr_type = get_expr_type(op1);
1267 TypeTableEntry *op2_type = get_expr_type(op2);
1268 assert(expr_type->id == TypeTableEntryIdErrorUnion);
1269 TypeTableEntry *child_type = expr_type->data.error.child_type;
1270 LLVMValueRef err_val;
1271 add_debug_source_node(g, node);
1272 if (handle_is_ptr(expr_type)) {
1273 LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, expr_val, 0, "");
1274 err_val = LLVMBuildLoad(g->builder, err_val_ptr, "");
1275 } else {
1276 err_val = expr_val;
1277 }
1278 LLVMValueRef zero = LLVMConstNull(g->err_tag_type->type_ref);
1279 LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, zero, "");
1280
1281 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapErrOk");
1282 LLVMBasicBlockRef err_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapErrError");
1283 LLVMBasicBlockRef end_block;
1284 bool err_reachable = op2_type->id != TypeTableEntryIdUnreachable;
1285 bool have_end_block = err_reachable && (child_type->size_in_bits > 0);
1286 if (have_end_block) {
1287 end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapErrEnd");
1288 }
1289
1290 LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block);
1291
1292 LLVMPositionBuilderAtEnd(g->builder, err_block);
1293 if (var) {
1294 LLVMBuildStore(g->builder, err_val, var->value_ref);
1295 }
1296 LLVMValueRef err_result = gen_expr(g, op2);
1297 add_debug_source_node(g, node);
1298 if (have_end_block) {
1299 LLVMBuildBr(g->builder, end_block);
1300 } else if (err_reachable) {
1301 LLVMBuildBr(g->builder, ok_block);
1302 }
1303
1304 LLVMPositionBuilderAtEnd(g->builder, ok_block);
1305 if (child_type->size_in_bits == 0) {
1306 return nullptr;
1307 }
1308 LLVMValueRef child_val_ptr = LLVMBuildStructGEP(g->builder, expr_val, 1, "");
1309 LLVMValueRef child_val;
1310 if (handle_is_ptr(child_type)) {
1311 child_val = child_val_ptr;
1312 } else {
1313 child_val = LLVMBuildLoad(g->builder, child_val_ptr, "");
1314 }
1315
1316 if (!have_end_block) {
1317 return child_val;
1318 }
1319
1320 LLVMBuildBr(g->builder, end_block);
1321
1322 LLVMPositionBuilderAtEnd(g->builder, end_block);
1323 LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(err_result), "");
1324 LLVMValueRef incoming_values[2] = {child_val, err_result};
1325 LLVMBasicBlockRef incoming_blocks[2] = {ok_block, err_block};
1326 LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
1327 return phi;
1328}
1329
1258static LLVMValueRef gen_return(CodeGen *g, AstNode *source_node, LLVMValueRef value) {1330static LLVMValueRef gen_return(CodeGen *g, AstNode *source_node, LLVMValueRef value) {
1259 TypeTableEntry *return_type = g->cur_fn->type_entry->data.fn.src_return_type;1331 TypeTableEntry *return_type = g->cur_fn->type_entry->data.fn.src_return_type;
1260 if (handle_is_ptr(return_type)) {1332 if (handle_is_ptr(return_type)) {
...@@ -2047,6 +2119,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {...@@ -2047,6 +2119,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
2047 switch (node->type) {2119 switch (node->type) {
2048 case NodeTypeBinOpExpr:2120 case NodeTypeBinOpExpr:
2049 return gen_bin_op_expr(g, node);2121 return gen_bin_op_expr(g, node);
2122 case NodeTypeUnwrapErrorExpr:
2123 return gen_unwrap_err_expr(g, node);
2050 case NodeTypeReturnExpr:2124 case NodeTypeReturnExpr:
2051 return gen_return_expr(g, node);2125 return gen_return_expr(g, node);
2052 case NodeTypeVariableDeclaration:2126 case NodeTypeVariableDeclaration:
src/parser.cpp+55-23
...@@ -95,6 +95,8 @@ const char *node_type_str(NodeType node_type) {...@@ -95,6 +95,8 @@ const char *node_type_str(NodeType node_type) {
95 return "Block";95 return "Block";
96 case NodeTypeBinOpExpr:96 case NodeTypeBinOpExpr:
97 return "BinOpExpr";97 return "BinOpExpr";
98 case NodeTypeUnwrapErrorExpr:
99 return "UnwrapErrorExpr";
98 case NodeTypeFnCallExpr:100 case NodeTypeFnCallExpr:
99 return "FnCallExpr";101 return "FnCallExpr";
100 case NodeTypeArrayAccessExpr:102 case NodeTypeArrayAccessExpr:
...@@ -273,6 +275,14 @@ void ast_print(AstNode *node, int indent) {...@@ -273,6 +275,14 @@ void ast_print(AstNode *node, int indent) {
273 ast_print(node->data.bin_op_expr.op1, indent + 2);275 ast_print(node->data.bin_op_expr.op1, indent + 2);
274 ast_print(node->data.bin_op_expr.op2, indent + 2);276 ast_print(node->data.bin_op_expr.op2, indent + 2);
275 break;277 break;
278 case NodeTypeUnwrapErrorExpr:
279 fprintf(stderr, "%s\n", node_type_str(node->type));
280 ast_print(node->data.unwrap_err_expr.op1, indent + 2);
281 if (node->data.unwrap_err_expr.symbol) {
282 ast_print(node->data.unwrap_err_expr.symbol, indent + 2);
283 }
284 ast_print(node->data.unwrap_err_expr.op2, indent + 2);
285 break;
276 case NodeTypeFnCallExpr:286 case NodeTypeFnCallExpr:
277 fprintf(stderr, "%s\n", node_type_str(node->type));287 fprintf(stderr, "%s\n", node_type_str(node->type));
278 ast_print(node->data.fn_call_expr.fn_ref_expr, indent + 2);288 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...@@ -964,7 +974,7 @@ static AstNode *ast_parse_expression(ParseContext *pc, int *token_index, bool ma
964static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandatory);974static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandatory);
965static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool mandatory);975static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool mandatory);
966static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool mandatory);976static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool mandatory);
967static AstNode *ast_parse_unwrap_maybe_expr(ParseContext *pc, int *token_index, bool mandatory);977static AstNode *ast_parse_unwrap_expr(ParseContext *pc, int *token_index, bool mandatory);
968static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, bool mandatory);978static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, bool mandatory);
969979
970static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) {980static 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,...@@ -1032,7 +1042,7 @@ static void ast_parse_directives(ParseContext *pc, int *token_index,
1032}1042}
10331043
1034/*1044/*
1035ParamDecl : option(token(NoAlias)) token(Symbol) token(Colon) UnwrapMaybeExpression | token(Ellipsis)1045ParamDecl : option("noalias") "Symbol" ":" PrefixOpExpression | "..."
1036*/1046*/
1037static AstNode *ast_parse_param_decl(ParseContext *pc, int *token_index) {1047static AstNode *ast_parse_param_decl(ParseContext *pc, int *token_index) {
1038 Token *first_token = &pc->tokens->at(*token_index);1048 Token *first_token = &pc->tokens->at(*token_index);
...@@ -1154,7 +1164,7 @@ static AstNode *ast_parse_grouped_expr(ParseContext *pc, int *token_index, bool...@@ -1154,7 +1164,7 @@ static AstNode *ast_parse_grouped_expr(ParseContext *pc, int *token_index, bool
1154}1164}
11551165
1156/*1166/*
1157ArrayType : token(LBracket) option(Expression) token(RBracket) option(token(Const)) UnwrapMaybeExpression1167ArrayType : "[" option(Expression) "]" option("const") PrefixOpExpression
1158*/1168*/
1159static AstNode *ast_parse_array_type_expr(ParseContext *pc, int *token_index, bool mandatory) {1169static AstNode *ast_parse_array_type_expr(ParseContext *pc, int *token_index, bool mandatory) {
1160 Token *l_bracket = &pc->tokens->at(*token_index);1170 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...@@ -1207,7 +1217,7 @@ static void ast_parse_asm_input_item(ParseContext *pc, int *token_index, AstNode
1207}1217}
12081218
1209/*1219/*
1210AsmOutputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) (token(Symbol) | token(Arrow) UnwrapMaybeExpression token(RParen)1220AsmOutputItem : "[" "Symbol" "]" "String" "(" ("Symbol" | "->" PrefixOpExpression) ")"
1211*/1221*/
1212static void ast_parse_asm_output_item(ParseContext *pc, int *token_index, AstNode *node) {1222static void ast_parse_asm_output_item(ParseContext *pc, int *token_index, AstNode *node) {
1213 ast_eat_token(pc, token_index, TokenIdLBracket);1223 ast_eat_token(pc, token_index, TokenIdLBracket);
...@@ -2132,7 +2142,7 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool m...@@ -2132,7 +2142,7 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool m
2132}2142}
21332143
2134/*2144/*
2135VariableDeclaration : option(FnVisibleMod) (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) UnwrapMaybeExpression option(token(Eq) Expression))2145VariableDeclaration : option(FnVisibleMod) ("var" | "const") "Symbol" ("=" Expression | ":" PrefixOpExpression option("=" Expression))
2136*/2146*/
2137static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token_index, bool mandatory) {2147static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token_index, bool mandatory) {
2138 Token *first_token = &pc->tokens->at(*token_index);2148 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...@@ -2454,38 +2464,55 @@ static BinOpType ast_parse_ass_op(ParseContext *pc, int *token_index, bool manda
2454}2464}
24552465
2456/*2466/*
2457UnwrapMaybeExpression : BoolOrExpression token(DoubleQuestion) BoolOrExpression | BoolOrExpression2467UnwrapExpression : BoolOrExpression (UnwrapMaybe | UnwrapError) | BoolOrExpression
2468UnwrapMaybe : "??" BoolOrExpression
2469UnwrapError : "%%" option("|" "Symbol" "|") BoolOrExpression
2458*/2470*/
2459// this is currently the first child expression of assignment2471static AstNode *ast_parse_unwrap_expr(ParseContext *pc, int *token_index, bool mandatory) {
2460static AstNode *ast_parse_unwrap_maybe_expr(ParseContext *pc, int *token_index, bool mandatory) {
2461 AstNode *lhs = ast_parse_bool_or_expr(pc, token_index, mandatory);2472 AstNode *lhs = ast_parse_bool_or_expr(pc, token_index, mandatory);
2462 if (!lhs)2473 if (!lhs)
2463 return nullptr;2474 return nullptr;
24642475
2465 Token *token = &pc->tokens->at(*token_index);2476 Token *token = &pc->tokens->at(*token_index);
24662477
2467 if (token->id != TokenIdDoubleQuestion) {2478 if (token->id == TokenIdDoubleQuestion) {
2468 return lhs;2479 *token_index += 1;
2469 }
24702480
2471 *token_index += 1;2481 AstNode *rhs = ast_parse_bool_or_expr(pc, token_index, true);
24722482
2473 AstNode *rhs = ast_parse_bool_or_expr(pc, token_index, true);2483 AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
2484 node->data.bin_op_expr.op1 = lhs;
2485 node->data.bin_op_expr.bin_op = BinOpTypeUnwrapMaybe;
2486 node->data.bin_op_expr.op2 = rhs;
24742487
2475 AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);2488 normalize_parent_ptrs(node);
2476 node->data.bin_op_expr.op1 = lhs;2489 return node;
2477 node->data.bin_op_expr.bin_op = BinOpTypeUnwrapMaybe;2490 } else if (token->id == TokenIdPercentPercent) {
2478 node->data.bin_op_expr.op2 = rhs;2491 *token_index += 1;
24792492
2480 normalize_parent_ptrs(node);2493 AstNode *node = ast_create_node(pc, NodeTypeUnwrapErrorExpr, token);
2481 return node;2494 node->data.unwrap_err_expr.op1 = lhs;
2495
2496 Token *maybe_bar_tok = &pc->tokens->at(*token_index);
2497 if (maybe_bar_tok->id == TokenIdBinOr) {
2498 *token_index += 1;
2499 node->data.unwrap_err_expr.symbol = ast_parse_symbol(pc, token_index);
2500 ast_eat_token(pc, token_index, TokenIdBinOr);
2501 }
2502 node->data.unwrap_err_expr.op2 = ast_parse_expression(pc, token_index, true);
2503
2504 normalize_parent_ptrs(node);
2505 return node;
2506 } else {
2507 return lhs;
2508 }
2482}2509}
24832510
2484/*2511/*
2485AssignmentExpression : UnwrapMaybeExpression AssignmentOperator UnwrapMaybeExpression | UnwrapMaybeExpression2512AssignmentExpression : UnwrapExpression AssignmentOperator UnwrapExpression | UnwrapExpression
2486*/2513*/
2487static AstNode *ast_parse_ass_expr(ParseContext *pc, int *token_index, bool mandatory) {2514static AstNode *ast_parse_ass_expr(ParseContext *pc, int *token_index, bool mandatory) {
2488 AstNode *lhs = ast_parse_unwrap_maybe_expr(pc, token_index, mandatory);2515 AstNode *lhs = ast_parse_unwrap_expr(pc, token_index, mandatory);
2489 if (!lhs)2516 if (!lhs)
2490 return nullptr;2517 return nullptr;
24912518
...@@ -2494,7 +2521,7 @@ static AstNode *ast_parse_ass_expr(ParseContext *pc, int *token_index, bool mand...@@ -2494,7 +2521,7 @@ static AstNode *ast_parse_ass_expr(ParseContext *pc, int *token_index, bool mand
2494 if (ass_op == BinOpTypeInvalid)2521 if (ass_op == BinOpTypeInvalid)
2495 return lhs;2522 return lhs;
24962523
2497 AstNode *rhs = ast_parse_unwrap_maybe_expr(pc, token_index, true);2524 AstNode *rhs = ast_parse_unwrap_expr(pc, token_index, true);
24982525
2499 AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);2526 AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
2500 node->data.bin_op_expr.op1 = lhs;2527 node->data.bin_op_expr.op1 = lhs;
...@@ -2646,7 +2673,7 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato...@@ -2646,7 +2673,7 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato
2646}2673}
26472674
2648/*2675/*
2649FnProto : many(Directive) option(FnVisibleMod) token(Fn) token(Symbol) ParamDeclList option(UnwrapMaybeExpression)2676FnProto : many(Directive) option(FnVisibleMod) "fn" "Symbol" ParamDeclList option(PrefixOpExpression)
2650*/2677*/
2651static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mandatory) {2678static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mandatory) {
2652 Token *first_token = &pc->tokens->at(*token_index);2679 Token *first_token = &pc->tokens->at(*token_index);
...@@ -3164,6 +3191,11 @@ void normalize_parent_ptrs(AstNode *node) {...@@ -3164,6 +3191,11 @@ void normalize_parent_ptrs(AstNode *node) {
3164 set_field(&node->data.bin_op_expr.op1);3191 set_field(&node->data.bin_op_expr.op1);
3165 set_field(&node->data.bin_op_expr.op2);3192 set_field(&node->data.bin_op_expr.op2);
3166 break;3193 break;
3194 case NodeTypeUnwrapErrorExpr:
3195 set_field(&node->data.unwrap_err_expr.op1);
3196 set_field(&node->data.unwrap_err_expr.symbol);
3197 set_field(&node->data.unwrap_err_expr.op2);
3198 break;
3167 case NodeTypeNumberLiteral:3199 case NodeTypeNumberLiteral:
3168 // none3200 // none
3169 break;3201 break;
src/tokenizer.cpp+6
...@@ -593,6 +593,11 @@ void tokenize(Buf *buf, Tokenization *out) {...@@ -593,6 +593,11 @@ void tokenize(Buf *buf, Tokenization *out) {
593 end_token(&t);593 end_token(&t);
594 t.state = TokenizeStateStart;594 t.state = TokenizeStateStart;
595 break;595 break;
596 case '%':
597 t.cur_tok->id = TokenIdPercentPercent;
598 end_token(&t);
599 t.state = TokenizeStateStart;
600 break;
596 default:601 default:
597 t.pos -= 1;602 t.pos -= 1;
598 end_token(&t);603 end_token(&t);
...@@ -1097,6 +1102,7 @@ const char * token_name(TokenId id) {...@@ -1097,6 +1102,7 @@ const char * token_name(TokenId id) {
1097 case TokenIdBitShiftRight: return ">>";1102 case TokenIdBitShiftRight: return ">>";
1098 case TokenIdSlash: return "/";1103 case TokenIdSlash: return "/";
1099 case TokenIdPercent: return "%";1104 case TokenIdPercent: return "%";
1105 case TokenIdPercentPercent: return "%%";
1100 case TokenIdDot: return ".";1106 case TokenIdDot: return ".";
1101 case TokenIdEllipsis: return "...";1107 case TokenIdEllipsis: return "...";
1102 case TokenIdMaybe: return "?";1108 case TokenIdMaybe: return "?";
src/tokenizer.hpp+1
...@@ -87,6 +87,7 @@ enum TokenId {...@@ -87,6 +87,7 @@ enum TokenId {
87 TokenIdBitShiftRight,87 TokenIdBitShiftRight,
88 TokenIdSlash,88 TokenIdSlash,
89 TokenIdPercent,89 TokenIdPercent,
90 TokenIdPercentPercent,
90 TokenIdDot,91 TokenIdDot,
91 TokenIdEllipsis,92 TokenIdEllipsis,
92 TokenIdMaybe,93 TokenIdMaybe,
std/std.zig+9-9
...@@ -130,7 +130,7 @@ pub struct OutStream {...@@ -130,7 +130,7 @@ pub struct OutStream {
130pub struct InStream {130pub struct InStream {
131 fd: isize,131 fd: isize,
132132
133 pub fn readline(is: &InStream, buf: []u8) %isize => {133 pub fn read(is: &InStream, buf: []u8) %isize => {
134 const amt_read = read(is.fd, buf.ptr, buf.len);134 const amt_read = read(is.fd, buf.ptr, buf.len);
135 if (amt_read < 0) {135 if (amt_read < 0) {
136 return switch (-amt_read) {136 return switch (-amt_read) {
...@@ -144,7 +144,6 @@ pub struct InStream {...@@ -144,7 +144,6 @@ pub struct InStream {
144 }144 }
145 return amt_read;145 return amt_read;
146 }146 }
147
148}147}
149148
150pub fn os_get_random_bytes(buf: []u8) %void => {149pub fn os_get_random_bytes(buf: []u8) %void => {
...@@ -160,30 +159,31 @@ pub fn os_get_random_bytes(buf: []u8) %void => {...@@ -160,30 +159,31 @@ pub fn os_get_random_bytes(buf: []u8) %void => {
160}159}
161160
162161
163// TODO return %u64 when we support errors162pub error InvalidChar;
164pub fn parse_u64(buf: []u8, radix: u8, result: &u64) bool => {163pub error Overflow;
164
165pub fn parse_u64(buf: []u8, radix: u8) %u64 => {
165 var x : u64 = 0;166 var x : u64 = 0;
166167
167 for (c, buf) {168 for (c, buf) {
168 const digit = char_to_digit(c);169 const digit = char_to_digit(c);
169170
170 if (digit > radix) {171 if (digit > radix) {
171 return true;172 return error.InvalidChar;
172 }173 }
173174
174 // x *= radix175 // x *= radix
175 if (@mul_with_overflow(u64, x, radix, &x)) {176 if (@mul_with_overflow(u64, x, radix, &x)) {
176 return true;177 return error.Overflow;
177 }178 }
178179
179 // x += digit180 // x += digit
180 if (@add_with_overflow(u64, x, digit, &x)) {181 if (@add_with_overflow(u64, x, digit, &x)) {
181 return true;182 return error.Overflow;
182 }183 }
183 }184 }
184185
185 *result = x;186 return x;
186 return false;
187}187}
188188
189fn char_to_digit(c: u8) u8 => {189fn char_to_digit(c: u8) u8 => {