(node Node)
| 775 | } |
| 776 | |
| 777 | func (p *Parser) parsePostfixExpression(node Node) Node { |
| 778 | postfixToken := p.current |
| 779 | for (postfixToken.Is(Operator) || postfixToken.Is(Bracket)) && p.err == nil { |
| 780 | optional := postfixToken.Value == "?." |
| 781 | parseToken: |
| 782 | if postfixToken.Value == "." || postfixToken.Value == "?." { |
| 783 | p.next() |
| 784 | |
| 785 | propertyToken := p.current |
| 786 | if optional && propertyToken.Is(Bracket, "[") { |
| 787 | postfixToken = propertyToken |
| 788 | goto parseToken |
| 789 | } |
| 790 | p.next() |
| 791 | |
| 792 | if propertyToken.Kind != Identifier && |
| 793 | // Operators like "not" and "matches" are valid methods or property names. |
| 794 | (propertyToken.Kind != Operator || !utils.IsValidIdentifier(propertyToken.Value)) { |
| 795 | p.error("expected name") |
| 796 | } |
| 797 | |
| 798 | property := p.createNode(&StringNode{Value: propertyToken.Value}, propertyToken.Location) |
| 799 | if property == nil { |
| 800 | return nil |
| 801 | } |
| 802 | |
| 803 | chainNode, isChain := node.(*ChainNode) |
| 804 | optional := postfixToken.Value == "?." |
| 805 | |
| 806 | if isChain { |
| 807 | node = chainNode.Node |
| 808 | } |
| 809 | |
| 810 | memberNode := p.createMemberNode(&MemberNode{ |
| 811 | Node: node, |
| 812 | Property: property, |
| 813 | Optional: optional, |
| 814 | }, propertyToken.Location) |
| 815 | if memberNode == nil { |
| 816 | return nil |
| 817 | } |
| 818 | |
| 819 | if p.current.Is(Bracket, "(") { |
| 820 | memberNode.Method = true |
| 821 | node = p.createNode(&CallNode{ |
| 822 | Callee: memberNode, |
| 823 | Arguments: p.parseArguments([]Node{}), |
| 824 | }, propertyToken.Location) |
| 825 | if node == nil { |
| 826 | return nil |
| 827 | } |
| 828 | } else { |
| 829 | node = memberNode |
| 830 | } |
| 831 | |
| 832 | if isChain || optional { |
| 833 | node = p.createNode(&ChainNode{Node: node}, propertyToken.Location) |
| 834 | if node == nil { |
no test coverage detected