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  }