| ... | @@ -1000,24 +1000,58 @@ pub const Parser = struct { | ... | @@ -1000,24 +1000,58 @@ pub const Parser = struct { |
| 1000 | | 1000 | |
| 1001 | var expression = popSuffixOp(&stack); | 1001 | var expression = popSuffixOp(&stack); |
| 1002 | while (true) { | 1002 | while (true) { |
| 1003 | switch (stack.pop()) { | 1003 | const s = stack.pop(); |
| 1004 | State.Expression => |dest_ptr| { | 1004 | if (s == State.Expression) { |
| 1005 | // we're done | 1005 | const dest_ptr = s.Expression; |
| 1006 | try dest_ptr.store(expression); | 1006 | // we're done |
| | 1007 | try dest_ptr.store(expression); |
| | 1008 | break; |
| | 1009 | } |
| | 1010 | |
| | 1011 | var placement_ptr = &expression; |
| | 1012 | var rhs : &&ast.Node = undefined; |
| | 1013 | const node = blk: { |
| | 1014 | switch (s) { |
| | 1015 | State.InfixOp => |infix_op| { |
| | 1016 | infix_op.lhs = popSuffixOp(&stack); |
| | 1017 | infix_op.rhs = expression; |
| | 1018 | rhs = &infix_op.rhs; |
| | 1019 | break :blk &infix_op.base; |
| | 1020 | }, |
| | 1021 | State.PrefixOp => |prefix_op| { |
| | 1022 | prefix_op.rhs = expression; |
| | 1023 | rhs = &prefix_op.rhs; |
| | 1024 | break :blk &prefix_op.base; |
| | 1025 | }, |
| | 1026 | else => unreachable, |
| | 1027 | } |
| | 1028 | }; |
| | 1029 | const node_perc = precedence(node); |
| | 1030 | |
| | 1031 | while (true) { |
| | 1032 | const perc = precedence(*placement_ptr); |
| | 1033 | |
| | 1034 | if (node_perc > perc) { |
| | 1035 | *placement_ptr = node; |
| 1007 | break; | 1036 | break; |
| 1008 | }, | 1037 | } |
| 1009 | State.InfixOp => |infix_op| { | 1038 | |
| 1010 | infix_op.rhs = expression; | 1039 | switch ((*placement_ptr).id) { |
| 1011 | infix_op.lhs = popSuffixOp(&stack); | 1040 | ast.Node.Id.SuffixOp => { |
| 1012 | expression = &infix_op.base; | 1041 | const suffix_op = @fieldParentPtr(ast.NodeSuffixOp, "base", *placement_ptr); |
| 1013 | continue; | 1042 | placement_ptr = &suffix_op.lhs; |
| 1014 | }, | 1043 | *rhs = suffix_op.lhs; |
| 1015 | State.PrefixOp => |prefix_op| { | 1044 | }, |
| 1016 | prefix_op.rhs = expression; | 1045 | ast.Node.Id.InfixOp => { |
| 1017 | expression = &prefix_op.base; | 1046 | const infix_op = @fieldParentPtr(ast.NodeInfixOp, "base", *placement_ptr); |
| 1018 | continue; | 1047 | placement_ptr = &infix_op.lhs; |
| 1019 | }, | 1048 | *rhs = infix_op.lhs; |
| 1020 | else => unreachable, | 1049 | }, |
| | 1050 | else => { |
| | 1051 | *placement_ptr = node; |
| | 1052 | break; |
| | 1053 | }, |
| | 1054 | } |
| 1021 | } | 1055 | } |
| 1022 | } | 1056 | } |
| 1023 | continue; | 1057 | continue; |
| ... | @@ -1308,6 +1342,99 @@ pub const Parser = struct { | ... | @@ -1308,6 +1342,99 @@ pub const Parser = struct { |
| 1308 | } | 1342 | } |
| 1309 | } | 1343 | } |
| 1310 | | 1344 | |
| | 1345 | fn precedence(node: &ast.Node) u8 { |
| | 1346 | switch (node.id) { |
| | 1347 | ast.Node.Id.PrefixOp => { |
| | 1348 | const prefix_op = @fieldParentPtr(ast.NodePrefixOp, "base", node); |
| | 1349 | switch (prefix_op.op) { |
| | 1350 | ast.NodePrefixOp.PrefixOp.ArrayType, |
| | 1351 | ast.NodePrefixOp.PrefixOp.SliceType => return 1, |
| | 1352 | |
| | 1353 | ast.NodePrefixOp.PrefixOp.BoolNot, |
| | 1354 | ast.NodePrefixOp.PrefixOp.Negation, |
| | 1355 | ast.NodePrefixOp.PrefixOp.NegationWrap, |
| | 1356 | ast.NodePrefixOp.PrefixOp.BitNot, |
| | 1357 | ast.NodePrefixOp.PrefixOp.Deref, |
| | 1358 | ast.NodePrefixOp.PrefixOp.AddrOf, |
| | 1359 | ast.NodePrefixOp.PrefixOp.UnwrapMaybe => return 3, |
| | 1360 | |
| | 1361 | ast.NodePrefixOp.PrefixOp.Try, |
| | 1362 | ast.NodePrefixOp.PrefixOp.Return => return 255, |
| | 1363 | } |
| | 1364 | }, |
| | 1365 | ast.Node.Id.SuffixOp => { |
| | 1366 | const suffix_op = @fieldParentPtr(ast.NodeSuffixOp, "base", node); |
| | 1367 | switch (suffix_op.op) { |
| | 1368 | ast.NodeSuffixOp.SuffixOp.Call, |
| | 1369 | ast.NodeSuffixOp.SuffixOp.Slice, |
| | 1370 | ast.NodeSuffixOp.SuffixOp.ArrayAccess => return 2, |
| | 1371 | |
| | 1372 | ast.NodeSuffixOp.SuffixOp.ArrayInitializer, |
| | 1373 | ast.NodeSuffixOp.SuffixOp.StructInitializer => return 5, |
| | 1374 | } |
| | 1375 | }, |
| | 1376 | ast.Node.Id.InfixOp => { |
| | 1377 | const infix_op = @fieldParentPtr(ast.NodeInfixOp, "base", node); |
| | 1378 | switch (infix_op.op) { |
| | 1379 | ast.NodeInfixOp.InfixOp.Period => return 2, |
| | 1380 | |
| | 1381 | ast.NodeInfixOp.InfixOp.ErrorUnion => return 4, |
| | 1382 | |
| | 1383 | ast.NodeInfixOp.InfixOp.Div, |
| | 1384 | ast.NodeInfixOp.InfixOp.ArrayMult, |
| | 1385 | ast.NodeInfixOp.InfixOp.Mod, |
| | 1386 | ast.NodeInfixOp.InfixOp.Mult, |
| | 1387 | ast.NodeInfixOp.InfixOp.MultWrap => return 6, |
| | 1388 | |
| | 1389 | ast.NodeInfixOp.InfixOp.Add, |
| | 1390 | ast.NodeInfixOp.InfixOp.AddWrap, |
| | 1391 | ast.NodeInfixOp.InfixOp.ArrayCat, |
| | 1392 | ast.NodeInfixOp.InfixOp.Sub, |
| | 1393 | ast.NodeInfixOp.InfixOp.SubWrap => return 7, |
| | 1394 | |
| | 1395 | ast.NodeInfixOp.InfixOp.BitShiftLeft, |
| | 1396 | ast.NodeInfixOp.InfixOp.BitShiftRight => return 8, |
| | 1397 | |
| | 1398 | ast.NodeInfixOp.InfixOp.BitAnd => return 9, |
| | 1399 | |
| | 1400 | ast.NodeInfixOp.InfixOp.BitXor => return 10, |
| | 1401 | |
| | 1402 | ast.NodeInfixOp.InfixOp.BitOr => return 11, |
| | 1403 | |
| | 1404 | ast.NodeInfixOp.InfixOp.EqualEqual, |
| | 1405 | ast.NodeInfixOp.InfixOp.BangEqual, |
| | 1406 | ast.NodeInfixOp.InfixOp.GreaterOrEqual, |
| | 1407 | ast.NodeInfixOp.InfixOp.GreaterThan, |
| | 1408 | ast.NodeInfixOp.InfixOp.LessOrEqual, |
| | 1409 | ast.NodeInfixOp.InfixOp.LessThan => return 12, |
| | 1410 | |
| | 1411 | ast.NodeInfixOp.InfixOp.BoolAnd => return 13, |
| | 1412 | |
| | 1413 | ast.NodeInfixOp.InfixOp.BoolOr => return 14, |
| | 1414 | |
| | 1415 | ast.NodeInfixOp.InfixOp.UnwrapMaybe => return 15, |
| | 1416 | |
| | 1417 | ast.NodeInfixOp.InfixOp.Assign, |
| | 1418 | ast.NodeInfixOp.InfixOp.AssignBitAnd, |
| | 1419 | ast.NodeInfixOp.InfixOp.AssignBitOr, |
| | 1420 | ast.NodeInfixOp.InfixOp.AssignBitShiftLeft, |
| | 1421 | ast.NodeInfixOp.InfixOp.AssignBitShiftRight, |
| | 1422 | ast.NodeInfixOp.InfixOp.AssignBitXor, |
| | 1423 | ast.NodeInfixOp.InfixOp.AssignDiv, |
| | 1424 | ast.NodeInfixOp.InfixOp.AssignMinus, |
| | 1425 | ast.NodeInfixOp.InfixOp.AssignMinusWrap, |
| | 1426 | ast.NodeInfixOp.InfixOp.AssignMod, |
| | 1427 | ast.NodeInfixOp.InfixOp.AssignPlus, |
| | 1428 | ast.NodeInfixOp.InfixOp.AssignPlusWrap, |
| | 1429 | ast.NodeInfixOp.InfixOp.AssignTimes, |
| | 1430 | ast.NodeInfixOp.InfixOp.AssignTimesWarp, |
| | 1431 | ast.NodeInfixOp.InfixOp.MergeErrorSets => return 16, |
| | 1432 | } |
| | 1433 | }, |
| | 1434 | else => return 0, |
| | 1435 | } |
| | 1436 | } |
| | 1437 | |
| 1311 | fn commaOrEnd(self: &Parser, stack: &ArrayList(State), end: &const Token.Id, ptr: &Token, state_after_comma: &const State) !void { | 1438 | fn commaOrEnd(self: &Parser, stack: &ArrayList(State), end: &const Token.Id, ptr: &Token, state_after_comma: &const State) !void { |
| 1312 | var token = self.getNextToken(); | 1439 | var token = self.getNextToken(); |
| 1313 | switch (token.id) { | 1440 | switch (token.id) { |
| ... | @@ -2549,6 +2676,39 @@ test "zig fmt: infix operators" { | ... | @@ -2549,6 +2676,39 @@ test "zig fmt: infix operators" { |
| 2549 | ); | 2676 | ); |
| 2550 | } | 2677 | } |
| 2551 | | 2678 | |
| | 2679 | test "zig fmt: precedence" { |
| | 2680 | try testCanonical( |
| | 2681 | \\test "precedence" { |
| | 2682 | \\ a!b(); |
| | 2683 | \\ (a!b)(); |
| | 2684 | \\ !a!b; |
| | 2685 | \\ !(a!b); |
| | 2686 | \\ a << b + c; |
| | 2687 | \\ (a << b) + c; |
| | 2688 | \\ a & b << c; |
| | 2689 | \\ (a & b) << c; |
| | 2690 | \\ a ^ b & c; |
| | 2691 | \\ (a ^ b) & c; |
| | 2692 | \\ a | b ^ c; |
| | 2693 | \\ (a | b) ^ c; |
| | 2694 | \\ a == b | c; |
| | 2695 | \\ (a == b) | c; |
| | 2696 | \\ a and b == c; |
| | 2697 | \\ (a and b) == c; |
| | 2698 | \\ a or b and c; |
| | 2699 | \\ (a or b) and c; |
| | 2700 | \\ (a or b) and c; |
| | 2701 | \\ a = b or c; |
| | 2702 | \\ (a = b) or c; |
| | 2703 | \\} |
| | 2704 | \\ |
| | 2705 | //\\ !a{}; |
| | 2706 | //\\ !(a{}); |
| | 2707 | //\\ a + b{}; |
| | 2708 | //\\ (a + b){}; |
| | 2709 | ); |
| | 2710 | } |
| | 2711 | |
| 2552 | test "zig fmt: prefix operators" { | 2712 | test "zig fmt: prefix operators" { |
| 2553 | try testCanonical( | 2713 | try testCanonical( |
| 2554 | \\test "prefix operators" { | 2714 | \\test "prefix operators" { |
| ... | @@ -3062,39 +3222,6 @@ test "zig fmt: container initializers" { | ... | @@ -3062,39 +3222,6 @@ test "zig fmt: container initializers" { |
| 3062 | ); | 3222 | ); |
| 3063 | } | 3223 | } |
| 3064 | | 3224 | |
| 3065 | test "zig fmt: precedence" { | | |
| 3066 | try testCanonical( | | |
| 3067 | \\test "precedence" { | | |
| 3068 | \\ a!b(); | | |
| 3069 | \\ (a!b)(); | | |
| 3070 | \\ !a!b; | | |
| 3071 | \\ !(a!b); | | |
| 3072 | \\ !a{}; | | |
| 3073 | \\ !(a{}); | | |
| 3074 | \\ a + b{}; | | |
| 3075 | \\ (a + b){}; | | |
| 3076 | \\ a << b + c; | | |
| 3077 | \\ (a << b) + c; | | |
| 3078 | \\ a & b << c; | | |
| 3079 | \\ (a & b) << c; | | |
| 3080 | \\ a ^ b & c; | | |
| 3081 | \\ (a ^ b) & c; | | |
| 3082 | \\ a | b ^ c; | | |
| 3083 | \\ (a | b) ^ c; | | |
| 3084 | \\ a == b | c; | | |
| 3085 | \\ (a == b) | c; | | |
| 3086 | \\ a and b == c; | | |
| 3087 | \\ (a and b) == c; | | |
| 3088 | \\ a or b and c; | | |
| 3089 | \\ (a or b) and c; | | |
| 3090 | \\ (a or b) and c; | | |
| 3091 | \\ a = b or c; | | |
| 3092 | \\ (a = b) or c; | | |
| 3093 | \\} | | |
| 3094 | \\ | | |
| 3095 | ); | | |
| 3096 | } | | |
| 3097 | | | |
| 3098 | test "zig fmt: zig fmt" { | 3225 | test "zig fmt: zig fmt" { |
| 3099 | try testCanonical(@embedFile("ast.zig")); | 3226 | try testCanonical(@embedFile("ast.zig")); |
| 3100 | try testCanonical(@embedFile("index.zig")); | 3227 | try testCanonical(@embedFile("index.zig")); |