-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathoperators.go
123 lines (114 loc) · 3.22 KB
/
operators.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package php
import (
"github.com/stephens2424/php/ast"
"github.com/stephens2424/php/token"
)
type operationType int
const (
nilOperation operationType = 1 << iota
unaryOperation
binaryOperation
ternaryOperation
assignmentOperation
subexpressionBeginOperation
subexpressionEndOperation
ignoreErrorOperation
)
func operationTypeForToken(t token.Token) operationType {
switch t {
case token.IgnoreErrorOperator:
return ignoreErrorOperation
case token.UnaryOperator,
token.NegationOperator,
token.CastOperator,
token.BitwiseNotOperator:
return unaryOperation
case token.AdditionOperator,
token.SubtractionOperator,
token.ConcatenationOperator,
token.ComparisonOperator,
token.MultOperator,
token.AndOperator,
token.OrOperator,
token.AmpersandOperator,
token.BitwiseXorOperator,
token.BitwiseOrOperator,
token.BitwiseShiftOperator,
token.WrittenAndOperator,
token.WrittenXorOperator,
token.WrittenOrOperator,
token.InstanceofOperator:
return binaryOperation
case token.TernaryOperator1:
return ternaryOperation
case token.AssignmentOperator:
return assignmentOperation
case token.OpenParen:
return subexpressionBeginOperation
case token.CloseParen:
return subexpressionEndOperation
}
return nilOperation
}
func (p *Parser) newBinaryOperation(operator token.Item, expr1, expr2 ast.Expression) ast.Expression {
var t ast.Type = ast.Numeric
switch operator.Typ {
case token.AssignmentOperator:
return p.parseAssignmentOperation(expr1, expr2, operator)
case token.ComparisonOperator, token.AndOperator, token.OrOperator, token.WrittenAndOperator, token.WrittenOrOperator, token.WrittenXorOperator:
t = ast.Boolean
case token.ConcatenationOperator:
t = ast.String
case token.AmpersandOperator, token.BitwiseXorOperator, token.BitwiseOrOperator, token.BitwiseShiftOperator:
t = ast.Unknown
}
return ast.BinaryExpression{
Type: t,
Antecedent: expr1,
Subsequent: expr2,
Operator: operator.Val,
}
}
func (p *Parser) parseBinaryOperation(lhs ast.Expression, operator token.Item, originalParenLevel int) ast.Expression {
p.next()
rhs := p.parseOperand()
currentPrecedence := operatorPrecedence[operator.Typ]
for {
nextOperator := p.peek()
nextPrecedence, ok := operatorPrecedence[nextOperator.Typ]
if !ok || nextPrecedence < currentPrecedence {
break
}
rhs = p.parseOperation(originalParenLevel, rhs)
}
return p.newBinaryOperation(operator, lhs, rhs)
}
func (p *Parser) parseTernaryOperation(lhs ast.Expression) ast.Expression {
var truthy ast.Expression
if p.peek().Typ == token.TernaryOperator2 {
truthy = lhs
} else {
truthy = p.parseNextExpression()
}
p.expect(token.TernaryOperator2)
falsy := p.parseNextExpression()
return &ast.TernaryExpression{
Condition: lhs,
True: truthy,
False: falsy,
Type: truthy.EvaluatesTo().Union(falsy.EvaluatesTo()),
}
}
func (p *Parser) parseUnaryExpressionRight(operand ast.Expression, operator token.Item) ast.Expression {
return ast.UnaryExpression{
Operand: operand,
Operator: operator.Val,
}
}
func (p *Parser) parseUnaryExpressionLeft(operand ast.Expression, operator token.Item) ast.Expression {
return ast.UnaryExpression{
Operand: operand,
Operator: operator.Val,
Preceding: true,
}
}