| ... | @@ -1309,9 +1309,8 @@ const Parser = struct { | ... | @@ -1309,9 +1309,8 @@ const Parser = struct { |
| 1309 | return expr; | 1309 | return expr; |
| 1310 | } | 1310 | } |
| 1311 | | 1311 | |
| 1312 | /// Expr <- BoolOrExpr | | |
| 1313 | fn parseExpr(p: *Parser) Error!Node.Index { | 1312 | fn parseExpr(p: *Parser) Error!Node.Index { |
| 1314 | return p.parseBoolOrExpr(); | 1313 | return p.parseExprPrecedence(0); |
| 1315 | } | 1314 | } |
| 1316 | | 1315 | |
| 1317 | fn expectExpr(p: *Parser) Error!Node.Index { | 1316 | fn expectExpr(p: *Parser) Error!Node.Index { |
| ... | @@ -1323,263 +1322,100 @@ const Parser = struct { | ... | @@ -1323,263 +1322,100 @@ const Parser = struct { |
| 1323 | } | 1322 | } |
| 1324 | } | 1323 | } |
| 1325 | | 1324 | |
| 1326 | /// BoolOrExpr <- BoolAndExpr (KEYWORD_or BoolAndExpr)* | 1325 | const Assoc = enum { |
| 1327 | fn parseBoolOrExpr(p: *Parser) Error!Node.Index { | 1326 | left, |
| 1328 | var res = try p.parseBoolAndExpr(); | 1327 | none, |
| 1329 | if (res == 0) return null_node; | 1328 | }; |
| 1330 | | 1329 | |
| 1331 | while (true) { | 1330 | const OperInfo = struct { |
| 1332 | switch (p.token_tags[p.tok_i]) { | 1331 | prec: i8, |
| 1333 | .keyword_or => { | 1332 | tag: Node.Tag, |
| 1334 | const or_token = p.nextToken(); | 1333 | assoc: Assoc = Assoc.left, |
| 1335 | const rhs = try p.parseBoolAndExpr(); | 1334 | }; |
| 1336 | if (rhs == 0) { | | |
| 1337 | return p.fail(.invalid_token); | | |
| 1338 | } | | |
| 1339 | res = try p.addNode(.{ | | |
| 1340 | .tag = .bool_or, | | |
| 1341 | .main_token = or_token, | | |
| 1342 | .data = .{ | | |
| 1343 | .lhs = res, | | |
| 1344 | .rhs = rhs, | | |
| 1345 | }, | | |
| 1346 | }); | | |
| 1347 | }, | | |
| 1348 | else => return res, | | |
| 1349 | } | | |
| 1350 | } | | |
| 1351 | } | | |
| 1352 | | 1335 | |
| 1353 | /// BoolAndExpr <- CompareExpr (KEYWORD_and CompareExpr)* | 1336 | // A table of binary operator information. Higher precedence numbers are |
| 1354 | fn parseBoolAndExpr(p: *Parser) !Node.Index { | 1337 | // stickier. All operators at the same precedence level should have the same |
| 1355 | var res = try p.parseCompareExpr(); | 1338 | // associativity. |
| 1356 | if (res == 0) return null_node; | 1339 | const operTable = std.enums.directEnumArrayDefault(Token.Tag, OperInfo, .{ .prec = -1, .tag = Node.Tag.root }, 0, .{ |
| | 1340 | .keyword_or = .{ .prec = 10, .tag = .bool_or }, |
| | 1341 | |
| | 1342 | .keyword_and = .{ .prec = 20, .tag = .bool_and }, |
| | 1343 | .invalid_ampersands = .{ .prec = 20, .tag = .bool_and }, |
| | 1344 | |
| | 1345 | .equal_equal = .{ .prec = 30, .tag = .equal_equal, .assoc = Assoc.none }, |
| | 1346 | .bang_equal = .{ .prec = 30, .tag = .bang_equal, .assoc = Assoc.none }, |
| | 1347 | .angle_bracket_left = .{ .prec = 30, .tag = .less_than, .assoc = Assoc.none }, |
| | 1348 | .angle_bracket_right = .{ .prec = 30, .tag = .greater_than, .assoc = Assoc.none }, |
| | 1349 | .angle_bracket_left_equal = .{ .prec = 30, .tag = .less_or_equal, .assoc = Assoc.none }, |
| | 1350 | .angle_bracket_right_equal = .{ .prec = 30, .tag = .greater_or_equal, .assoc = Assoc.none }, |
| | 1351 | |
| | 1352 | .ampersand = .{ .prec = 40, .tag = .bit_and }, |
| | 1353 | .caret = .{ .prec = 40, .tag = .bit_xor }, |
| | 1354 | .pipe = .{ .prec = 40, .tag = .bit_or }, |
| | 1355 | .keyword_orelse = .{ .prec = 40, .tag = .@"orelse" }, |
| | 1356 | .keyword_catch = .{ .prec = 40, .tag = .@"catch" }, |
| | 1357 | |
| | 1358 | .angle_bracket_angle_bracket_left = .{ .prec = 50, .tag = .bit_shift_left }, |
| | 1359 | .angle_bracket_angle_bracket_right = .{ .prec = 50, .tag = .bit_shift_right }, |
| | 1360 | |
| | 1361 | .plus = .{ .prec = 60, .tag = .add }, |
| | 1362 | .minus = .{ .prec = 60, .tag = .sub }, |
| | 1363 | .plus_plus = .{ .prec = 60, .tag = .array_cat }, |
| | 1364 | .plus_percent = .{ .prec = 60, .tag = .add_wrap }, |
| | 1365 | .minus_percent = .{ .prec = 60, .tag = .sub_wrap }, |
| | 1366 | |
| | 1367 | .pipe_pipe = .{ .prec = 70, .tag = .merge_error_sets }, |
| | 1368 | .asterisk = .{ .prec = 70, .tag = .mul }, |
| | 1369 | .slash = .{ .prec = 70, .tag = .div }, |
| | 1370 | .percent = .{ .prec = 70, .tag = .mod }, |
| | 1371 | .asterisk_asterisk = .{ .prec = 70, .tag = .array_mult }, |
| | 1372 | .asterisk_percent = .{ .prec = 70, .tag = .mul_wrap }, |
| | 1373 | }); |
| 1357 | | 1374 | |
| 1358 | while (true) { | 1375 | fn parseExprPrecedence(p: *Parser, min_prec: i32) Error!Node.Index { |
| 1359 | switch (p.token_tags[p.tok_i]) { | 1376 | var node = try p.parsePrefixExpr(); |
| 1360 | .keyword_and => { | 1377 | if (node == 0) { |
| 1361 | const and_token = p.nextToken(); | 1378 | return null_node; |
| 1362 | const rhs = try p.parseCompareExpr(); | | |
| 1363 | if (rhs == 0) { | | |
| 1364 | return p.fail(.invalid_token); | | |
| 1365 | } | | |
| 1366 | res = try p.addNode(.{ | | |
| 1367 | .tag = .bool_and, | | |
| 1368 | .main_token = and_token, | | |
| 1369 | .data = .{ | | |
| 1370 | .lhs = res, | | |
| 1371 | .rhs = rhs, | | |
| 1372 | }, | | |
| 1373 | }); | | |
| 1374 | }, | | |
| 1375 | .invalid_ampersands => { | | |
| 1376 | try p.warn(.invalid_and); | | |
| 1377 | p.tok_i += 1; | | |
| 1378 | return p.parseCompareExpr(); | | |
| 1379 | }, | | |
| 1380 | else => return res, | | |
| 1381 | } | | |
| 1382 | } | 1379 | } |
| 1383 | } | | |
| 1384 | | 1380 | |
| 1385 | /// CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)? | 1381 | var banned_prec: i8 = -1; |
| 1386 | /// CompareOp | | |
| 1387 | /// <- EQUALEQUAL | | |
| 1388 | /// / EXCLAMATIONMARKEQUAL | | |
| 1389 | /// / LARROW | | |
| 1390 | /// / RARROW | | |
| 1391 | /// / LARROWEQUAL | | |
| 1392 | /// / RARROWEQUAL | | |
| 1393 | fn parseCompareExpr(p: *Parser) !Node.Index { | | |
| 1394 | const expr = try p.parseBitwiseExpr(); | | |
| 1395 | if (expr == 0) return null_node; | | |
| 1396 | | | |
| 1397 | const tag: Node.Tag = switch (p.token_tags[p.tok_i]) { | | |
| 1398 | .equal_equal => .equal_equal, | | |
| 1399 | .bang_equal => .bang_equal, | | |
| 1400 | .angle_bracket_left => .less_than, | | |
| 1401 | .angle_bracket_right => .greater_than, | | |
| 1402 | .angle_bracket_left_equal => .less_or_equal, | | |
| 1403 | .angle_bracket_right_equal => .greater_or_equal, | | |
| 1404 | else => return expr, | | |
| 1405 | }; | | |
| 1406 | return p.addNode(.{ | | |
| 1407 | .tag = tag, | | |
| 1408 | .main_token = p.nextToken(), | | |
| 1409 | .data = .{ | | |
| 1410 | .lhs = expr, | | |
| 1411 | .rhs = try p.expectBitwiseExpr(), | | |
| 1412 | }, | | |
| 1413 | }); | | |
| 1414 | } | | |
| 1415 | | | |
| 1416 | /// BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)* | | |
| 1417 | /// BitwiseOp | | |
| 1418 | /// <- AMPERSAND | | |
| 1419 | /// / CARET | | |
| 1420 | /// / PIPE | | |
| 1421 | /// / KEYWORD_orelse | | |
| 1422 | /// / KEYWORD_catch Payload? | | |
| 1423 | fn parseBitwiseExpr(p: *Parser) !Node.Index { | | |
| 1424 | var res = try p.parseBitShiftExpr(); | | |
| 1425 | if (res == 0) return null_node; | | |
| 1426 | | 1382 | |
| 1427 | while (true) { | 1383 | while (true) { |
| 1428 | const tag: Node.Tag = switch (p.token_tags[p.tok_i]) { | 1384 | const tok_tag = p.token_tags[p.tok_i]; |
| 1429 | .ampersand => .bit_and, | 1385 | const info = operTable[@intCast(usize, @enumToInt(tok_tag))]; |
| 1430 | .caret => .bit_xor, | 1386 | if (info.prec < min_prec or info.prec == banned_prec) { |
| 1431 | .pipe => .bit_or, | 1387 | break; |
| 1432 | .keyword_orelse => .@"orelse", | 1388 | } |
| | 1389 | const oper_token = p.nextToken(); |
| | 1390 | // Special-case handling for "catch" and "&&". |
| | 1391 | switch (tok_tag) { |
| 1433 | .keyword_catch => { | 1392 | .keyword_catch => { |
| 1434 | const catch_token = p.nextToken(); | | |
| 1435 | _ = try p.parsePayload(); | 1393 | _ = try p.parsePayload(); |
| 1436 | const rhs = try p.parseBitShiftExpr(); | | |
| 1437 | if (rhs == 0) { | | |
| 1438 | return p.fail(.invalid_token); | | |
| 1439 | } | | |
| 1440 | res = try p.addNode(.{ | | |
| 1441 | .tag = .@"catch", | | |
| 1442 | .main_token = catch_token, | | |
| 1443 | .data = .{ | | |
| 1444 | .lhs = res, | | |
| 1445 | .rhs = rhs, | | |
| 1446 | }, | | |
| 1447 | }); | | |
| 1448 | continue; | | |
| 1449 | }, | | |
| 1450 | else => return res, | | |
| 1451 | }; | | |
| 1452 | res = try p.addNode(.{ | | |
| 1453 | .tag = tag, | | |
| 1454 | .main_token = p.nextToken(), | | |
| 1455 | .data = .{ | | |
| 1456 | .lhs = res, | | |
| 1457 | .rhs = try p.expectBitShiftExpr(), | | |
| 1458 | }, | 1394 | }, |
| 1459 | }); | 1395 | .invalid_ampersands => { |
| 1460 | } | 1396 | try p.warn(.invalid_and); |
| 1461 | } | | |
| 1462 | | | |
| 1463 | fn expectBitwiseExpr(p: *Parser) Error!Node.Index { | | |
| 1464 | const node = try p.parseBitwiseExpr(); | | |
| 1465 | if (node == 0) { | | |
| 1466 | return p.fail(.invalid_token); | | |
| 1467 | } else { | | |
| 1468 | return node; | | |
| 1469 | } | | |
| 1470 | } | | |
| 1471 | | | |
| 1472 | /// BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)* | | |
| 1473 | /// BitShiftOp | | |
| 1474 | /// <- LARROW2 | | |
| 1475 | /// / RARROW2 | | |
| 1476 | fn parseBitShiftExpr(p: *Parser) Error!Node.Index { | | |
| 1477 | var res = try p.parseAdditionExpr(); | | |
| 1478 | if (res == 0) return null_node; | | |
| 1479 | | | |
| 1480 | while (true) { | | |
| 1481 | const tag: Node.Tag = switch (p.token_tags[p.tok_i]) { | | |
| 1482 | .angle_bracket_angle_bracket_left => .bit_shift_left, | | |
| 1483 | .angle_bracket_angle_bracket_right => .bit_shift_right, | | |
| 1484 | else => return res, | | |
| 1485 | }; | | |
| 1486 | res = try p.addNode(.{ | | |
| 1487 | .tag = tag, | | |
| 1488 | .main_token = p.nextToken(), | | |
| 1489 | .data = .{ | | |
| 1490 | .lhs = res, | | |
| 1491 | .rhs = try p.expectAdditionExpr(), | | |
| 1492 | }, | 1397 | }, |
| 1493 | }); | 1398 | else => {}, |
| 1494 | } | 1399 | } |
| 1495 | } | 1400 | const rhs = try p.parseExprPrecedence(info.prec + 1); |
| 1496 | | 1401 | if (rhs == 0) { |
| 1497 | fn expectBitShiftExpr(p: *Parser) Error!Node.Index { | 1402 | return p.fail(.invalid_token); |
| 1498 | const node = try p.parseBitShiftExpr(); | 1403 | } |
| 1499 | if (node == 0) { | | |
| 1500 | return p.fail(.invalid_token); | | |
| 1501 | } else { | | |
| 1502 | return node; | | |
| 1503 | } | | |
| 1504 | } | | |
| 1505 | | | |
| 1506 | /// AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)* | | |
| 1507 | /// AdditionOp | | |
| 1508 | /// <- PLUS | | |
| 1509 | /// / MINUS | | |
| 1510 | /// / PLUS2 | | |
| 1511 | /// / PLUSPERCENT | | |
| 1512 | /// / MINUSPERCENT | | |
| 1513 | fn parseAdditionExpr(p: *Parser) Error!Node.Index { | | |
| 1514 | var res = try p.parseMultiplyExpr(); | | |
| 1515 | if (res == 0) return null_node; | | |
| 1516 | | 1404 | |
| 1517 | while (true) { | 1405 | node = try p.addNode(.{ |
| 1518 | const tag: Node.Tag = switch (p.token_tags[p.tok_i]) { | 1406 | .tag = info.tag, |
| 1519 | .plus => .add, | 1407 | .main_token = oper_token, |
| 1520 | .minus => .sub, | | |
| 1521 | .plus_plus => .array_cat, | | |
| 1522 | .plus_percent => .add_wrap, | | |
| 1523 | .minus_percent => .sub_wrap, | | |
| 1524 | else => return res, | | |
| 1525 | }; | | |
| 1526 | res = try p.addNode(.{ | | |
| 1527 | .tag = tag, | | |
| 1528 | .main_token = p.nextToken(), | | |
| 1529 | .data = .{ | 1408 | .data = .{ |
| 1530 | .lhs = res, | 1409 | .lhs = node, |
| 1531 | .rhs = try p.expectMultiplyExpr(), | 1410 | .rhs = rhs, |
| 1532 | }, | 1411 | }, |
| 1533 | }); | 1412 | }); |
| 1534 | } | | |
| 1535 | } | | |
| 1536 | | 1413 | |
| 1537 | fn expectAdditionExpr(p: *Parser) Error!Node.Index { | 1414 | if (info.assoc == Assoc.none) { |
| 1538 | const node = try p.parseAdditionExpr(); | 1415 | banned_prec = info.prec; |
| 1539 | if (node == 0) { | 1416 | } |
| 1540 | return p.fail(.invalid_token); | | |
| 1541 | } | | |
| 1542 | return node; | | |
| 1543 | } | | |
| 1544 | | | |
| 1545 | /// MultiplyExpr <- PrefixExpr (MultiplyOp PrefixExpr)* | | |
| 1546 | /// MultiplyOp | | |
| 1547 | /// <- PIPE2 | | |
| 1548 | /// / ASTERISK | | |
| 1549 | /// / SLASH | | |
| 1550 | /// / PERCENT | | |
| 1551 | /// / ASTERISK2 | | |
| 1552 | /// / ASTERISKPERCENT | | |
| 1553 | fn parseMultiplyExpr(p: *Parser) Error!Node.Index { | | |
| 1554 | var res = try p.parsePrefixExpr(); | | |
| 1555 | if (res == 0) return null_node; | | |
| 1556 | | | |
| 1557 | while (true) { | | |
| 1558 | const tag: Node.Tag = switch (p.token_tags[p.tok_i]) { | | |
| 1559 | .pipe_pipe => .merge_error_sets, | | |
| 1560 | .asterisk => .mul, | | |
| 1561 | .slash => .div, | | |
| 1562 | .percent => .mod, | | |
| 1563 | .asterisk_asterisk => .array_mult, | | |
| 1564 | .asterisk_percent => .mul_wrap, | | |
| 1565 | else => return res, | | |
| 1566 | }; | | |
| 1567 | res = try p.addNode(.{ | | |
| 1568 | .tag = tag, | | |
| 1569 | .main_token = p.nextToken(), | | |
| 1570 | .data = .{ | | |
| 1571 | .lhs = res, | | |
| 1572 | .rhs = try p.expectPrefixExpr(), | | |
| 1573 | }, | | |
| 1574 | }); | | |
| 1575 | } | 1417 | } |
| 1576 | } | | |
| 1577 | | 1418 | |
| 1578 | fn expectMultiplyExpr(p: *Parser) Error!Node.Index { | | |
| 1579 | const node = try p.parseMultiplyExpr(); | | |
| 1580 | if (node == 0) { | | |
| 1581 | return p.fail(.invalid_token); | | |
| 1582 | } | | |
| 1583 | return node; | 1419 | return node; |
| 1584 | } | 1420 | } |
| 1585 | | 1421 | |