parser_test.go (17790B)
1 package parser 2 3 import ( 4 "fmt" 5 "umx_compiler/ast" 6 "umx_compiler/lexer" 7 "testing" 8 ) 9 10 func TestLetStatements(t *testing.T) { 11 tests := []struct { 12 input string 13 expectedIdentifier string 14 expectedValue interface{} 15 }{ 16 {"let x = 5;", "x", 5}, 17 {"let y = true;", "y", true}, 18 {"let foo = y;", "foo", "y"}, 19 } 20 21 for _, tt := range tests { 22 l := lexer.New(tt.input) 23 p := New(l) 24 prg := p.ParseProgram() 25 checkParserErrors(t, p) 26 27 if prg == nil { 28 t.Fatalf("ParseProgram() returned nil") 29 } 30 if len(prg.Statements) != 1 { 31 t.Fatalf("program.Statements has not 1 elements but %d", len(prg.Statements)) 32 } 33 34 statement := prg.Statements[0] 35 if !testLetStatement(t, statement, tt.expectedIdentifier) { 36 return 37 } 38 39 val := statement.(*ast.LetStatement).Value 40 if !testLiteralExpression(t, val, tt.expectedValue) { 41 return 42 } 43 } 44 } 45 46 func testLetStatement(t *testing.T, s ast.Statement, name string) bool { 47 if s.TokenLiteral() != "let" { 48 t.Errorf("s.TokenLiteral() is not 'let' but '%s' instead", s.TokenLiteral()) 49 return false 50 } 51 52 letStatement, ok := s.(*ast.LetStatement) 53 if !ok { 54 t.Errorf("s is not *ast.LetStatement but %T", s) 55 return false 56 } 57 58 if letStatement.Name.Value != name { 59 t.Errorf("letStatement.Name.Value is not %s but %s", name, letStatement.Name.Value) 60 return false 61 } 62 63 if letStatement.Name.TokenLiteral() != name { 64 t.Errorf("letStatement.Name.TokenLiteral() is not %s but %s", name, letStatement.Name.TokenLiteral()) 65 return false 66 } 67 68 return true 69 } 70 71 func TestReturnStatements(t *testing.T) { 72 input := ` 73 return 5; 74 return 10; 75 return 112233; 76 ` 77 l := lexer.New(input) 78 p := New(l) 79 program := p.ParseProgram() 80 checkParserErrors(t, p) 81 82 if len(program.Statements) != 3 { 83 t.Fatalf("program.Statements has not 3 elements but %d", len(program.Statements)) 84 } 85 86 for _, statement := range program.Statements { 87 returnStatement, ok := statement.(*ast.ReturnStatement) 88 if !ok { 89 t.Errorf("statement is not *ast.ReturnStatement but %T", statement) 90 continue 91 } 92 if returnStatement.TokenLiteral() != "return" { 93 t.Errorf("returnStatement.TokenLiteral() is not 'return' but %s", returnStatement.TokenLiteral()) 94 } 95 } 96 } 97 98 func checkParserErrors(t *testing.T, p *Parser) { 99 errors := p.Errors() 100 if len(errors) == 0 { 101 return 102 } 103 104 t.Errorf("%d parse errors:", len(errors)) 105 for _, msg := range errors { 106 t.Errorf("%s", msg) 107 } 108 t.FailNow() 109 } 110 111 func TestIdentifierExpression(t *testing.T) { 112 input := "foo;" 113 114 l := lexer.New(input) 115 p := New(l) 116 prg := p.ParseProgram() 117 checkParserErrors(t, p) 118 119 if len(prg.Statements) != 1 { 120 t.Fatalf("prg.Statements has more than 1 element (%d)", len(prg.Statements)) 121 } 122 123 statement, ok := prg.Statements[0].(*ast.ExpressionStatement) 124 if !ok { 125 t.Fatalf("prg.Statements[0] is not ast.ExpressionStatement but %T", prg.Statements[0]) 126 } 127 128 ident, ok := statement.Expression.(*ast.Identifier) 129 if !ok { 130 t.Fatalf("expression is not *ast.Identifier but %T", statement.Expression) 131 } 132 133 if ident.Value != "foo" { 134 t.Fatalf("ident.Value is not valid: %s", ident.Value) 135 } 136 137 if ident.TokenLiteral() != "foo" { 138 t.Errorf("ident.TokenLiteral() is not 'foo' but %s", ident.TokenLiteral()) 139 } 140 } 141 142 func TestIntegerLiteralExpression(t *testing.T) { 143 input := "8;" 144 l := lexer.New(input) 145 p := New(l) 146 prg := p.ParseProgram() 147 checkParserErrors(t, p) 148 149 if len(prg.Statements) != 1 { 150 t.Fatalf("statements count is not 1 but %d", len(prg.Statements)) 151 } 152 153 statement, ok := prg.Statements[0].(*ast.ExpressionStatement) 154 if !ok { 155 t.Fatalf("prg.Statements[0] is not ExpressionStatement but %T", prg.Statements[0]) 156 } 157 158 literal, ok := statement.Expression.(*ast.IntegerLiteral) 159 if !ok { 160 t.Fatalf("statement.Expression is not IntegerLiteral but %T", statement.Expression) 161 } 162 163 if literal.Value != 8 { 164 t.Errorf("literal.Value is not 8 but %d", literal.Value) 165 } 166 167 if literal.TokenLiteral() != "8" { 168 t.Errorf("literal.TokenLiteral is not '8' but %s", literal.TokenLiteral()) 169 } 170 } 171 172 func TestParsingPrefixExpressions(t *testing.T) { 173 prefixTests := []struct { 174 input string 175 operator string 176 value interface{} 177 }{ 178 {"!5;", "!", 5}, 179 {"-15;", "-", 15}, 180 {"!true;", "!", true}, 181 } 182 183 for _, tt := range prefixTests { 184 l := lexer.New(tt.input) 185 p := New(l) 186 prg := p.ParseProgram() 187 checkParserErrors(t, p) 188 189 if len(prg.Statements) != 1 { 190 t.Fatalf("prg.Statements count is wrong: %d instead of 1", len(prg.Statements)) 191 } 192 193 statement, ok := prg.Statements[0].(*ast.ExpressionStatement) 194 if !ok { 195 t.Fatalf("prg.Statements[0] is not ast.ExpressionStatement but %T", prg.Statements[0]) 196 } 197 198 expr, ok := statement.Expression.(*ast.PrefixExpression) 199 if !ok { 200 t.Fatalf("statement.Expression is not PrefixExpression but %T", statement.Expression) 201 } 202 203 if expr.Operator != tt.operator { 204 t.Fatalf("exp.Operator is not %s but %s", tt.operator, expr.Operator) 205 } 206 207 if !testLiteralExpression(t, expr.Right, tt.value) { 208 return 209 } 210 } 211 } 212 213 func TestParsingInfixExpressions(t *testing.T) { 214 infixTests := []struct { 215 input string 216 leftValue interface{} 217 operator string 218 rightValue interface{} 219 }{ 220 {"1 + 2", 1, "+", 2}, 221 {"3 - 4", 3, "-", 4}, 222 {"5 * 6", 5, "*", 6}, 223 {"7 / 8", 7, "/", 8}, 224 {"9 > 0", 9, ">", 0}, 225 {"1 < 2", 1, "<", 2}, 226 {"3 == 3", 3, "==", 3}, 227 {"4 != 5", 4, "!=", 5}, 228 {"true == true", true, "==", true}, 229 } 230 231 for _, tt := range infixTests { 232 l := lexer.New(tt.input) 233 p := New(l) 234 prg := p.ParseProgram() 235 checkParserErrors(t, p) 236 237 if len(prg.Statements) != 1 { 238 t.Fatalf("prg.Statements length is not 1 but %d", len(prg.Statements)) 239 } 240 241 statement, ok := prg.Statements[0].(*ast.ExpressionStatement) 242 if !ok { 243 t.Fatalf("statement is not ExpressionStatement but %T", prg.Statements[0]) 244 } 245 246 if !testInfixExpression(t, statement.Expression, tt.leftValue, tt.operator, tt.rightValue) { 247 return 248 } 249 } 250 } 251 252 func testIntegerLiteral(t *testing.T, il ast.Expression, value int64) bool { 253 integ, ok := il.(*ast.IntegerLiteral) 254 if !ok { 255 t.Errorf("il is not *ast.IntegerLiteral but %T", il) 256 return false 257 } 258 if integ.Value != value { 259 t.Errorf("integ.Value is not %d but %d", value, integ.Value) 260 return false 261 } 262 if integ.TokenLiteral() != fmt.Sprintf("%d", value) { 263 t.Errorf("integ.TokenLiteral not %d but %s", value, integ.TokenLiteral()) 264 return false 265 } 266 return true 267 } 268 269 func testBooleanLiteral(t *testing.T, expr ast.Expression, value bool) bool { 270 bo, ok := expr.(*ast.Boolean) 271 if !ok { 272 t.Errorf("expr is not boolean but %T", expr) 273 return false 274 } 275 if bo.Value != value { 276 t.Errorf("bo.Value is not %t but %t", value, bo.Value) 277 return false 278 } 279 if bo.TokenLiteral() != fmt.Sprintf("%t", value) { 280 t.Errorf("bo.TokenLiteral is not %t but %s", value, bo.TokenLiteral()) 281 return false 282 } 283 return true 284 } 285 286 func testIdentifier(t *testing.T, expr ast.Expression, value string) bool { 287 ident, ok := expr.(*ast.Identifier) 288 if !ok { 289 t.Errorf("expr is not *ast.Identifier but %T", expr) 290 return false 291 } 292 if ident.Value != value { 293 t.Errorf("ident.Value is not %s but %s", value, ident.Value) 294 return false 295 } 296 if ident.TokenLiteral() != value { 297 t.Errorf("ident.TokenLiteral() is not %s but %s", value, ident.TokenLiteral()) 298 return false 299 } 300 return true 301 } 302 303 func testLiteralExpression(t *testing.T, expr ast.Expression, expected interface{}) bool { 304 switch v := expected.(type) { 305 case int: 306 return testIntegerLiteral(t, expr, int64(v)) 307 case int64: 308 return testIntegerLiteral(t, expr, v) 309 case string: 310 return testIdentifier(t, expr, v) 311 case bool: 312 return testBooleanLiteral(t, expr, v) 313 } 314 t.Errorf("expr type is not handled: %T", expr) 315 return false 316 } 317 318 func testInfixExpression(t *testing.T, expr ast.Expression, left interface{}, operator string, right interface{}) bool { 319 opExpr, ok := expr.(*ast.InfixExpression) 320 if !ok { 321 t.Errorf("expr is not *ast.InfixExpression but %T", expr) 322 return false 323 } 324 if !testLiteralExpression(t, opExpr.Left, left) { 325 return false 326 } 327 if opExpr.Operator != operator { 328 t.Errorf("opExpr.Operator is not %q but %q", operator, opExpr.Operator) 329 return false 330 } 331 if !testLiteralExpression(t, opExpr.Right, right) { 332 return false 333 } 334 return true 335 } 336 337 func TestOperatorPrecedenceParsing(t *testing.T) { 338 tests := []struct { 339 input string 340 expected string 341 }{ 342 {"-a*b", "((-a) * b)"}, 343 {"!-a", "(!(-a))"}, 344 {"a+b+c", "((a + b) + c)"}, 345 {"a*b*c", "((a * b) * c)"}, 346 {"a*b/c", "((a * b) / c)"}, 347 {"a+b*c+d/e-f", "(((a + (b * c)) + (d / e)) - f)"}, 348 {"5>4==3<4", "((5 > 4) == (3 < 4))"}, 349 {"true", "true"}, 350 {"false", "false"}, 351 {"3<5==true==!false", "(((3 < 5) == true) == (!false))"}, 352 {"!(true == true)", "(!(true == true))"}, 353 {"2/(5+5)", "(2 / (5 + 5))"}, 354 {"-(5+5)", "(-(5 + 5))"}, 355 {"a+add(b*c)+d", "((a + add((b * c))) + d)"}, 356 {"add(a+b+c*d/f+g)", "add((((a + b) + ((c * d) / f)) + g))"}, 357 {"add(a,b,1,2*3,4+5,add(6,7+8))", "add(a, b, 1, (2 * 3), (4 + 5), add(6, (7 + 8)))"}, 358 {"a*[1,2,3,4][b*c]*d", "((a * ([1, 2, 3, 4][(b * c)])) * d)"}, 359 {"add(a*b[2], b[1], 2*[1,2][1])", "add((a * (b[2])), (b[1]), (2 * ([1, 2][1])))"}, 360 } 361 362 for _, tt := range tests { 363 l := lexer.New(tt.input) 364 p := New(l) 365 prg := p.ParseProgram() 366 checkParserErrors(t, p) 367 actual := prg.String() 368 if actual != tt.expected { 369 t.Errorf("expected %q but got %q", tt.expected, actual) 370 } 371 } 372 } 373 374 func TestBooleanExpression(t *testing.T) { 375 tests := []struct { 376 input string 377 expectedBoolean bool 378 }{ 379 {"true;", true}, 380 {"false;", false}, 381 } 382 383 for _, tt := range tests { 384 l := lexer.New(tt.input) 385 p := New(l) 386 program := p.ParseProgram() 387 checkParserErrors(t, p) 388 389 if len(program.Statements) != 1 { 390 t.Fatalf("program has not enough statements. got=%d", 391 len(program.Statements)) 392 } 393 394 stmt, ok := program.Statements[0].(*ast.ExpressionStatement) 395 if !ok { 396 t.Fatalf("program.Statements[0] is not ast.ExpressionStatement. got=%T", 397 program.Statements[0]) 398 } 399 400 boolean, ok := stmt.Expression.(*ast.Boolean) 401 if !ok { 402 t.Fatalf("exp not *ast.Boolean. got=%T", stmt.Expression) 403 } 404 if boolean.Value != tt.expectedBoolean { 405 t.Errorf("boolean.Value not %t. got=%t", tt.expectedBoolean, 406 boolean.Value) 407 } 408 } 409 } 410 411 func TestIfExpression(t *testing.T) { 412 input := "if (x<y) { x }" 413 l := lexer.New(input) 414 p := New(l) 415 prg := p.ParseProgram() 416 checkParserErrors(t, p) 417 if len(prg.Statements) != 1 { 418 t.Fatalf("len(prg.Statements) is not 1 but %d", len(prg.Statements)) 419 } 420 statement, ok := prg.Statements[0].(*ast.ExpressionStatement) 421 if !ok { 422 t.Fatalf("prg.Statements[0] is not ExpressionStatement but %T", prg.Statements[0]) 423 } 424 expr, ok := statement.Expression.(*ast.IfExpression) 425 if !ok { 426 t.Fatalf("statement.Expression is not IfExpression but %T", statement.Expression) 427 } 428 if !testInfixExpression(t, expr.Condition, "x", "<", "y") { 429 return 430 } 431 if len(expr.Consequence.Statements) != 1 { 432 t.Fatalf("len(expr.Consequence.Statements) is not 1 but %d", len(expr.Consequence.Statements)) 433 } 434 cons, ok := expr.Consequence.Statements[0].(*ast.ExpressionStatement) 435 if !ok { 436 t.Fatalf("consequence statement is not Statement but %T", expr.Consequence.Statements[0]) 437 } 438 if !testIdentifier(t, cons.Expression, "x") { 439 return 440 } 441 if expr.Alternative != nil { 442 t.Fatalf("expr alternative is not nil") 443 } 444 } 445 446 func TestIfElseExpression(t *testing.T) { 447 input := "if (x<y) { x } else { y }" 448 l := lexer.New(input) 449 p := New(l) 450 prg := p.ParseProgram() 451 checkParserErrors(t, p) 452 if len(prg.Statements) != 1 { 453 t.Fatalf("len(prg.Statements) is not 1 but %d", len(prg.Statements)) 454 } 455 statement, ok := prg.Statements[0].(*ast.ExpressionStatement) 456 if !ok { 457 t.Fatalf("prg.Statements[0] is not ExpressionStatement but %T", prg.Statements[0]) 458 } 459 expr, ok := statement.Expression.(*ast.IfExpression) 460 if !ok { 461 t.Fatalf("statement.Expression is not IfExpression but %T", statement.Expression) 462 } 463 if !testInfixExpression(t, expr.Condition, "x", "<", "y") { 464 return 465 } 466 if len(expr.Consequence.Statements) != 1 { 467 t.Fatalf("len(expr.Consequence.Statements) is not 1 but %d", len(expr.Consequence.Statements)) 468 } 469 cons, ok := expr.Consequence.Statements[0].(*ast.ExpressionStatement) 470 if !ok { 471 t.Fatalf("consequence statement is not Statement but %T", expr.Consequence.Statements[0]) 472 } 473 if !testIdentifier(t, cons.Expression, "x") { 474 return 475 } 476 if expr.Alternative == nil { 477 t.Fatalf("expr alternative cannot be empty") 478 } 479 if len(expr.Alternative.Statements) != 1 { 480 t.Fatalf("len(expr.Alternative.Statements) is not 1 but %d", len(expr.Alternative.Statements)) 481 } 482 alt, ok := expr.Alternative.Statements[0].(*ast.ExpressionStatement) 483 if !ok { 484 t.Fatalf("alternative statement is not Statement but %T", expr.Alternative.Statements[0]) 485 } 486 if !testIdentifier(t, alt.Expression, "y") { 487 return 488 } 489 } 490 491 func TestFunctionLiteralParsing(t *testing.T) { 492 input := "fn(x,y) { x+y; }" 493 l := lexer.New(input) 494 p := New(l) 495 prg := p.ParseProgram() 496 checkParserErrors(t, p) 497 if len(prg.Statements) != 1 { 498 t.Fatalf("prg.Statements count is wrong") 499 } 500 statement, ok := prg.Statements[0].(*ast.ExpressionStatement) 501 if !ok { 502 t.Fatalf("prg.Statement[0] is not expressionstatement but %T", prg.Statements[0]) 503 } 504 function, ok := statement.Expression.(*ast.FunctionLiteral) 505 if !ok { 506 t.Fatalf("statement.Expression is not a function but %T", statement.Expression) 507 } 508 if len(function.Parameters) != 2 { 509 t.Fatalf("function parameters count is wrong") 510 } 511 testLiteralExpression(t, function.Parameters[0], "x") 512 testLiteralExpression(t, function.Parameters[1], "y") 513 if len(function.Body.Statements) != 1 { 514 t.Fatalf("function body statements count is wrong") 515 } 516 bodyStatement, ok := function.Body.Statements[0].(*ast.ExpressionStatement) 517 if !ok { 518 t.Fatalf("body statement is not an expression") 519 } 520 testInfixExpression(t, bodyStatement.Expression, "x", "+", "y") 521 } 522 523 func TestFunctionParameterParsing(t *testing.T) { 524 tests := []struct { 525 input string 526 expectedParams []string 527 }{ 528 {input: "fn(){};", expectedParams: []string{}}, 529 {input: "fn(x){};", expectedParams: []string{"x"}}, 530 {input: "fn(x,y,z){};", expectedParams: []string{"x", "y", "z"}}, 531 } 532 533 for _, tt := range tests { 534 l := lexer.New(tt.input) 535 p := New(l) 536 prg := p.ParseProgram() 537 checkParserErrors(t, p) 538 statement := prg.Statements[0].(*ast.ExpressionStatement) 539 function := statement.Expression.(*ast.FunctionLiteral) 540 if len(function.Parameters) != len(tt.expectedParams) { 541 t.Errorf("parameters count is wrong (%d instead of %d)", len(function.Parameters), len(tt.expectedParams)) 542 } 543 for i, ident := range tt.expectedParams { 544 testLiteralExpression(t, function.Parameters[i], ident) 545 } 546 } 547 } 548 549 func TestCallParametersParsing(t *testing.T) { 550 input := "add(1, 2*3, 4+5);" 551 l := lexer.New(input) 552 p := New(l) 553 prg := p.ParseProgram() 554 checkParserErrors(t, p) 555 if len(prg.Statements) != 1 { 556 t.Fatalf("prg.Statements count is wrong") 557 } 558 statement, ok := prg.Statements[0].(*ast.ExpressionStatement) 559 if !ok { 560 t.Fatalf("prg.Statements[0] is not ExpressionStatement but %T", prg.Statements[0]) 561 } 562 expr, ok := statement.Expression.(*ast.CallExpression) 563 if !ok { 564 t.Fatalf("statement.Expression is not CallExpression but %T", statement.Expression) 565 } 566 if !testIdentifier(t, expr.Function, "add") { 567 return 568 } 569 if len(expr.Arguments) != 3 { 570 t.Fatalf("expr.Arguments count is wrong (%d)", len(expr.Arguments)) 571 } 572 testLiteralExpression(t, expr.Arguments[0], 1) 573 testInfixExpression(t, expr.Arguments[1], 2, "*", 3) 574 testInfixExpression(t, expr.Arguments[2], 4, "+", 5) 575 } 576 577 func TestStringLiteralExpression(t *testing.T) { 578 input := `"ehlo world";` 579 l := lexer.New(input) 580 p := New(l) 581 prg := p.ParseProgram() 582 checkParserErrors(t, p) 583 statement := prg.Statements[0].(*ast.ExpressionStatement) 584 literal, ok := statement.Expression.(*ast.StringLiteral) 585 if !ok { 586 t.Fatalf("expression is not string literal") 587 } 588 if literal.Value != "ehlo world" { 589 t.Errorf("literal string value is wrong") 590 } 591 } 592 593 func TestParsingArrayLiterals(t *testing.T) { 594 input := "[10,20*30,40+50]" 595 l := lexer.New(input) 596 p := New(l) 597 prg := p.ParseProgram() 598 checkParserErrors(t, p) 599 statement, ok := prg.Statements[0].(*ast.ExpressionStatement) 600 array, ok := statement.Expression.(*ast.ArrayLiteral) 601 if !ok { 602 t.Fatalf("expression is not ArrayLiteral") 603 } 604 if len(array.Elements) != 3 { 605 t.Fatalf("array Elements count is wrong") 606 } 607 testIntegerLiteral(t, array.Elements[0], 10) 608 testInfixExpression(t, array.Elements[1], 20, "*", 30) 609 testInfixExpression(t, array.Elements[2], 40, "+", 50) 610 } 611 612 func TestParsingIndexExpressions(t *testing.T) { 613 input := "myArray[1+2]" 614 l := lexer.New(input) 615 p := New(l) 616 prg := p.ParseProgram() 617 checkParserErrors(t, p) 618 statement, ok := prg.Statements[0].(*ast.ExpressionStatement) 619 indexExp, ok := statement.Expression.(*ast.IndexExpression) 620 if !ok { 621 t.Fatalf("expression is not IndexExpression") 622 } 623 if !testIdentifier(t, indexExp.Left, "myArray") { 624 return 625 } 626 if !testInfixExpression(t, indexExp.Index, 1, "+", 2) { 627 return 628 } 629 } 630 631 func TestParsingHashLiteralsStringKeys(t *testing.T) { 632 input := `{"one": 1, "two": 2, "three": 3};` 633 l := lexer.New(input) 634 p := New(l) 635 prg := p.ParseProgram() 636 checkParserErrors(t, p) 637 statement := prg.Statements[0].(*ast.ExpressionStatement) 638 hash, ok := statement.Expression.(*ast.HashLiteral) 639 if !ok { 640 t.Fatalf("expression is not ast.HashLiteral but %T", statement.Expression) 641 } 642 if len(hash.Pairs) != 3 { 643 t.Fatalf("Wrong number of elements in hash") 644 } 645 expected := map[string]int64{ 646 "one": 1, 647 "two": 2, 648 "three": 3, 649 } 650 for k, v := range hash.Pairs { 651 literal, ok := k.(*ast.StringLiteral) 652 if !ok { 653 t.Fatalf("key is not ast.StringLiteral") 654 } 655 expectedVal := expected[literal.String()] 656 testIntegerLiteral(t, v, expectedVal) 657 } 658 }