1 package parser
2
3 import (
4 "bytes"
5 "encoding/json"
6 "reflect"
7 "strings"
8 "testing"
9
10 "github.com/dop251/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
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
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
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
707
708
709
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 }
891
View as plain text