1515 byte (opPlus ),
1616 byte (opMinus ),
1717 byte (opMultiply ),
18- byte (opMultiply ),
1918 byte (opDivide ),
19+ byte (opRemainder ),
2020 byte (opExponentiation ),
2121 byte (opBitwiseOR ),
2222 byte (opBitwiseXOR ),
@@ -83,8 +83,6 @@ func evaluateExpression(tokens []*Token) (*Operand, []*Token, error) {
8383// execOperator takes an Operator and one or two Operands (the second one can be `nil` depending on operator type - unary or binary).
8484// It does evaluate the expression ("operand1 operator operand2" or "operator operand1") and return Operand which is a typed value.
8585func execOperator (op Operator , left * Operand , right * Operand ) (* Operand , error ) {
86- var res Operand
87-
8886 if bytes .IndexByte (opsArithmetic , byte (op )) != - 1 {
8987 // arithmetic
9088 return doArithmetic (op , left , right )
@@ -95,86 +93,94 @@ func execOperator(op Operator, left *Operand, right *Operand) (*Operand, error)
9593 // logic
9694 return doLogic (op , left , right )
9795 }
98- return & res , errUnknownToken
96+ return nil , errUnknownToken
9997}
10098
10199// doArithmetic actually evaluates the arithmetic operators.
102100// Note the special case of string concatenation: string + any_type -> string
103101func doArithmetic (op Operator , left * Operand , right * Operand ) (* Operand , error ) {
104- var res Operand
105-
106102 if op == opPlus && (left .Type | right .Type )& otString > 0 {
107103 // string concatenation
108- res .Type = otString
109- lstr := toString (left )
110- rstr := toString (right )
111- res .Str = append (lstr .Str , rstr .Str ... )
112- return & res , nil
104+ toString (left )
105+ toString (right )
106+ left .Str = append (left .Str [:len (left .Str ):len (left .Str )], right .Str ... ) // cannot use left buffer, must reallocate!
107+ return left , nil
113108 }
114109
115- res .Type = otNumber
116110 switch op {
117111 case opUnaryMinus :
118- res .Number = - toNumber (left ).Number
112+ left .Number = - toNumber (left ).Number
119113 case opPlus :
120- res .Number = toNumber (left ).Number + toNumber (right ).Number
114+ left .Number = toNumber (left ).Number + toNumber (right ).Number
121115 case opMinus :
122- res .Number = toNumber (left ).Number - toNumber (right ).Number
116+ left .Number = toNumber (left ).Number - toNumber (right ).Number
123117 case opMultiply :
124- res .Number = toNumber (left ).Number * toNumber (right ).Number
118+ left .Number = toNumber (left ).Number * toNumber (right ).Number
125119 case opDivide :
126- res .Number = toNumber (left ).Number / toNumber (right ).Number
120+ left .Number = toNumber (left ).Number / toNumber (right ).Number
121+ case opRemainder :
122+ left .Number = float64 (int64 (toNumber (left ).Number ) % int64 (toNumber (right ).Number ))
127123 case opExponentiation :
128- res .Number = math .Pow (toNumber (left ).Number , toNumber (right ).Number )
124+ left .Number = math .Pow (toNumber (left ).Number , toNumber (right ).Number )
129125 case opBitwiseAND :
130- res .Number = float64 (int64 (toNumber (left ).Number ) & int64 (toNumber (right ).Number ))
126+ left .Number = float64 (int64 (toNumber (left ).Number ) & int64 (toNumber (right ).Number ))
131127 case opBitwiseOR :
132- res .Number = float64 (int64 (toNumber (left ).Number ) | int64 (toNumber (right ).Number ))
128+ left .Number = float64 (int64 (toNumber (left ).Number ) | int64 (toNumber (right ).Number ))
133129 case opBitwiseXOR :
134- res .Number = float64 (int64 (toNumber (left ).Number ) ^ int64 (toNumber (right ).Number ))
130+ left .Number = float64 (int64 (toNumber (left ).Number ) ^ int64 (toNumber (right ).Number ))
135131 case opBitwiseNOT :
136- res .Number = float64 (^ int64 (toNumber (left ).Number ))
132+ left .Number = float64 (^ int64 (toNumber (left ).Number ))
137133 case opShiftLeft :
138- res .Number = float64 (int64 (toNumber (left ).Number ) << int64 (toNumber (right ).Number ))
134+ left .Number = float64 (int64 (toNumber (left ).Number ) << int64 (toNumber (right ).Number ))
139135 case opShiftRight :
140- res .Number = float64 (int64 (toNumber (left ).Number ) >> int64 (toNumber (right ).Number ))
136+ left .Number = float64 (int64 (toNumber (left ).Number ) >> int64 (toNumber (right ).Number ))
141137 }
142- return & res , nil
138+ left .Type = otNumber
139+ return left , nil
143140}
144141
145142// doComaparison compares two operands. The special case is string regexp match which works only on strings.
146143// Otherwise works like JS comparison.
147144func doComparison (op Operator , left * Operand , right * Operand ) (* Operand , error ) {
148- result := Operand { Type : otBoolean , Bool : false }
145+ result := left
149146
150147 comparedTypes := left .Type | right .Type
151148
152149 // [1] 7.2.14 (2,3)
153150 if op == opEqual && comparedTypes & (otNull | otUndefined ) > 0 {
154151 // at least one side is null or undefined:
152+ result .Type = otBoolean
155153 result .Bool = (comparedTypes | otNull | otUndefined ) == (otNull | otUndefined ) // both are null or undefined
156- return & result , nil
154+ return result , nil
157155 }
158156 if op == opRegexMatch || op == opNotRegexMatch {
159157 // one of them must be regexp
160158 if comparedTypes & otRegexp != otRegexp {
161- return & result , nil
159+ result .Type = otBoolean
160+ result .Bool = false
161+ return result , nil
162162 }
163163 // other must be non-regexp
164164 if comparedTypes - otRegexp == 0 {
165- return & result , nil
165+ result .Type = otBoolean
166+ result .Bool = false
167+ return result , nil
166168 }
167169 // convert non-regexp part to string and compare
168170 if right .Type == otRegexp {
169- return doCompareString (op , toString (left ), right ) // regexp should be second argument
171+ toString (left )
172+ return doCompareString (op , left , right ) // regexp should be second argument
170173 }
171- return doCompareString (op , toString (right ), left ) // regexp should be second argument
174+ toString (right )
175+ return doCompareString (op , right , left ) // regexp should be second argument
172176 }
173177
174178 // [1] 7.2.15 (1)
175179 if (op == opStrictEqual || op == opStrictNotEqual ) && left .Type != right .Type {
176180 // strict comparison: types must match
177- return & result , nil
181+ result .Type = otBoolean
182+ result .Bool = false
183+ return result , nil
178184 }
179185
180186 // [1] 7.2.15 (4)
@@ -188,26 +194,23 @@ func doComparison(op Operator, left *Operand, right *Operand) (*Operand, error)
188194
189195// doLogic executes binary logical operators following JavaScript conversion rules.
190196func doLogic (op Operator , left * Operand , right * Operand ) (* Operand , error ) {
191- var res Operand
192- res .Type = otBoolean
193-
194197 lval := toBoolean (left )
195198 if op == opLogicalAND || op == opLogicalOR {
196- if (op == opLogicalAND && ! lval . Bool ) || (op == opLogicalOR && lval . Bool ) { // false AND ..., true OR ... -> result!
199+ if (op == opLogicalAND && ! lval ) || (op == opLogicalOR && lval ) { // false AND ..., true OR ... -> result!
197200 return left , nil
198201 }
199202 return right , nil
200203 }
201204
202205 // logical NOT
203- lval .Bool = ! lval .Bool
204- return lval , nil
206+ left .Type = otBoolean
207+ left .Bool = ! lval
208+ return left , nil
205209}
206210
207211// doCompareNumber compares two numbers.
208212func doCompareNumber (op Operator , left * Operand , right * Operand ) (* Operand , error ) {
209- var res Operand
210- res .Type = otBoolean
213+ res := left
211214 switch op {
212215 case opG :
213216 res .Bool = left .Number > right .Number
@@ -222,13 +225,13 @@ func doCompareNumber(op Operator, left *Operand, right *Operand) (*Operand, erro
222225 case opLE :
223226 res .Bool = left .Number <= right .Number
224227 }
225- return & res , nil
228+ res .Type = otBoolean
229+ return res , nil
226230}
227231
228232// doCompareString compares two strings.
229233func doCompareString (op Operator , left * Operand , right * Operand ) (* Operand , error ) {
230- var res Operand
231- res .Type = otBoolean
234+ res := left
232235 switch op {
233236 case opEqual , opStrictEqual :
234237 res .Bool = compareSlices (left .Str , right .Str ) == 0
@@ -247,9 +250,10 @@ func doCompareString(op Operator, left *Operand, right *Operand) (*Operand, erro
247250 case opNotRegexMatch :
248251 res .Bool = ! right .Regexp .MatchString (string (left .Str ))
249252 default :
250- return left , errUnknownToken
253+ return res , errUnknownToken
251254 }
252- return & res , nil
255+ res .Type = otBoolean
256+ return res , nil
253257}
254258
255259// toString converts operand to string following JavaScript conversion rules.
@@ -258,8 +262,7 @@ func toString(op *Operand) *Operand {
258262 return op
259263 }
260264
261- result := * op
262- result .Type = otString
265+ result := op
263266
264267 switch op .Type {
265268 case otUndefined :
@@ -273,9 +276,11 @@ func toString(op *Operand) *Operand {
273276 result .Str = []byte ("false" )
274277 }
275278 case otNumber :
276- result .Str = []byte (strconv .FormatFloat (result .Number , 'f' , - 1 , 64 ))
279+ result .Str = []byte (strconv .FormatFloat (op .Number , 'f' , - 1 , 64 ))
277280 }
278- return & result
281+ result .Type = otString
282+
283+ return result
279284}
280285
281286// toNumber converts operand to number following JavaScript conversion rules. See [1] 7.1.4
@@ -284,8 +289,7 @@ func toNumber(op *Operand) *Operand {
284289 return op
285290 }
286291
287- result := * op
288- result .Type = otNumber
292+ result := op
289293
290294 switch op .Type {
291295 case otUndefined :
@@ -311,28 +315,25 @@ func toNumber(op *Operand) *Operand {
311315 case otRegexp :
312316 result .Number = math .NaN ()
313317 }
314- return & result
318+ result .Type = otNumber
319+ return result
315320}
316321
317322// toBoolean converts operand to boolean following JavaScript conversion rules.
318- func toBoolean (op * Operand ) * Operand {
323+ func toBoolean (op * Operand ) bool {
319324 if op .Type == otBoolean {
320- return op
325+ return op . Bool
321326 }
322327
323- result := * op
324- result .Type = otBoolean
328+ result := false
325329 switch op .Type {
326- case otUndefined , otNull :
327- result .Bool = false
330+ case otUndefined , otNull , otRegexp :
328331 case otString :
329- result . Bool = len (op .Str ) > 0
332+ result = len (op .Str ) > 0
330333 case otNumber :
331- result .Bool = op .Number != 0 && ! math .IsNaN (op .Number )
332- case otRegexp :
333- result .Bool = false
334+ result = op .Number != 0 && ! math .IsNaN (op .Number )
334335 }
335- return & result
336+ return result
336337}
337338
338339// logic complies to [1] 7.2.13 (3) only for BYTES not codepoints!
0 commit comments