(s: ITokenStream, minBp: number)
| 708 | type OpInfo = PrefixInfo | InfixInfo | PostfixInfo; |
| 709 | |
| 710 | function parsePratt(s: ITokenStream, minBp: number): Ast.Expression { |
| 711 | // pratt parsing |
| 712 | // https://matklad.github.io/2020/04/13/simple-but-powerful-pratt-parsing.html |
| 713 | |
| 714 | let left: Ast.Expression; |
| 715 | |
| 716 | const tokenKind = s.getTokenKind(); |
| 717 | const prefix = operators.find((x): x is PrefixInfo => x.opKind === 'prefix' && x.kind === tokenKind); |
| 718 | if (prefix != null) { |
| 719 | left = parsePrefix(s, prefix.bp); |
| 720 | } else { |
| 721 | left = parseAtom(s, false); |
| 722 | } |
| 723 | |
| 724 | while (true) { |
| 725 | // 改行のエスケープ |
| 726 | if (s.is(TokenKind.BackSlash)) { |
| 727 | s.next(); |
| 728 | s.expect(TokenKind.NewLine); |
| 729 | s.next(); |
| 730 | } |
| 731 | |
| 732 | const tokenKind = s.getTokenKind(); |
| 733 | |
| 734 | const postfix = operators.find((x): x is PostfixInfo => x.opKind === 'postfix' && x.kind === tokenKind); |
| 735 | if (postfix != null) { |
| 736 | if (postfix.bp < minBp) { |
| 737 | break; |
| 738 | } |
| 739 | |
| 740 | if ([TokenKind.OpenBracket, TokenKind.OpenParen].includes(tokenKind) && s.getToken().hasLeftSpacing) { |
| 741 | // 前にスペースがある場合は後置演算子として処理しない |
| 742 | } else { |
| 743 | left = parsePostfix(s, left); |
| 744 | continue; |
| 745 | } |
| 746 | } |
| 747 | |
| 748 | const infix = operators.find((x): x is InfixInfo => x.opKind === 'infix' && x.kind === tokenKind); |
| 749 | if (infix != null) { |
| 750 | if (infix.lbp < minBp) { |
| 751 | break; |
| 752 | } |
| 753 | |
| 754 | left = parseInfix(s, left, infix.rbp); |
| 755 | continue; |
| 756 | } |
| 757 | |
| 758 | break; |
| 759 | } |
| 760 | |
| 761 | return left; |
| 762 | } |
| 763 | |
| 764 | //#endregion Pratt parsing |
no test coverage detected