github.com/nuvolaris/goja@v0.0.0-20230825100449-967811910c6d/parser/marshal_test.go (about) 1 package parser 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "reflect" 7 "strings" 8 "testing" 9 10 "github.com/nuvolaris/goja/ast" 11 ) 12 13 func marshal(name string, children ...interface{}) interface{} { 14 if len(children) == 1 { 15 if name == "" { 16 return testMarshalNode(children[0]) 17 } 18 return map[string]interface{}{ 19 name: children[0], 20 } 21 } 22 map_ := map[string]interface{}{} 23 length := len(children) / 2 24 for i := 0; i < length; i++ { 25 name := children[i*2].(string) 26 value := children[i*2+1] 27 map_[name] = value 28 } 29 if name == "" { 30 return map_ 31 } 32 return map[string]interface{}{ 33 name: map_, 34 } 35 } 36 37 func testMarshalNode(node interface{}) interface{} { 38 switch node := node.(type) { 39 40 // Expression 41 42 case *ast.ArrayLiteral: 43 return marshal("Array", testMarshalNode(node.Value)) 44 45 case *ast.AssignExpression: 46 return marshal("Assign", 47 "Left", testMarshalNode(node.Left), 48 "Right", testMarshalNode(node.Right), 49 ) 50 51 case *ast.BinaryExpression: 52 return marshal("BinaryExpression", 53 "Operator", node.Operator.String(), 54 "Left", testMarshalNode(node.Left), 55 "Right", testMarshalNode(node.Right), 56 ) 57 58 case *ast.BooleanLiteral: 59 return marshal("Literal", node.Value) 60 61 case *ast.CallExpression: 62 return marshal("Call", 63 "Callee", testMarshalNode(node.Callee), 64 "ArgumentList", testMarshalNode(node.ArgumentList), 65 ) 66 67 case *ast.ConditionalExpression: 68 return marshal("Conditional", 69 "Test", testMarshalNode(node.Test), 70 "Consequent", testMarshalNode(node.Consequent), 71 "Alternate", testMarshalNode(node.Alternate), 72 ) 73 74 case *ast.DotExpression: 75 return marshal("Dot", 76 "Left", testMarshalNode(node.Left), 77 "Member", node.Identifier.Name, 78 ) 79 80 case *ast.NewExpression: 81 return marshal("New", 82 "Callee", testMarshalNode(node.Callee), 83 "ArgumentList", testMarshalNode(node.ArgumentList), 84 ) 85 86 case *ast.NullLiteral: 87 return marshal("Literal", nil) 88 89 case *ast.NumberLiteral: 90 return marshal("Literal", node.Value) 91 92 case *ast.ObjectLiteral: 93 return marshal("Object", testMarshalNode(node.Value)) 94 95 case *ast.RegExpLiteral: 96 return marshal("Literal", node.Literal) 97 98 case *ast.StringLiteral: 99 return marshal("Literal", node.Literal) 100 101 case *ast.Binding: 102 return marshal("Binding", "Target", testMarshalNode(node.Target), 103 "Initializer", testMarshalNode(node.Initializer)) 104 105 // Statement 106 107 case *ast.Program: 108 return testMarshalNode(node.Body) 109 110 case *ast.BlockStatement: 111 return marshal("BlockStatement", testMarshalNode(node.List)) 112 113 case *ast.EmptyStatement: 114 return "EmptyStatement" 115 116 case *ast.ExpressionStatement: 117 return testMarshalNode(node.Expression) 118 119 case *ast.ForInStatement: 120 return marshal("ForIn", 121 "Into", testMarshalNode(node.Into), 122 "Source", marshal("", node.Source), 123 "Body", marshal("", node.Body), 124 ) 125 126 case *ast.FunctionLiteral: 127 return marshal("Function", testMarshalNode(node.Body)) 128 129 case *ast.Identifier: 130 return marshal("Identifier", node.Name) 131 132 case *ast.IfStatement: 133 if_ := marshal("", 134 "Test", testMarshalNode(node.Test), 135 "Consequent", testMarshalNode(node.Consequent), 136 ).(map[string]interface{}) 137 if node.Alternate != nil { 138 if_["Alternate"] = testMarshalNode(node.Alternate) 139 } 140 return marshal("If", if_) 141 142 case *ast.LabelledStatement: 143 return marshal("Label", 144 "Name", node.Label.Name, 145 "Statement", testMarshalNode(node.Statement), 146 ) 147 case *ast.PropertyKeyed: 148 return marshal("", 149 "Key", node.Key, 150 "Value", testMarshalNode(node.Value), 151 ) 152 153 case *ast.ReturnStatement: 154 return marshal("Return", testMarshalNode(node.Argument)) 155 156 case *ast.SequenceExpression: 157 return marshal("Sequence", testMarshalNode(node.Sequence)) 158 159 case *ast.ThrowStatement: 160 return marshal("Throw", testMarshalNode(node.Argument)) 161 162 case *ast.VariableStatement: 163 return marshal("Var", testMarshalNode(node.List)) 164 165 // Special 166 case *ast.ForDeclaration: 167 return marshal("For-Into-Decl", testMarshalNode(node.Target)) 168 169 case *ast.ForIntoVar: 170 return marshal("For-Into-Var", testMarshalNode(node.Binding)) 171 172 } 173 174 { 175 value := reflect.ValueOf(node) 176 if value.Kind() == reflect.Slice { 177 tmp0 := []interface{}{} 178 for index := 0; index < value.Len(); index++ { 179 tmp0 = append(tmp0, testMarshalNode(value.Index(index).Interface())) 180 } 181 return tmp0 182 } 183 } 184 185 return nil 186 } 187 188 func testMarshal(node interface{}) string { 189 value, err := json.Marshal(testMarshalNode(node)) 190 if err != nil { 191 panic(err) 192 } 193 return string(value) 194 } 195 196 func TestParserAST(t *testing.T) { 197 tt(t, func() { 198 199 test := func(inputOutput string) { 200 match := matchBeforeAfterSeparator.FindStringIndex(inputOutput) 201 input := strings.TrimSpace(inputOutput[0:match[0]]) 202 wantOutput := strings.TrimSpace(inputOutput[match[1]:]) 203 _, program, err := testParse(input) 204 is(err, nil) 205 haveOutput := testMarshal(program) 206 tmp0, tmp1 := bytes.Buffer{}, bytes.Buffer{} 207 json.Indent(&tmp0, []byte(haveOutput), "\t\t", " ") 208 json.Indent(&tmp1, []byte(wantOutput), "\t\t", " ") 209 is("\n\t\t"+tmp0.String(), "\n\t\t"+tmp1.String()) 210 } 211 212 test(` 213 --- 214 [] 215 `) 216 217 test(` 218 ; 219 --- 220 [ 221 "EmptyStatement" 222 ] 223 `) 224 225 test(` 226 ;;; 227 --- 228 [ 229 "EmptyStatement", 230 "EmptyStatement", 231 "EmptyStatement" 232 ] 233 `) 234 235 test(` 236 1; true; abc; "abc"; null; 237 --- 238 [ 239 { 240 "Literal": 1 241 }, 242 { 243 "Literal": true 244 }, 245 { 246 "Identifier": "abc" 247 }, 248 { 249 "Literal": "\"abc\"" 250 }, 251 { 252 "Literal": null 253 } 254 ] 255 `) 256 257 test(` 258 { 1; null; 3.14159; ; } 259 --- 260 [ 261 { 262 "BlockStatement": [ 263 { 264 "Literal": 1 265 }, 266 { 267 "Literal": null 268 }, 269 { 270 "Literal": 3.14159 271 }, 272 "EmptyStatement" 273 ] 274 } 275 ] 276 `) 277 278 test(` 279 new abc(); 280 --- 281 [ 282 { 283 "New": { 284 "ArgumentList": [], 285 "Callee": { 286 "Identifier": "abc" 287 } 288 } 289 } 290 ] 291 `) 292 293 test(` 294 new abc(1, 3.14159) 295 --- 296 [ 297 { 298 "New": { 299 "ArgumentList": [ 300 { 301 "Literal": 1 302 }, 303 { 304 "Literal": 3.14159 305 } 306 ], 307 "Callee": { 308 "Identifier": "abc" 309 } 310 } 311 } 312 ] 313 `) 314 315 test(` 316 true ? false : true 317 --- 318 [ 319 { 320 "Conditional": { 321 "Alternate": { 322 "Literal": true 323 }, 324 "Consequent": { 325 "Literal": false 326 }, 327 "Test": { 328 "Literal": true 329 } 330 } 331 } 332 ] 333 `) 334 335 test(` 336 true || false 337 --- 338 [ 339 { 340 "BinaryExpression": { 341 "Left": { 342 "Literal": true 343 }, 344 "Operator": "||", 345 "Right": { 346 "Literal": false 347 } 348 } 349 } 350 ] 351 `) 352 353 test(` 354 0 + { abc: true } 355 --- 356 [ 357 { 358 "BinaryExpression": { 359 "Left": { 360 "Literal": 0 361 }, 362 "Operator": "+", 363 "Right": { 364 "Object": [ 365 { 366 "Key": { 367 "Idx": 7, 368 "Literal": "abc", 369 "Value": "abc" 370 }, 371 "Value": { 372 "Literal": true 373 } 374 } 375 ] 376 } 377 } 378 } 379 ] 380 `) 381 382 test(` 383 1 == "1" 384 --- 385 [ 386 { 387 "BinaryExpression": { 388 "Left": { 389 "Literal": 1 390 }, 391 "Operator": "==", 392 "Right": { 393 "Literal": "\"1\"" 394 } 395 } 396 } 397 ] 398 `) 399 400 test(` 401 abc(1) 402 --- 403 [ 404 { 405 "Call": { 406 "ArgumentList": [ 407 { 408 "Literal": 1 409 } 410 ], 411 "Callee": { 412 "Identifier": "abc" 413 } 414 } 415 } 416 ] 417 `) 418 419 test(` 420 Math.pow(3, 2) 421 --- 422 [ 423 { 424 "Call": { 425 "ArgumentList": [ 426 { 427 "Literal": 3 428 }, 429 { 430 "Literal": 2 431 } 432 ], 433 "Callee": { 434 "Dot": { 435 "Left": { 436 "Identifier": "Math" 437 }, 438 "Member": "pow" 439 } 440 } 441 } 442 } 443 ] 444 `) 445 446 test(` 447 1, 2, 3 448 --- 449 [ 450 { 451 "Sequence": [ 452 { 453 "Literal": 1 454 }, 455 { 456 "Literal": 2 457 }, 458 { 459 "Literal": 3 460 } 461 ] 462 } 463 ] 464 `) 465 466 test(` 467 / abc /gim; 468 --- 469 [ 470 { 471 "Literal": "/ abc /gim" 472 } 473 ] 474 `) 475 476 test(` 477 if (0) 478 1; 479 --- 480 [ 481 { 482 "If": { 483 "Consequent": { 484 "Literal": 1 485 }, 486 "Test": { 487 "Literal": 0 488 } 489 } 490 } 491 ] 492 `) 493 494 test(` 495 0+function(){ 496 return; 497 } 498 --- 499 [ 500 { 501 "BinaryExpression": { 502 "Left": { 503 "Literal": 0 504 }, 505 "Operator": "+", 506 "Right": { 507 "Function": { 508 "BlockStatement": [ 509 { 510 "Return": null 511 } 512 ] 513 } 514 } 515 } 516 } 517 ] 518 `) 519 520 test(` 521 xyzzy // Ignore it 522 // Ignore this 523 // And this 524 /* And all.. 525 526 527 528 ... of this! 529 */ 530 "Nothing happens." 531 // And finally this 532 --- 533 [ 534 { 535 "Identifier": "xyzzy" 536 }, 537 { 538 "Literal": "\"Nothing happens.\"" 539 } 540 ] 541 `) 542 543 test(` 544 ((x & (x = 1)) !== 0) 545 --- 546 [ 547 { 548 "BinaryExpression": { 549 "Left": { 550 "BinaryExpression": { 551 "Left": { 552 "Identifier": "x" 553 }, 554 "Operator": "\u0026", 555 "Right": { 556 "Assign": { 557 "Left": { 558 "Identifier": "x" 559 }, 560 "Right": { 561 "Literal": 1 562 } 563 } 564 } 565 } 566 }, 567 "Operator": "!==", 568 "Right": { 569 "Literal": 0 570 } 571 } 572 } 573 ] 574 `) 575 576 test(` 577 { abc: 'def' } 578 --- 579 [ 580 { 581 "BlockStatement": [ 582 { 583 "Label": { 584 "Name": "abc", 585 "Statement": { 586 "Literal": "'def'" 587 } 588 } 589 } 590 ] 591 } 592 ] 593 `) 594 595 test(` 596 // This is not an object, this is a string literal with a label! 597 ({ abc: 'def' }) 598 --- 599 [ 600 { 601 "Object": [ 602 { 603 "Key": { 604 "Idx": 77, 605 "Literal": "abc", 606 "Value": "abc" 607 }, 608 "Value": { 609 "Literal": "'def'" 610 } 611 } 612 ] 613 } 614 ] 615 `) 616 617 test(` 618 [,] 619 --- 620 [ 621 { 622 "Array": [ 623 null 624 ] 625 } 626 ] 627 `) 628 629 test(` 630 [,,] 631 --- 632 [ 633 { 634 "Array": [ 635 null, 636 null 637 ] 638 } 639 ] 640 `) 641 642 test(` 643 ({ get abc() {} }) 644 --- 645 [ 646 { 647 "Object": [ 648 { 649 "Key": { 650 "Idx": 8, 651 "Literal": "abc", 652 "Value": "abc" 653 }, 654 "Value": { 655 "Function": { 656 "BlockStatement": [] 657 } 658 } 659 } 660 ] 661 } 662 ] 663 `) 664 665 test(` 666 /abc/.source 667 --- 668 [ 669 { 670 "Dot": { 671 "Left": { 672 "Literal": "/abc/" 673 }, 674 "Member": "source" 675 } 676 } 677 ] 678 `) 679 680 test(` 681 xyzzy 682 683 throw new TypeError("Nothing happens.") 684 --- 685 [ 686 { 687 "Identifier": "xyzzy" 688 }, 689 { 690 "Throw": { 691 "New": { 692 "ArgumentList": [ 693 { 694 "Literal": "\"Nothing happens.\"" 695 } 696 ], 697 "Callee": { 698 "Identifier": "TypeError" 699 } 700 } 701 } 702 } 703 ] 704 `) 705 706 // When run, this will call a type error to be thrown 707 // This is essentially the same as: 708 // 709 // var abc = 1(function(){})() 710 // 711 test(` 712 var abc = 1 713 (function(){ 714 })() 715 --- 716 [ 717 { 718 "Var": [ 719 { 720 "Binding": { 721 "Initializer": { 722 "Call": { 723 "ArgumentList": [], 724 "Callee": { 725 "Call": { 726 "ArgumentList": [ 727 { 728 "Function": { 729 "BlockStatement": [] 730 } 731 } 732 ], 733 "Callee": { 734 "Literal": 1 735 } 736 } 737 } 738 } 739 }, 740 "Target": { 741 "Identifier": "abc" 742 } 743 } 744 } 745 ] 746 } 747 ] 748 `) 749 750 test(` 751 "use strict" 752 --- 753 [ 754 { 755 "Literal": "\"use strict\"" 756 } 757 ] 758 `) 759 760 test(` 761 "use strict" 762 abc = 1 + 2 + 11 763 --- 764 [ 765 { 766 "Literal": "\"use strict\"" 767 }, 768 { 769 "Assign": { 770 "Left": { 771 "Identifier": "abc" 772 }, 773 "Right": { 774 "BinaryExpression": { 775 "Left": { 776 "BinaryExpression": { 777 "Left": { 778 "Literal": 1 779 }, 780 "Operator": "+", 781 "Right": { 782 "Literal": 2 783 } 784 } 785 }, 786 "Operator": "+", 787 "Right": { 788 "Literal": 11 789 } 790 } 791 } 792 } 793 } 794 ] 795 `) 796 797 test(` 798 abc = function() { 'use strict' } 799 --- 800 [ 801 { 802 "Assign": { 803 "Left": { 804 "Identifier": "abc" 805 }, 806 "Right": { 807 "Function": { 808 "BlockStatement": [ 809 { 810 "Literal": "'use strict'" 811 } 812 ] 813 } 814 } 815 } 816 } 817 ] 818 `) 819 820 test(` 821 for (var abc in def) { 822 } 823 --- 824 [ 825 { 826 "ForIn": { 827 "Body": { 828 "BlockStatement": [] 829 }, 830 "Into": { 831 "For-Into-Var": { 832 "Binding": { 833 "Initializer": null, 834 "Target": { 835 "Identifier": "abc" 836 } 837 } 838 } 839 }, 840 "Source": { 841 "Identifier": "def" 842 } 843 } 844 } 845 ] 846 `) 847 848 test(` 849 abc = { 850 '"': "'", 851 "'": '"', 852 } 853 --- 854 [ 855 { 856 "Assign": { 857 "Left": { 858 "Identifier": "abc" 859 }, 860 "Right": { 861 "Object": [ 862 { 863 "Key": { 864 "Idx": 21, 865 "Literal": "'\"'", 866 "Value": "\"" 867 }, 868 "Value": { 869 "Literal": "\"'\"" 870 } 871 }, 872 { 873 "Key": { 874 "Idx": 43, 875 "Literal": "\"'\"", 876 "Value": "'" 877 }, 878 "Value": { 879 "Literal": "'\"'" 880 } 881 } 882 ] 883 } 884 } 885 } 886 ] 887 `) 888 889 }) 890 }