@@ -182,6 +182,140 @@ func TestParsingPrefixExpression(t *testing.T) {
182
182
}
183
183
}
184
184
185
+ func TestParsingInfixExpressions (t * testing.T ) {
186
+ // Test parsing infix operators.
187
+ // e.g.: `5 + 5;`
188
+ // As with prefix operator expressions, we can use any expressions to the
189
+ // left and right of the operator:
190
+ // <expression> <infix operator> <expression>
191
+
192
+ infixTests := []struct {
193
+ input string
194
+ leftValue int64
195
+ operator string
196
+ rightValue int64
197
+ }{
198
+ {"5 + 5;" , 5 , "+" , 5 },
199
+ {"5 - 5;" , 5 , "-" , 5 },
200
+ {"5 * 5;" , 5 , "*" , 5 },
201
+ {"5 / 5;" , 5 , "/" , 5 },
202
+ {"5 > 5;" , 5 , ">" , 5 },
203
+ {"5 < 5;" , 5 , "<" , 5 },
204
+ {"5 == 5;" , 5 , "==" , 5 },
205
+ {"5 != 5;" , 5 , "!=" , 5 },
206
+ }
207
+
208
+ for _ , tt := range infixTests {
209
+ l := lexer .New (tt .input )
210
+ p := New (l )
211
+ program := p .ParseProgram ()
212
+ checkParserErrors (t , p )
213
+
214
+ if len (program .Statements ) != 1 {
215
+ t .Fatalf ("program.Statements does not contain %d statements. got=%d\n " ,
216
+ 1 , len (program .Statements ))
217
+ }
218
+
219
+ stmt , ok := program .Statements [0 ].(* ast.ExpressionStatement )
220
+ if ! ok {
221
+ t .Fatalf ("program.Statements[0] is not ast.ExpressionStatement. got=%T" ,
222
+ program .Statements [0 ])
223
+ }
224
+
225
+ exp , ok := stmt .Expression .(* ast.InfixExpression )
226
+ if ! ok {
227
+ t .Fatalf ("exp is not ast.InfixExpression. got=%T" , stmt .Expression )
228
+ }
229
+
230
+ if ! testIntegerLiteral (t , exp .Left , tt .leftValue ) {
231
+ return
232
+ }
233
+
234
+ if exp .Operator != tt .operator {
235
+ t .Fatalf ("exp.Operator is not '%s'. got=%s" ,
236
+ tt .operator , exp .Operator )
237
+ }
238
+
239
+ if ! testIntegerLiteral (t , exp .Right , tt .rightValue ) {
240
+ return
241
+ }
242
+ }
243
+ }
244
+
245
+ func TestOperatorPrecedenceParsing (t * testing.T ) {
246
+ // Tests that use multiple operators with different precedences and how the
247
+ // AST in string form correctly represents this.
248
+ tests := []struct {
249
+ input string
250
+ expected string
251
+ }{
252
+ {
253
+ "-a * b" ,
254
+ "((-a) * b)" ,
255
+ },
256
+ {
257
+ "!-a" ,
258
+ "(!(-a))" ,
259
+ },
260
+ {
261
+ "a + b + c" ,
262
+ "((a + b) + c)" ,
263
+ },
264
+ {
265
+ "a + b - c" ,
266
+ "((a + b) - c)" ,
267
+ },
268
+ {
269
+ "a * b * c" ,
270
+ "((a * b) * c)" ,
271
+ },
272
+ {
273
+ "a * b / c" ,
274
+ "((a * b) / c)" ,
275
+ },
276
+ {
277
+ "a + b / c" ,
278
+ "(a + (b / c))" ,
279
+ },
280
+ {
281
+ "a + b * c + d / e - f" ,
282
+ "(((a + (b * c)) + (d / e)) - f)" ,
283
+ },
284
+ {
285
+ "3 + 4; -5 * 5" ,
286
+ "(3 + 4)((-5) * 5)" ,
287
+ },
288
+ {
289
+ "5 > 4 == 3 < 4" ,
290
+ "((5 > 4) == (3 < 4))" ,
291
+ },
292
+ {
293
+ "5 < 4 != 3 > 4" ,
294
+ "((5 < 4) != (3 > 4))" ,
295
+ },
296
+ {
297
+ "3 + 4 * 5 == 3 * 1 + 4 * 5" ,
298
+ "((3 + (4 * 5)) == ((3 * 1) + (4 * 5)))" ,
299
+ },
300
+ {
301
+ "3 + 4 * 5 == 3 * 1 + 4 * 5" ,
302
+ "((3 + (4 * 5)) == ((3 * 1) + (4 * 5)))" ,
303
+ },
304
+ }
305
+
306
+ for _ , tt := range tests {
307
+ l := lexer .New (tt .input )
308
+ p := New (l )
309
+ program := p .ParseProgram ()
310
+ checkParserErrors (t , p )
311
+
312
+ actual := program .String ()
313
+ if actual != tt .expected {
314
+ t .Errorf ("expected=%q, got=%q" , tt .expected , actual )
315
+ }
316
+ }
317
+ }
318
+
185
319
func testIntegerLiteral (t * testing.T , il ast.Expression , value int64 ) bool {
186
320
integ , ok := il .(* ast.IntegerLiteral )
187
321
if ! ok {
0 commit comments