123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962 |
- package parser
- import (
- "bytes"
- "encoding/json"
- "reflect"
- "strings"
- "testing"
- "github.com/dop251/goja/ast"
- )
- func marshal(name string, children ...interface{}) interface{} {
- if len(children) == 1 {
- if name == "" {
- return testMarshalNode(children[0])
- }
- return map[string]interface{}{
- name: children[0],
- }
- }
- map_ := map[string]interface{}{}
- length := len(children) / 2
- for i := 0; i < length; i++ {
- name := children[i*2].(string)
- value := children[i*2+1]
- map_[name] = value
- }
- if name == "" {
- return map_
- }
- return map[string]interface{}{
- name: map_,
- }
- }
- func testMarshalNode(node interface{}) interface{} {
- switch node := node.(type) {
- // Expression
- case *ast.ArrayLiteral:
- return marshal("Array", testMarshalNode(node.Value))
- case *ast.AssignExpression:
- return marshal("Assign",
- "Left", testMarshalNode(node.Left),
- "Right", testMarshalNode(node.Right),
- )
- case *ast.BinaryExpression:
- return marshal("BinaryExpression",
- "Operator", node.Operator.String(),
- "Left", testMarshalNode(node.Left),
- "Right", testMarshalNode(node.Right),
- )
- case *ast.BooleanLiteral:
- return marshal("Literal", node.Value)
- case *ast.CallExpression:
- return marshal("Call",
- "Callee", testMarshalNode(node.Callee),
- "ArgumentList", testMarshalNode(node.ArgumentList),
- )
- case *ast.ConditionalExpression:
- return marshal("Conditional",
- "Test", testMarshalNode(node.Test),
- "Consequent", testMarshalNode(node.Consequent),
- "Alternate", testMarshalNode(node.Alternate),
- )
- case *ast.DotExpression:
- return marshal("Dot",
- "Left", testMarshalNode(node.Left),
- "Member", node.Identifier.Name,
- )
- case *ast.NewExpression:
- return marshal("New",
- "Callee", testMarshalNode(node.Callee),
- "ArgumentList", testMarshalNode(node.ArgumentList),
- )
- case *ast.NullLiteral:
- return marshal("Literal", nil)
- case *ast.NumberLiteral:
- return marshal("Literal", node.Value)
- case *ast.ObjectLiteral:
- return marshal("Object", testMarshalNode(node.Value))
- case *ast.RegExpLiteral:
- return marshal("Literal", node.Literal)
- case *ast.StringLiteral:
- return marshal("Literal", node.Literal)
- case *ast.Binding:
- return marshal("Binding", "Target", testMarshalNode(node.Target),
- "Initializer", testMarshalNode(node.Initializer))
- // Statement
- case *ast.Program:
- return testMarshalNode(node.Body)
- case *ast.BlockStatement:
- return marshal("BlockStatement", testMarshalNode(node.List))
- case *ast.EmptyStatement:
- return "EmptyStatement"
- case *ast.ExpressionStatement:
- return testMarshalNode(node.Expression)
- case *ast.ForInStatement:
- return marshal("ForIn",
- "Into", testMarshalNode(node.Into),
- "Source", marshal("", node.Source),
- "Body", marshal("", node.Body),
- )
- case *ast.FunctionLiteral:
- return marshal("Function", testMarshalNode(node.Body))
- case *ast.Identifier:
- return marshal("Identifier", node.Name)
- case *ast.IfStatement:
- if_ := marshal("",
- "Test", testMarshalNode(node.Test),
- "Consequent", testMarshalNode(node.Consequent),
- ).(map[string]interface{})
- if node.Alternate != nil {
- if_["Alternate"] = testMarshalNode(node.Alternate)
- }
- return marshal("If", if_)
- case *ast.LabelledStatement:
- return marshal("Label",
- "Name", node.Label.Name,
- "Statement", testMarshalNode(node.Statement),
- )
- case *ast.PropertyKeyed:
- return marshal("",
- "Key", node.Key,
- "Value", testMarshalNode(node.Value),
- )
- case *ast.ReturnStatement:
- return marshal("Return", testMarshalNode(node.Argument))
- case *ast.SequenceExpression:
- return marshal("Sequence", testMarshalNode(node.Sequence))
- case *ast.ThrowStatement:
- return marshal("Throw", testMarshalNode(node.Argument))
- case *ast.VariableStatement:
- return marshal("Var", testMarshalNode(node.List))
- // Special
- case *ast.ForDeclaration:
- return marshal("For-Into-Decl", testMarshalNode(node.Target))
- case *ast.ForIntoVar:
- return marshal("For-Into-Var", testMarshalNode(node.Binding))
- }
- {
- value := reflect.ValueOf(node)
- if value.Kind() == reflect.Slice {
- tmp0 := []interface{}{}
- for index := 0; index < value.Len(); index++ {
- tmp0 = append(tmp0, testMarshalNode(value.Index(index).Interface()))
- }
- return tmp0
- }
- }
- return nil
- }
- func testMarshal(node interface{}) string {
- value, err := json.Marshal(testMarshalNode(node))
- if err != nil {
- panic(err)
- }
- return string(value)
- }
- func TestParserAST(t *testing.T) {
- tt(t, func() {
- test := func(inputOutput string) {
- match := matchBeforeAfterSeparator.FindStringIndex(inputOutput)
- input := strings.TrimSpace(inputOutput[0:match[0]])
- wantOutput := strings.TrimSpace(inputOutput[match[1]:])
- _, program, err := testParse(input)
- is(err, nil)
- haveOutput := testMarshal(program)
- tmp0, tmp1 := bytes.Buffer{}, bytes.Buffer{}
- json.Indent(&tmp0, []byte(haveOutput), "\t\t", " ")
- json.Indent(&tmp1, []byte(wantOutput), "\t\t", " ")
- is("\n\t\t"+tmp0.String(), "\n\t\t"+tmp1.String())
- }
- test(`
- ---
- []
- `)
- test(`
- ;
- ---
- [
- "EmptyStatement"
- ]
- `)
- test(`
- ;;;
- ---
- [
- "EmptyStatement",
- "EmptyStatement",
- "EmptyStatement"
- ]
- `)
- test(`
- 1; true; abc; "abc"; null;
- ---
- [
- {
- "Literal": 1
- },
- {
- "Literal": true
- },
- {
- "Identifier": "abc"
- },
- {
- "Literal": "\"abc\""
- },
- {
- "Literal": null
- }
- ]
- `)
- test(`
- { 1; null; 3.14159; ; }
- ---
- [
- {
- "BlockStatement": [
- {
- "Literal": 1
- },
- {
- "Literal": null
- },
- {
- "Literal": 3.14159
- },
- "EmptyStatement"
- ]
- }
- ]
- `)
- test(`
- new abc();
- ---
- [
- {
- "New": {
- "ArgumentList": [],
- "Callee": {
- "Identifier": "abc"
- }
- }
- }
- ]
- `)
- test(`
- new abc(1, 3.14159)
- ---
- [
- {
- "New": {
- "ArgumentList": [
- {
- "Literal": 1
- },
- {
- "Literal": 3.14159
- }
- ],
- "Callee": {
- "Identifier": "abc"
- }
- }
- }
- ]
- `)
- test(`
- true ? false : true
- ---
- [
- {
- "Conditional": {
- "Alternate": {
- "Literal": true
- },
- "Consequent": {
- "Literal": false
- },
- "Test": {
- "Literal": true
- }
- }
- }
- ]
- `)
- test(`
- true || false
- ---
- [
- {
- "BinaryExpression": {
- "Left": {
- "Literal": true
- },
- "Operator": "||",
- "Right": {
- "Literal": false
- }
- }
- }
- ]
- `)
- test(`
- 0 + { abc: true }
- ---
- [
- {
- "BinaryExpression": {
- "Left": {
- "Literal": 0
- },
- "Operator": "+",
- "Right": {
- "Object": [
- {
- "Key": {
- "Idx": 7,
- "Literal": "abc",
- "Value": "abc"
- },
- "Value": {
- "Literal": true
- }
- }
- ]
- }
- }
- }
- ]
- `)
- test(`
- 1 == "1"
- ---
- [
- {
- "BinaryExpression": {
- "Left": {
- "Literal": 1
- },
- "Operator": "==",
- "Right": {
- "Literal": "\"1\""
- }
- }
- }
- ]
- `)
- test(`
- abc(1)
- ---
- [
- {
- "Call": {
- "ArgumentList": [
- {
- "Literal": 1
- }
- ],
- "Callee": {
- "Identifier": "abc"
- }
- }
- }
- ]
- `)
- test(`
- Math.pow(3, 2)
- ---
- [
- {
- "Call": {
- "ArgumentList": [
- {
- "Literal": 3
- },
- {
- "Literal": 2
- }
- ],
- "Callee": {
- "Dot": {
- "Left": {
- "Identifier": "Math"
- },
- "Member": "pow"
- }
- }
- }
- }
- ]
- `)
- test(`
- 1, 2, 3
- ---
- [
- {
- "Sequence": [
- {
- "Literal": 1
- },
- {
- "Literal": 2
- },
- {
- "Literal": 3
- }
- ]
- }
- ]
- `)
- test(`
- / abc /gim;
- ---
- [
- {
- "Literal": "/ abc /gim"
- }
- ]
- `)
- test(`
- if (0)
- 1;
- ---
- [
- {
- "If": {
- "Consequent": {
- "Literal": 1
- },
- "Test": {
- "Literal": 0
- }
- }
- }
- ]
- `)
- test(`
- 0+function(){
- return;
- }
- ---
- [
- {
- "BinaryExpression": {
- "Left": {
- "Literal": 0
- },
- "Operator": "+",
- "Right": {
- "Function": {
- "BlockStatement": [
- {
- "Return": null
- }
- ]
- }
- }
- }
- }
- ]
- `)
- test(`
- xyzzy // Ignore it
- // Ignore this
- // And this
- /* And all..
- ... of this!
- */
- "Nothing happens."
- // And finally this
- ---
- [
- {
- "Identifier": "xyzzy"
- },
- {
- "Literal": "\"Nothing happens.\""
- }
- ]
- `)
- test(`
- ((x & (x = 1)) !== 0)
- ---
- [
- {
- "BinaryExpression": {
- "Left": {
- "BinaryExpression": {
- "Left": {
- "Identifier": "x"
- },
- "Operator": "\u0026",
- "Right": {
- "Assign": {
- "Left": {
- "Identifier": "x"
- },
- "Right": {
- "Literal": 1
- }
- }
- }
- }
- },
- "Operator": "!==",
- "Right": {
- "Literal": 0
- }
- }
- }
- ]
- `)
- test(`
- { abc: 'def' }
- ---
- [
- {
- "BlockStatement": [
- {
- "Label": {
- "Name": "abc",
- "Statement": {
- "Literal": "'def'"
- }
- }
- }
- ]
- }
- ]
- `)
- test(`
- // This is not an object, this is a string literal with a label!
- ({ abc: 'def' })
- ---
- [
- {
- "Object": [
- {
- "Key": {
- "Idx": 77,
- "Literal": "abc",
- "Value": "abc"
- },
- "Value": {
- "Literal": "'def'"
- }
- }
- ]
- }
- ]
- `)
- test(`
- [,]
- ---
- [
- {
- "Array": [
- null
- ]
- }
- ]
- `)
- test(`
- [,,]
- ---
- [
- {
- "Array": [
- null,
- null
- ]
- }
- ]
- `)
- test(`
- ({ get abc() {} })
- ---
- [
- {
- "Object": [
- {
- "Key": {
- "Idx": 8,
- "Literal": "abc",
- "Value": "abc"
- },
- "Value": {
- "Function": {
- "BlockStatement": []
- }
- }
- }
- ]
- }
- ]
- `)
- test(`
- /abc/.source
- ---
- [
- {
- "Dot": {
- "Left": {
- "Literal": "/abc/"
- },
- "Member": "source"
- }
- }
- ]
- `)
- test(`
- xyzzy
- throw new TypeError("Nothing happens.")
- ---
- [
- {
- "Identifier": "xyzzy"
- },
- {
- "Throw": {
- "New": {
- "ArgumentList": [
- {
- "Literal": "\"Nothing happens.\""
- }
- ],
- "Callee": {
- "Identifier": "TypeError"
- }
- }
- }
- }
- ]
- `)
- // When run, this will call a type error to be thrown
- // This is essentially the same as:
- //
- // var abc = 1(function(){})()
- //
- test(`
- var abc = 1
- (function(){
- })()
- ---
- [
- {
- "Var": [
- {
- "Binding": {
- "Initializer": {
- "Call": {
- "ArgumentList": [],
- "Callee": {
- "Call": {
- "ArgumentList": [
- {
- "Function": {
- "BlockStatement": []
- }
- }
- ],
- "Callee": {
- "Literal": 1
- }
- }
- }
- }
- },
- "Target": {
- "Identifier": "abc"
- }
- }
- }
- ]
- }
- ]
- `)
- test(`
- "use strict"
- ---
- [
- {
- "Literal": "\"use strict\""
- }
- ]
- `)
- test(`
- "use strict"
- abc = 1 + 2 + 11
- ---
- [
- {
- "Literal": "\"use strict\""
- },
- {
- "Assign": {
- "Left": {
- "Identifier": "abc"
- },
- "Right": {
- "BinaryExpression": {
- "Left": {
- "BinaryExpression": {
- "Left": {
- "Literal": 1
- },
- "Operator": "+",
- "Right": {
- "Literal": 2
- }
- }
- },
- "Operator": "+",
- "Right": {
- "Literal": 11
- }
- }
- }
- }
- }
- ]
- `)
- test(`
- abc = function() { 'use strict' }
- ---
- [
- {
- "Assign": {
- "Left": {
- "Identifier": "abc"
- },
- "Right": {
- "Function": {
- "BlockStatement": [
- {
- "Literal": "'use strict'"
- }
- ]
- }
- }
- }
- }
- ]
- `)
- test(`
- for (var abc in def) {
- }
- ---
- [
- {
- "ForIn": {
- "Body": {
- "BlockStatement": []
- },
- "Into": {
- "For-Into-Var": {
- "Binding": {
- "Initializer": null,
- "Target": {
- "Identifier": "abc"
- }
- }
- }
- },
- "Source": {
- "Identifier": "def"
- }
- }
- }
- ]
- `)
- test(`
- abc = {
- '"': "'",
- "'": '"',
- }
- ---
- [
- {
- "Assign": {
- "Left": {
- "Identifier": "abc"
- },
- "Right": {
- "Object": [
- {
- "Key": {
- "Idx": 21,
- "Literal": "'\"'",
- "Value": "\""
- },
- "Value": {
- "Literal": "\"'\""
- }
- },
- {
- "Key": {
- "Idx": 43,
- "Literal": "\"'\"",
- "Value": "'"
- },
- "Value": {
- "Literal": "'\"'"
- }
- }
- ]
- }
- }
- }
- ]
- `)
- return
- test(`
- if (!abc && abc.jkl(def) && abc[0] === +abc[0] && abc.length < ghi) {
- }
- ---
- [
- {
- "If": {
- "Consequent": {
- "BlockStatement": []
- },
- "Test": {
- "BinaryExpression": {
- "Left": {
- "BinaryExpression": {
- "Left": {
- "BinaryExpression": {
- "Left": null,
- "Operator": "\u0026\u0026",
- "Right": {
- "Call": {
- "ArgumentList": [
- {
- "Identifier": "def"
- }
- ],
- "Callee": {
- "Dot": {
- "Left": {
- "Identifier": "abc"
- },
- "Member": "jkl"
- }
- }
- }
- }
- }
- },
- "Operator": "\u0026\u0026",
- "Right": {
- "BinaryExpression": {
- "Left": null,
- "Operator": "===",
- "Right": null
- }
- }
- }
- },
- "Operator": "\u0026\u0026",
- "Right": {
- "BinaryExpression": {
- "Left": {
- "Dot": {
- "Left": {
- "Identifier": "abc"
- },
- "Member": "length"
- }
- },
- "Operator": "\u003c",
- "Right": {
- "Identifier": "ghi"
- }
- }
- }
- }
- }
- }
- }
- ]
- `)
- })
- }
|