1package js
2
3import (
4 "bytes"
5 "fmt"
6 "io"
7 "strconv"
8
9 "github.com/tdewolff/parse/v2"
10)
11
12var ErrInvalidJSON = fmt.Errorf("invalid JSON")
13
14type JSONer interface {
15 JSON(*bytes.Buffer) error
16}
17
18// AST is the full ECMAScript abstract syntax tree.
19type AST struct {
20 Comments [][]byte // first comments in file
21 BlockStmt // module
22}
23
24func (ast *AST) String() string {
25 s := ""
26 for i, item := range ast.BlockStmt.List {
27 if i != 0 {
28 s += " "
29 }
30 s += item.String()
31 }
32 return s
33}
34
35////////////////////////////////////////////////////////////////
36
37// DeclType specifies the kind of declaration.
38type DeclType uint16
39
40// DeclType values.
41const (
42 NoDecl DeclType = iota // undeclared variables
43 VariableDecl // var
44 FunctionDecl // function
45 ArgumentDecl // function and method arguments
46 LexicalDecl // let, const, class
47 CatchDecl // catch statement argument
48 ExprDecl // function expression name or class expression name
49)
50
51func (decl DeclType) String() string {
52 switch decl {
53 case NoDecl:
54 return "NoDecl"
55 case VariableDecl:
56 return "VariableDecl"
57 case FunctionDecl:
58 return "FunctionDecl"
59 case ArgumentDecl:
60 return "ArgumentDecl"
61 case LexicalDecl:
62 return "LexicalDecl"
63 case CatchDecl:
64 return "CatchDecl"
65 case ExprDecl:
66 return "ExprDecl"
67 }
68 return "Invalid(" + strconv.Itoa(int(decl)) + ")"
69}
70
71// Var is a variable, where Decl is the type of declaration and can be var|function for function scoped variables, let|const|class for block scoped variables.
72type Var struct {
73 Data []byte
74 Link *Var // is set when merging variable uses, as in: {a} {var a} where the first links to the second, only used for undeclared variables
75 Uses uint16
76 Decl DeclType
77}
78
79// Name returns the variable name.
80func (v *Var) Name() []byte {
81 for v.Link != nil {
82 v = v.Link
83 }
84 return v.Data
85}
86
87func (v Var) String() string {
88 return string(v.Name())
89}
90
91// JS converts the node back to valid JavaScript
92func (v Var) JS() string {
93 return v.String()
94}
95
96// JS converts the node back to valid JavaScript (writes to io.Writer)
97func (v Var) JSWriteTo(w io.Writer) (i int, err error) {
98 return w.Write(v.Name())
99}
100
101// VarsByUses is sortable by uses in descending order.
102// TODO: write custom sorter for varsbyuses
103type VarsByUses VarArray
104
105func (vs VarsByUses) Len() int {
106 return len(vs)
107}
108
109func (vs VarsByUses) Swap(i, j int) {
110 vs[i], vs[j] = vs[j], vs[i]
111}
112
113func (vs VarsByUses) Less(i, j int) bool {
114 return vs[i].Uses > vs[j].Uses
115}
116
117////////////////////////////////////////////////////////////////
118
119// VarArray is a set of variables in scopes.
120type VarArray []*Var
121
122func (vs VarArray) String() string {
123 s := "["
124 for i, v := range vs {
125 if i != 0 {
126 s += ", "
127 }
128 links := 0
129 for v.Link != nil {
130 v = v.Link
131 links++
132 }
133 s += fmt.Sprintf("Var{%v %s %v %v}", v.Decl, string(v.Data), links, v.Uses)
134 }
135 return s + "]"
136}
137
138// Scope is a function or block scope with a list of variables declared and used.
139type Scope struct {
140 Parent, Func *Scope // Parent is nil for global scope
141 Declared VarArray // Link in Var are always nil
142 Undeclared VarArray
143 VarDecls []*VarDecl
144 NumForDecls uint16 // offset into Declared to mark variables used in for statements
145 NumFuncArgs uint16 // offset into Declared to mark variables used in function arguments
146 NumArgUses uint16 // offset into Undeclared to mark variables used in arguments
147 IsGlobalOrFunc bool
148 HasWith bool
149}
150
151func (s Scope) String() string {
152 return "Scope{Declared: " + s.Declared.String() + ", Undeclared: " + s.Undeclared.String() + "}"
153}
154
155// Declare declares a new variable.
156func (s *Scope) Declare(decl DeclType, name []byte) (*Var, bool) {
157 // refer to new variable for previously undeclared symbols in the current and lower scopes
158 // this happens in `{ a = 5; } var a` where both a's refer to the same variable
159 curScope := s
160 if decl == VariableDecl || decl == FunctionDecl {
161 // find function scope for var and function declarations
162 for s != s.Func {
163 // make sure that `{let i;{var i}}` is an error
164 if v := s.findDeclared(name, false); v != nil && v.Decl != decl && v.Decl != CatchDecl {
165 return nil, false
166 }
167 s = s.Parent
168 }
169 }
170
171 if v := s.findDeclared(name, true); v != nil {
172 // variable already declared, might be an error or a duplicate declaration
173 if (ArgumentDecl < v.Decl || FunctionDecl < decl) && v.Decl != ExprDecl {
174 // only allow (v.Decl,decl) of: (var|function|argument,var|function), (expr,*), any other combination is a syntax error
175 return nil, false
176 }
177 if v.Decl == ExprDecl {
178 v.Decl = decl
179 }
180 v.Uses++
181 for s != curScope {
182 curScope.AddUndeclared(v) // add variable declaration as used variable to the current scope
183 curScope = curScope.Parent
184 }
185 return v, true
186 }
187
188 var v *Var
189 // reuse variable if previously used, as in: a;var a
190 if decl != ArgumentDecl { // in case of function f(a=b,b), where the first b is different from the second
191 for i, uv := range s.Undeclared[s.NumArgUses:] {
192 // no need to evaluate v.Link as v.Data stays the same and Link is nil in the active scope
193 if 0 < uv.Uses && uv.Decl == NoDecl && bytes.Equal(name, uv.Data) {
194 // must be NoDecl so that it can't be a var declaration that has been added
195 v = uv
196 s.Undeclared = append(s.Undeclared[:int(s.NumArgUses)+i], s.Undeclared[int(s.NumArgUses)+i+1:]...)
197 break
198 }
199 }
200 }
201 if v == nil {
202 // add variable to the context list and to the scope
203 v = &Var{name, nil, 0, decl}
204 } else {
205 v.Decl = decl
206 }
207 v.Uses++
208 s.Declared = append(s.Declared, v)
209 for s != curScope {
210 curScope.AddUndeclared(v) // add variable declaration as used variable to the current scope
211 curScope = curScope.Parent
212 }
213 return v, true
214}
215
216// Use increments the usage of a variable.
217func (s *Scope) Use(name []byte) *Var {
218 // check if variable is declared in the current scope
219 v := s.findDeclared(name, false)
220 if v == nil {
221 // check if variable is already used before in the current or lower scopes
222 v = s.findUndeclared(name)
223 if v == nil {
224 // add variable to the context list and to the scope's undeclared
225 v = &Var{name, nil, 0, NoDecl}
226 s.Undeclared = append(s.Undeclared, v)
227 }
228 }
229 v.Uses++
230 return v
231}
232
233// findDeclared finds a declared variable in the current scope.
234func (s *Scope) findDeclared(name []byte, skipForDeclared bool) *Var {
235 start := 0
236 if skipForDeclared {
237 // we skip the for initializer for declarations (only has effect for let/const)
238 start = int(s.NumForDecls)
239 }
240 // reverse order to find the inner let first in `for(let a in []){let a; {a}}`
241 for i := len(s.Declared) - 1; start <= i; i-- {
242 v := s.Declared[i]
243 // no need to evaluate v.Link as v.Data stays the same, and Link is always nil in Declared
244 if bytes.Equal(name, v.Data) {
245 return v
246 }
247 }
248 return nil
249}
250
251// findUndeclared finds an undeclared variable in the current and contained scopes.
252func (s *Scope) findUndeclared(name []byte) *Var {
253 for _, v := range s.Undeclared {
254 // no need to evaluate v.Link as v.Data stays the same and Link is nil in the active scope
255 if 0 < v.Uses && bytes.Equal(name, v.Data) {
256 return v
257 }
258 }
259 return nil
260}
261
262// add undeclared variable to scope, this is called for the block scope when declaring a var in it
263func (s *Scope) AddUndeclared(v *Var) {
264 // don't add undeclared symbol if it's already there
265 for _, vorig := range s.Undeclared {
266 if v == vorig {
267 return
268 }
269 }
270 s.Undeclared = append(s.Undeclared, v) // add variable declaration as used variable to the current scope
271}
272
273// MarkForStmt marks the declared variables in current scope as for statement initializer to distinguish from declarations in body.
274func (s *Scope) MarkForStmt() {
275 s.NumForDecls = uint16(len(s.Declared))
276 s.NumArgUses = uint16(len(s.Undeclared)) // ensures for different b's in for(var a in b){let b}
277}
278
279// MarkFuncArgs marks the declared/undeclared variables in the current scope as function arguments.
280func (s *Scope) MarkFuncArgs() {
281 s.NumFuncArgs = uint16(len(s.Declared))
282 s.NumArgUses = uint16(len(s.Undeclared)) // ensures different b's in `function f(a=b){var b}`.
283}
284
285// HoistUndeclared copies all undeclared variables of the current scope to the parent scope.
286func (s *Scope) HoistUndeclared() {
287 for i, vorig := range s.Undeclared {
288 // no need to evaluate vorig.Link as vorig.Data stays the same
289 if 0 < vorig.Uses && vorig.Decl == NoDecl {
290 if v := s.Parent.findDeclared(vorig.Data, false); v != nil {
291 // check if variable is declared in parent scope
292 v.Uses += vorig.Uses
293 vorig.Link = v
294 s.Undeclared[i] = v // point reference to existing var (to avoid many Link chains)
295 } else if v := s.Parent.findUndeclared(vorig.Data); v != nil {
296 // check if variable is already used before in parent scope
297 v.Uses += vorig.Uses
298 vorig.Link = v
299 s.Undeclared[i] = v // point reference to existing var (to avoid many Link chains)
300 } else {
301 // add variable to the context list and to the scope's undeclared
302 s.Parent.Undeclared = append(s.Parent.Undeclared, vorig)
303 }
304 }
305 }
306}
307
308// UndeclareScope undeclares all declared variables in the current scope and adds them to the parent scope.
309// Called when possible arrow func ends up being a parenthesized expression, scope is not further used.
310func (s *Scope) UndeclareScope() {
311 // look if the variable already exists in the parent scope, if so replace the Var pointer in original use
312 for _, vorig := range s.Declared {
313 // no need to evaluate vorig.Link as vorig.Data stays the same, and Link is always nil in Declared
314 // vorig.Uses will be atleast 1
315 if v := s.Parent.findDeclared(vorig.Data, false); v != nil {
316 // check if variable has been declared in this scope
317 v.Uses += vorig.Uses
318 vorig.Link = v
319 } else if v := s.Parent.findUndeclared(vorig.Data); v != nil {
320 // check if variable is already used before in the current or lower scopes
321 v.Uses += vorig.Uses
322 vorig.Link = v
323 } else {
324 // add variable to the context list and to the scope's undeclared
325 vorig.Decl = NoDecl
326 s.Parent.Undeclared = append(s.Parent.Undeclared, vorig)
327 }
328 }
329 s.Declared = s.Declared[:0]
330 s.Undeclared = s.Undeclared[:0]
331}
332
333// Unscope moves all declared variables of the current scope to the parent scope. Undeclared variables are already in the parent scope.
334func (s *Scope) Unscope() {
335 for _, vorig := range s.Declared {
336 // no need to evaluate vorig.Link as vorig.Data stays the same, and Link is always nil in Declared
337 // vorig.Uses will be atleast 1
338 s.Parent.Declared = append(s.Parent.Declared, vorig)
339 }
340 s.Declared = s.Declared[:0]
341 s.Undeclared = s.Undeclared[:0]
342}
343
344////////////////////////////////////////////////////////////////
345
346// INode is an interface for AST nodes
347type INode interface {
348 String() string
349 JS() string
350 JSWriteTo(io.Writer) (int, error)
351}
352
353// IStmt is a dummy interface for statements.
354type IStmt interface {
355 INode
356 stmtNode()
357}
358
359// IBinding is a dummy interface for bindings.
360type IBinding interface {
361 INode
362 bindingNode()
363}
364
365// IExpr is a dummy interface for expressions.
366type IExpr interface {
367 INode
368 exprNode()
369}
370
371////////////////////////////////////////////////////////////////
372
373// BlockStmt is a block statement.
374type BlockStmt struct {
375 List []IStmt
376 Scope
377}
378
379func (n BlockStmt) String() string {
380 s := "Stmt({"
381 for _, item := range n.List {
382 s += " " + item.String()
383 }
384 return s + " })"
385}
386
387// JS converts the node back to valid JavaScript
388func (n BlockStmt) JS() string {
389 s := ""
390 if n.Scope.Parent != nil {
391 s += "{ "
392 }
393 for _, item := range n.List {
394 if _, isEmpty := item.(*EmptyStmt); !isEmpty {
395 s += item.JS() + "; "
396 }
397 }
398 if n.Scope.Parent != nil {
399 s += "}"
400 }
401 return s
402}
403
404// JS converts the node back to valid JavaScript (writes to io.Writer)
405func (n BlockStmt) JSWriteTo(w io.Writer) (i int, err error) {
406 var wn int
407 if n.Scope.Parent != nil {
408 wn, err = w.Write([]byte("{ "))
409 i += wn
410 if err != nil {
411 return
412 }
413 }
414 for _, item := range n.List {
415 if _, isEmpty := item.(*EmptyStmt); !isEmpty {
416 wn, err = item.JSWriteTo(w)
417 i += wn
418 if err != nil {
419 return
420 }
421 wn, err = w.Write([]byte("; "))
422 i += wn
423 if err != nil {
424 return
425 }
426 }
427 }
428 if n.Scope.Parent != nil {
429 wn, err = w.Write([]byte{'}'})
430 i += wn
431 if err != nil {
432 return
433 }
434 }
435 return
436}
437
438// EmptyStmt is an empty statement.
439type EmptyStmt struct {
440}
441
442func (n EmptyStmt) String() string {
443 return "Stmt(;)"
444}
445
446// JS converts the node back to valid JavaScript
447func (n EmptyStmt) JS() string {
448 return ";"
449}
450
451// JS converts the node back to valid JavaScript (writes to io.Writer)
452func (n EmptyStmt) JSWriteTo(w io.Writer) (i int, err error) {
453 wn, err := w.Write([]byte{';'})
454 i = wn
455 return
456}
457
458// ExprStmt is an expression statement.
459type ExprStmt struct {
460 Value IExpr
461}
462
463func (n ExprStmt) String() string {
464 val := n.Value.String()
465 if val[0] == '(' && val[len(val)-1] == ')' {
466 return "Stmt" + n.Value.String()
467 }
468 return "Stmt(" + n.Value.String() + ")"
469}
470
471// JS converts the node back to valid JavaScript
472func (n ExprStmt) JS() string {
473 return n.Value.JS()
474}
475
476// JS converts the node back to valid JavaScript (writes to io.Writer)
477func (n ExprStmt) JSWriteTo(w io.Writer) (i int, err error) {
478 return n.Value.JSWriteTo(w)
479}
480
481// IfStmt is an if statement.
482type IfStmt struct {
483 Cond IExpr
484 Body IStmt
485 Else IStmt // can be nil
486}
487
488func (n IfStmt) String() string {
489 s := "Stmt(if " + n.Cond.String() + " " + n.Body.String()
490 if n.Else != nil {
491 s += " else " + n.Else.String()
492 }
493 return s + ")"
494}
495
496// JS converts the node back to valid JavaScript
497func (n IfStmt) JS() string {
498 s := "if (" + n.Cond.JS() + ") "
499 switch n.Body.(type) {
500 case *BlockStmt:
501 s += n.Body.JS()
502 default:
503 s += "{ " + n.Body.JS() + " }"
504 }
505 if n.Else != nil {
506 switch n.Else.(type) {
507 case *BlockStmt:
508 s += " else " + n.Else.JS()
509 default:
510 s += " else { " + n.Else.JS() + " }"
511 }
512 }
513 return s
514}
515
516// JS converts the node back to valid JavaScript (writes to io.Writer)
517func (n IfStmt) JSWriteTo(w io.Writer) (i int, err error) {
518 var wn int
519 wn, err = w.Write([]byte("if ("))
520 i += wn
521 if err != nil {
522 return
523 }
524 wn, err = n.Cond.JSWriteTo(w)
525 i += wn
526 if err != nil {
527 return
528 }
529 wn, err = w.Write([]byte(") "))
530 i += wn
531 if err != nil {
532 return
533 }
534 switch n.Body.(type) {
535 case *BlockStmt:
536 wn, err = n.Body.JSWriteTo(w)
537 i += wn
538 if err != nil {
539 return
540 }
541 default:
542 wn, err = w.Write([]byte("{ "))
543 i += wn
544 if err != nil {
545 return
546 }
547 wn, err = n.Body.JSWriteTo(w)
548 i += wn
549 if err != nil {
550 return
551 }
552 wn, err = w.Write([]byte(" }"))
553 i += wn
554 if err != nil {
555 return
556 }
557 }
558 if n.Else != nil {
559 switch n.Else.(type) {
560 case *BlockStmt:
561 wn, err = w.Write([]byte(" else "))
562 i += wn
563 if err != nil {
564 return
565 }
566 wn, err = n.Else.JSWriteTo(w)
567 i += wn
568 if err != nil {
569 return
570 }
571 default:
572 wn, err = w.Write([]byte(" else { "))
573 i += wn
574 if err != nil {
575 return
576 }
577 wn, err = n.Else.JSWriteTo(w)
578 i += wn
579 if err != nil {
580 return
581 }
582 wn, err = w.Write([]byte(" }"))
583 i += wn
584 if err != nil {
585 return
586 }
587 }
588 }
589 return
590}
591
592// DoWhileStmt is a do-while iteration statement.
593type DoWhileStmt struct {
594 Cond IExpr
595 Body IStmt
596}
597
598func (n DoWhileStmt) String() string {
599 return "Stmt(do " + n.Body.String() + " while " + n.Cond.String() + ")"
600}
601
602// JS converts the node back to valid JavaScript
603func (n DoWhileStmt) JS() string {
604 s := "do "
605 switch n.Body.(type) {
606 case *BlockStmt:
607 s += n.Body.JS()
608 default:
609 s += "{ " + n.Body.JS() + " }"
610 }
611 return s + " while (" + n.Cond.JS() + ")"
612}
613
614// JS converts the node back to valid JavaScript (writes to io.Writer)
615func (n DoWhileStmt) JSWriteTo(w io.Writer) (i int, err error) {
616 var wn int
617 wn, err = w.Write([]byte("do "))
618 i += wn
619 if err != nil {
620 return
621 }
622 switch n.Body.(type) {
623 case *BlockStmt:
624 wn, err = n.Body.JSWriteTo(w)
625 i += wn
626 if err != nil {
627 return
628 }
629 default:
630 wn, err = w.Write([]byte("{ "))
631 i += wn
632 if err != nil {
633 return
634 }
635 wn, err = n.Body.JSWriteTo(w)
636 i += wn
637 if err != nil {
638 return
639 }
640 wn, err = w.Write([]byte(" }"))
641 i += wn
642 if err != nil {
643 return
644 }
645 }
646 wn, err = w.Write([]byte(" while ("))
647 i += wn
648 if err != nil {
649 return
650 }
651 wn, err = n.Cond.JSWriteTo(w)
652 i += wn
653 if err != nil {
654 return
655 }
656 wn, err = w.Write([]byte(")"))
657 i += wn
658 return
659}
660
661// WhileStmt is a while iteration statement.
662type WhileStmt struct {
663 Cond IExpr
664 Body IStmt
665}
666
667func (n WhileStmt) String() string {
668 return "Stmt(while " + n.Cond.String() + " " + n.Body.String() + ")"
669}
670
671// JS converts the node back to valid JavaScript
672func (n WhileStmt) JS() string {
673 s := "while (" + n.Cond.JS() + ") "
674 if n.Body != nil {
675 s += n.Body.JS()
676 }
677 return s
678}
679
680// JS converts the node back to valid JavaScript (writes to io.Writer)
681func (n WhileStmt) JSWriteTo(w io.Writer) (i int, err error) {
682 var wn int
683 wn, err = w.Write([]byte("while ("))
684 i += wn
685 if err != nil {
686 return
687 }
688 wn, err = n.Cond.JSWriteTo(w)
689 i += wn
690 if err != nil {
691 return
692 }
693 wn, err = w.Write([]byte(") "))
694 i += wn
695 if err != nil {
696 return
697 }
698 if n.Body != nil {
699 wn, err = n.Body.JSWriteTo(w)
700 i += wn
701 if err != nil {
702 return
703 }
704 }
705 return
706}
707
708// ForStmt is a regular for iteration statement.
709type ForStmt struct {
710 Init IExpr // can be nil
711 Cond IExpr // can be nil
712 Post IExpr // can be nil
713 Body *BlockStmt
714}
715
716func (n ForStmt) String() string {
717 s := "Stmt(for"
718 if v, ok := n.Init.(*VarDecl); !ok && n.Init != nil || ok && len(v.List) != 0 {
719 s += " " + n.Init.String()
720 }
721 s += " ;"
722 if n.Cond != nil {
723 s += " " + n.Cond.String()
724 }
725 s += " ;"
726 if n.Post != nil {
727 s += " " + n.Post.String()
728 }
729 return s + " " + n.Body.String() + ")"
730}
731
732// JS converts the node back to valid JavaScript
733func (n ForStmt) JS() string {
734 s := "for ("
735 if v, ok := n.Init.(*VarDecl); !ok && n.Init != nil || ok && len(v.List) != 0 {
736 s += n.Init.JS()
737 } else {
738 s += " "
739 }
740 s += "; "
741 if n.Cond != nil {
742 s += n.Cond.JS()
743 }
744 s += "; "
745 if n.Post != nil {
746 s += n.Post.JS()
747 }
748 return s + ") " + n.Body.JS()
749}
750
751// JS converts the node back to valid JavaScript (writes to io.Writer)
752func (n ForStmt) JSWriteTo(w io.Writer) (i int, err error) {
753 var wn int
754 wn, err = w.Write([]byte("for ("))
755 i += wn
756 if err != nil {
757 return
758 }
759 if v, ok := n.Init.(*VarDecl); !ok && n.Init != nil || ok && len(v.List) != 0 {
760 wn, err = n.Init.JSWriteTo(w)
761 i += wn
762 if err != nil {
763 return
764 }
765 } else {
766 wn, err = w.Write([]byte(" "))
767 i += wn
768 if err != nil {
769 return
770 }
771 }
772 wn, err = w.Write([]byte("; "))
773 i += wn
774 if err != nil {
775 return
776 }
777 if n.Cond != nil {
778 wn, err = n.Cond.JSWriteTo(w)
779 i += wn
780 if err != nil {
781 return
782 }
783 }
784 wn, err = w.Write([]byte("; "))
785 i += wn
786 if err != nil {
787 return
788 }
789 if n.Post != nil {
790 wn, err = n.Post.JSWriteTo(w)
791 i += wn
792 if err != nil {
793 return
794 }
795 }
796 wn, err = w.Write([]byte(") "))
797 i += wn
798 if err != nil {
799 return
800 }
801 wn, err = n.Body.JSWriteTo(w)
802 i += wn
803 return
804}
805
806// ForInStmt is a for-in iteration statement.
807type ForInStmt struct {
808 Init IExpr
809 Value IExpr
810 Body *BlockStmt
811}
812
813func (n ForInStmt) String() string {
814 return "Stmt(for " + n.Init.String() + " in " + n.Value.String() + " " + n.Body.String() + ")"
815}
816
817// JS converts the node back to valid JavaScript
818func (n ForInStmt) JS() string {
819 return "for (" + n.Init.JS() + " in " + n.Value.JS() + ") " + n.Body.JS()
820}
821
822// JS converts the node back to valid JavaScript (writes to io.Writer)
823func (n ForInStmt) JSWriteTo(w io.Writer) (i int, err error) {
824 var wn int
825 wn, err = w.Write([]byte("for ("))
826 i += wn
827 if err != nil {
828 return
829 }
830 wn, err = n.Init.JSWriteTo(w)
831 i += wn
832 if err != nil {
833 return
834 }
835 wn, err = w.Write([]byte(" in "))
836 i += wn
837 if err != nil {
838 return
839 }
840 wn, err = n.Value.JSWriteTo(w)
841 i += wn
842 if err != nil {
843 return
844 }
845 wn, err = w.Write([]byte(") "))
846 i += wn
847 if err != nil {
848 return
849 }
850 wn, err = n.Body.JSWriteTo(w)
851 i += wn
852 return
853}
854
855// ForOfStmt is a for-of iteration statement.
856type ForOfStmt struct {
857 Await bool
858 Init IExpr
859 Value IExpr
860 Body *BlockStmt
861}
862
863func (n ForOfStmt) String() string {
864 s := "Stmt(for"
865 if n.Await {
866 s += " await"
867 }
868 return s + " " + n.Init.String() + " of " + n.Value.String() + " " + n.Body.String() + ")"
869}
870
871// JS converts the node back to valid JavaScript
872func (n ForOfStmt) JS() string {
873 s := "for"
874 if n.Await {
875 s += " await"
876 }
877 return s + " (" + n.Init.JS() + " of " + n.Value.JS() + ") " + n.Body.JS()
878}
879
880// JS converts the node back to valid JavaScript (writes to io.Writer)
881func (n ForOfStmt) JSWriteTo(w io.Writer) (i int, err error) {
882 var wn int
883 wn, err = w.Write([]byte("for"))
884 i += wn
885 if err != nil {
886 return
887 }
888 if n.Await {
889 wn, err = w.Write([]byte(" await"))
890 i += wn
891 if err != nil {
892 return
893 }
894 }
895 wn, err = w.Write([]byte(" ("))
896 i += wn
897 if err != nil {
898 return
899 }
900 wn, err = n.Init.JSWriteTo(w)
901 i += wn
902 if err != nil {
903 return
904 }
905 wn, err = w.Write([]byte(" of "))
906 i += wn
907 if err != nil {
908 return
909 }
910 wn, err = n.Value.JSWriteTo(w)
911 i += wn
912 if err != nil {
913 return
914 }
915 wn, err = w.Write([]byte(") "))
916 i += wn
917 if err != nil {
918 return
919 }
920 wn, err = n.Body.JSWriteTo(w)
921 i += wn
922 return
923}
924
925// CaseClause is a case clause or default clause for a switch statement.
926type CaseClause struct {
927 TokenType
928 Cond IExpr // can be nil
929 List []IStmt
930}
931
932func (n CaseClause) String() string {
933 s := " Clause(" + n.TokenType.String()
934 if n.Cond != nil {
935 s += " " + n.Cond.String()
936 }
937 for _, item := range n.List {
938 s += " " + item.String()
939 }
940 return s + ")"
941}
942
943// JS converts the node back to valid JavaScript
944func (n CaseClause) JS() string {
945 s := " "
946 if n.Cond != nil {
947 s += "case " + n.Cond.JS()
948 } else {
949 s += "default"
950 }
951 s += ":"
952 for _, item := range n.List {
953 s += " " + item.JS() + ";"
954 }
955 return s
956}
957
958// JS converts the node back to valid JavaScript (writes to io.Writer)
959func (n CaseClause) JSWriteTo(w io.Writer) (i int, err error) {
960 var wn int
961 wn, err = w.Write([]byte(" "))
962 i += wn
963 if err != nil {
964 return
965 }
966 if n.Cond != nil {
967 wn, err = w.Write([]byte("case "))
968 i += wn
969 if err != nil {
970 return
971 }
972 wn, err = n.Cond.JSWriteTo(w)
973 i += wn
974 if err != nil {
975 return
976 }
977 } else {
978 wn, err = w.Write([]byte("default"))
979 i += wn
980 if err != nil {
981 return
982 }
983 }
984 wn, err = w.Write([]byte(":"))
985 i += wn
986 if err != nil {
987 return
988 }
989 for _, item := range n.List {
990 wn, err = w.Write([]byte(" "))
991 i += wn
992 if err != nil {
993 return
994 }
995 wn, err = item.JSWriteTo(w)
996 i += wn
997 if err != nil {
998 return
999 }
1000 wn, err = w.Write([]byte(";"))
1001 i += wn
1002 if err != nil {
1003 return
1004 }
1005 }
1006 return
1007}
1008
1009// SwitchStmt is a switch statement.
1010type SwitchStmt struct {
1011 Init IExpr
1012 List []CaseClause
1013 Scope
1014}
1015
1016func (n SwitchStmt) String() string {
1017 s := "Stmt(switch " + n.Init.String()
1018 for _, clause := range n.List {
1019 s += clause.String()
1020 }
1021 return s + ")"
1022}
1023
1024// JS converts the node back to valid JavaScript
1025func (n SwitchStmt) JS() string {
1026 s := "switch (" + n.Init.JS() + ") {"
1027 for _, clause := range n.List {
1028 s += clause.JS()
1029 }
1030 return s + " }"
1031}
1032
1033// JS converts the node back to valid JavaScript (writes to io.Writer)
1034func (n SwitchStmt) JSWriteTo(w io.Writer) (i int, err error) {
1035 var wn int
1036 wn, err = w.Write([]byte("switch ("))
1037 i += wn
1038 if err != nil {
1039 return
1040 }
1041 wn, err = n.Init.JSWriteTo(w)
1042 i += wn
1043 if err != nil {
1044 return
1045 }
1046 wn, err = w.Write([]byte(") {"))
1047 i += wn
1048 if err != nil {
1049 return
1050 }
1051 for _, clause := range n.List {
1052 wn, err = clause.JSWriteTo(w)
1053 i += wn
1054 if err != nil {
1055 return
1056 }
1057 }
1058 wn, err = w.Write([]byte(" }"))
1059 i += wn
1060 return
1061}
1062
1063// BranchStmt is a continue or break statement.
1064type BranchStmt struct {
1065 Type TokenType
1066 Label []byte // can be nil
1067}
1068
1069func (n BranchStmt) String() string {
1070 s := "Stmt(" + n.Type.String()
1071 if n.Label != nil {
1072 s += " " + string(n.Label)
1073 }
1074 return s + ")"
1075}
1076
1077// JS converts the node back to valid JavaScript
1078func (n BranchStmt) JS() string {
1079 s := n.Type.String()
1080 if n.Label != nil {
1081 s += " " + string(n.Label)
1082 }
1083 return s
1084}
1085
1086// JS converts the node back to valid JavaScript (writes to io.Writer)
1087func (n BranchStmt) JSWriteTo(w io.Writer) (i int, err error) {
1088 var wn int
1089 wn, err = w.Write(n.Type.Bytes())
1090 i += wn
1091 if err != nil {
1092 return
1093 }
1094 if n.Label != nil {
1095 wn, err = w.Write([]byte(" "))
1096 i += wn
1097 if err != nil {
1098 return
1099 }
1100 wn, err = w.Write(n.Label)
1101 i += wn
1102 if err != nil {
1103 return
1104 }
1105 }
1106 return
1107}
1108
1109// ReturnStmt is a return statement.
1110type ReturnStmt struct {
1111 Value IExpr // can be nil
1112}
1113
1114func (n ReturnStmt) String() string {
1115 s := "Stmt(return"
1116 if n.Value != nil {
1117 s += " " + n.Value.String()
1118 }
1119 return s + ")"
1120}
1121
1122// JS converts the node back to valid JavaScript
1123func (n ReturnStmt) JS() string {
1124 s := "return"
1125 if n.Value != nil {
1126 s += " " + n.Value.JS()
1127 }
1128 return s
1129}
1130
1131// JS converts the node back to valid JavaScript (writes to io.Writer)
1132func (n ReturnStmt) JSWriteTo(w io.Writer) (i int, err error) {
1133 var wn int
1134 wn, err = w.Write([]byte("return"))
1135 i += wn
1136 if err != nil {
1137 return
1138 }
1139 if n.Value != nil {
1140 wn, err = w.Write([]byte(" "))
1141 i += wn
1142 if err != nil {
1143 return
1144 }
1145 wn, err = n.Value.JSWriteTo(w)
1146 i += wn
1147 if err != nil {
1148 return
1149 }
1150 }
1151 return
1152}
1153
1154// WithStmt is a with statement.
1155type WithStmt struct {
1156 Cond IExpr
1157 Body IStmt
1158}
1159
1160func (n WithStmt) String() string {
1161 return "Stmt(with " + n.Cond.String() + " " + n.Body.String() + ")"
1162}
1163
1164// JS converts the node back to valid JavaScript
1165func (n WithStmt) JS() string {
1166 return "with (" + n.Cond.JS() + ") " + n.Body.JS()
1167}
1168
1169// JS converts the node back to valid JavaScript (writes to io.Writer)
1170func (n WithStmt) JSWriteTo(w io.Writer) (i int, err error) {
1171 var wn int
1172 wn, err = w.Write([]byte("with ("))
1173 i += wn
1174 if err != nil {
1175 return
1176 }
1177 wn, err = n.Cond.JSWriteTo(w)
1178 i += wn
1179 if err != nil {
1180 return
1181 }
1182 wn, err = w.Write([]byte(") "))
1183 i += wn
1184 if err != nil {
1185 return
1186 }
1187 wn, err = n.Body.JSWriteTo(w)
1188 i += wn
1189 return
1190}
1191
1192// LabelledStmt is a labelled statement.
1193type LabelledStmt struct {
1194 Label []byte
1195 Value IStmt
1196}
1197
1198func (n LabelledStmt) String() string {
1199 return "Stmt(" + string(n.Label) + " : " + n.Value.String() + ")"
1200}
1201
1202// JS converts the node back to valid JavaScript
1203func (n LabelledStmt) JS() string {
1204 return string(n.Label) + ": " + n.Value.JS()
1205}
1206
1207// JS converts the node back to valid JavaScript (writes to io.Writer)
1208func (n LabelledStmt) JSWriteTo(w io.Writer) (i int, err error) {
1209 var wn int
1210 wn, err = w.Write(n.Label)
1211 i += wn
1212 if err != nil {
1213 return
1214 }
1215 wn, err = w.Write([]byte(": "))
1216 i += wn
1217 if err != nil {
1218 return
1219 }
1220 wn, err = n.Value.JSWriteTo(w)
1221 i += wn
1222 return
1223}
1224
1225// ThrowStmt is a throw statement.
1226type ThrowStmt struct {
1227 Value IExpr
1228}
1229
1230func (n ThrowStmt) String() string {
1231 return "Stmt(throw " + n.Value.String() + ")"
1232}
1233
1234// JS converts the node back to valid JavaScript
1235func (n ThrowStmt) JS() string {
1236 return "throw " + n.Value.JS()
1237}
1238
1239// JS converts the node back to valid JavaScript (writes to io.Writer)
1240func (n ThrowStmt) JSWriteTo(w io.Writer) (i int, err error) {
1241 var wn int
1242 wn, err = w.Write([]byte("throw "))
1243 i += wn
1244 if err != nil {
1245 return
1246 }
1247 wn, err = n.Value.JSWriteTo(w)
1248 i += wn
1249 return
1250}
1251
1252// TryStmt is a try statement.
1253type TryStmt struct {
1254 Body *BlockStmt
1255 Binding IBinding // can be nil
1256 Catch *BlockStmt // can be nil
1257 Finally *BlockStmt // can be nil
1258}
1259
1260func (n TryStmt) String() string {
1261 s := "Stmt(try " + n.Body.String()
1262 if n.Catch != nil {
1263 s += " catch"
1264 if n.Binding != nil {
1265 s += " Binding(" + n.Binding.String() + ")"
1266 }
1267 s += " " + n.Catch.String()
1268 }
1269 if n.Finally != nil {
1270 s += " finally " + n.Finally.String()
1271 }
1272 return s + ")"
1273}
1274
1275// JS converts the node back to valid JavaScript
1276func (n TryStmt) JS() string {
1277 s := "try " + n.Body.JS()
1278 if n.Catch != nil {
1279 s += " catch"
1280 if n.Binding != nil {
1281 s += "(" + n.Binding.JS() + ")"
1282 }
1283 s += " " + n.Catch.JS()
1284 }
1285 if n.Finally != nil {
1286 s += " finally " + n.Finally.JS()
1287 }
1288 return s
1289}
1290
1291// JS converts the node back to valid JavaScript (writes to io.Writer)
1292func (n TryStmt) JSWriteTo(w io.Writer) (i int, err error) {
1293 var wn int
1294 wn, err = w.Write([]byte("try "))
1295 i += wn
1296 if err != nil {
1297 return
1298 }
1299 wn, err = n.Body.JSWriteTo(w)
1300 i += wn
1301 if err != nil {
1302 return
1303 }
1304 if n.Catch != nil {
1305 wn, err = w.Write([]byte(" catch"))
1306 i += wn
1307 if err != nil {
1308 return
1309 }
1310 if n.Binding != nil {
1311 wn, err = w.Write([]byte("("))
1312 i += wn
1313 if err != nil {
1314 return
1315 }
1316 wn, err = n.Binding.JSWriteTo(w)
1317 i += wn
1318 if err != nil {
1319 return
1320 }
1321 wn, err = w.Write([]byte(")"))
1322 i += wn
1323 if err != nil {
1324 return
1325 }
1326 }
1327 wn, err = w.Write([]byte(" "))
1328 i += wn
1329 if err != nil {
1330 return
1331 }
1332 wn, err = n.Catch.JSWriteTo(w)
1333 i += wn
1334 if err != nil {
1335 return
1336 }
1337 }
1338 if n.Finally != nil {
1339 wn, err = w.Write([]byte(" finally "))
1340 i += wn
1341 if err != nil {
1342 return
1343 }
1344 wn, err = n.Finally.JSWriteTo(w)
1345 i += wn
1346 }
1347 return
1348}
1349
1350// DebuggerStmt is a debugger statement.
1351type DebuggerStmt struct {
1352}
1353
1354func (n DebuggerStmt) String() string {
1355 return "Stmt(debugger)"
1356}
1357
1358// JS converts the node back to valid JavaScript
1359func (n DebuggerStmt) JS() string {
1360 return "debugger"
1361}
1362
1363// JS converts the node back to valid JavaScript (writes to io.Writer)
1364func (n DebuggerStmt) JSWriteTo(w io.Writer) (i int, err error) {
1365 var wn int
1366 wn, err = w.Write([]byte("debugger"))
1367 i += wn
1368 return
1369}
1370
1371// Alias is a name space import or import/export specifier for import/export statements.
1372type Alias struct {
1373 Name []byte // can be nil
1374 Binding []byte // can be nil
1375}
1376
1377func (alias Alias) String() string {
1378 s := ""
1379 if alias.Name != nil {
1380 s += string(alias.Name) + " as "
1381 }
1382 return s + string(alias.Binding)
1383}
1384
1385// JS converts the node back to valid JavaScript
1386func (alias Alias) JS() string {
1387 return alias.String()
1388}
1389
1390// JS converts the node back to valid JavaScript (writes to io.Writer)
1391func (alias Alias) JSWriteTo(w io.Writer) (i int, err error) {
1392 var wn int
1393 if alias.Name != nil {
1394 wn, err = w.Write(alias.Name)
1395 i += wn
1396 if err != nil {
1397 return
1398 }
1399 wn, err = w.Write([]byte(" as "))
1400 i += wn
1401 if err != nil {
1402 return
1403 }
1404 }
1405 wn, err = w.Write(alias.Binding)
1406 i += wn
1407 return
1408}
1409
1410// ImportStmt is an import statement.
1411type ImportStmt struct {
1412 List []Alias
1413 Default []byte // can be nil
1414 Module []byte
1415}
1416
1417func (n ImportStmt) String() string {
1418 s := "Stmt(import"
1419 if n.Default != nil {
1420 s += " " + string(n.Default)
1421 if len(n.List) != 0 {
1422 s += " ,"
1423 }
1424 }
1425 if len(n.List) == 1 && len(n.List[0].Name) == 1 && n.List[0].Name[0] == '*' {
1426 s += " " + n.List[0].String()
1427 } else if 0 < len(n.List) {
1428 s += " {"
1429 for i, item := range n.List {
1430 if i != 0 {
1431 s += " ,"
1432 }
1433 if item.Binding != nil {
1434 s += " " + item.String()
1435 }
1436 }
1437 s += " }"
1438 }
1439 if n.Default != nil || len(n.List) != 0 {
1440 s += " from"
1441 }
1442 return s + " " + string(n.Module) + ")"
1443}
1444
1445// JS converts the node back to valid JavaScript
1446func (n ImportStmt) JS() string {
1447 s := "import"
1448 if n.Default != nil {
1449 s += " " + string(n.Default)
1450 if len(n.List) != 0 {
1451 s += " ,"
1452 }
1453 }
1454 if len(n.List) == 1 && len(n.List[0].Name) == 1 && n.List[0].Name[0] == '*' {
1455 s += " " + n.List[0].JS()
1456 } else if 0 < len(n.List) {
1457 s += " {"
1458 for i, item := range n.List {
1459 if i != 0 {
1460 s += " ,"
1461 }
1462 if item.Binding != nil {
1463 s += " " + item.JS()
1464 }
1465 }
1466 s += " }"
1467 }
1468 if n.Default != nil || len(n.List) != 0 {
1469 s += " from"
1470 }
1471 return s + " " + string(n.Module)
1472}
1473
1474// JS converts the node back to valid JavaScript (writes to io.Writer)
1475func (n ImportStmt) JSWriteTo(w io.Writer) (i int, err error) {
1476 var wn int
1477 wn, err = w.Write([]byte("import"))
1478 i += wn
1479 if err != nil {
1480 return
1481 }
1482 if n.Default != nil {
1483 wn, err = w.Write([]byte(" "))
1484 i += wn
1485 if err != nil {
1486 return
1487 }
1488 wn, err = w.Write(n.Default)
1489 i += wn
1490 if err != nil {
1491 return
1492 }
1493 if len(n.List) != 0 {
1494 wn, err = w.Write([]byte(" ,"))
1495 i += wn
1496 if err != nil {
1497 return
1498 }
1499 }
1500 }
1501 if len(n.List) == 1 && len(n.List[0].Name) == 1 && n.List[0].Name[0] == '*' {
1502 wn, err = w.Write([]byte(" "))
1503 i += wn
1504 if err != nil {
1505 return
1506 }
1507 wn, err = n.List[0].JSWriteTo(w)
1508 i += wn
1509 if err != nil {
1510 return
1511 }
1512 } else if 0 < len(n.List) {
1513 wn, err = w.Write([]byte(" {"))
1514 i += wn
1515 if err != nil {
1516 return
1517 }
1518 for j, item := range n.List {
1519 if j != 0 {
1520 wn, err = w.Write([]byte(" ,"))
1521 i += wn
1522 if err != nil {
1523 return
1524 }
1525 }
1526 if item.Binding != nil {
1527 wn, err = w.Write([]byte(" "))
1528 i += wn
1529 if err != nil {
1530 return
1531 }
1532 wn, err = item.JSWriteTo(w)
1533 i += wn
1534 if err != nil {
1535 return
1536 }
1537 }
1538 }
1539 wn, err = w.Write([]byte(" }"))
1540 i += wn
1541 if err != nil {
1542 return
1543 }
1544 }
1545 if n.Default != nil || len(n.List) != 0 {
1546 wn, err = w.Write([]byte(" from"))
1547 i += wn
1548 if err != nil {
1549 return
1550 }
1551 }
1552 wn, err = w.Write([]byte(" "))
1553 i += wn
1554 if err != nil {
1555 return
1556 }
1557 wn, err = w.Write(n.Module)
1558 i += wn
1559 return
1560}
1561
1562// ExportStmt is an export statement.
1563type ExportStmt struct {
1564 List []Alias
1565 Module []byte // can be nil
1566 Default bool
1567 Decl IExpr
1568}
1569
1570func (n ExportStmt) String() string {
1571 s := "Stmt(export"
1572 if n.Decl != nil {
1573 if n.Default {
1574 s += " default"
1575 }
1576 return s + " " + n.Decl.String() + ")"
1577 } else if len(n.List) == 1 && (len(n.List[0].Name) == 1 && n.List[0].Name[0] == '*' || n.List[0].Name == nil && len(n.List[0].Binding) == 1 && n.List[0].Binding[0] == '*') {
1578 s += " " + n.List[0].String()
1579 } else if 0 < len(n.List) {
1580 s += " {"
1581 for i, item := range n.List {
1582 if i != 0 {
1583 s += " ,"
1584 }
1585 if item.Binding != nil {
1586 s += " " + item.String()
1587 }
1588 }
1589 s += " }"
1590 }
1591 if n.Module != nil {
1592 s += " from " + string(n.Module)
1593 }
1594 return s + ")"
1595}
1596
1597// JS converts the node back to valid JavaScript
1598func (n ExportStmt) JS() string {
1599 s := "export"
1600 if n.Decl != nil {
1601 if n.Default {
1602 s += " default"
1603 }
1604 return s + " " + n.Decl.JS()
1605 } else if len(n.List) == 1 && (len(n.List[0].Name) == 1 && n.List[0].Name[0] == '*' || n.List[0].Name == nil && len(n.List[0].Binding) == 1 && n.List[0].Binding[0] == '*') {
1606 s += " " + n.List[0].JS()
1607 } else if 0 < len(n.List) {
1608 s += " {"
1609 for i, item := range n.List {
1610 if i != 0 {
1611 s += " ,"
1612 }
1613 if item.Binding != nil {
1614 s += " " + item.JS()
1615 }
1616 }
1617 s += " }"
1618 }
1619 if n.Module != nil {
1620 s += " from " + string(n.Module)
1621 }
1622 return s
1623}
1624
1625// JS converts the node back to valid JavaScript (writes to io.Writer)
1626func (n ExportStmt) JSWriteTo(w io.Writer) (i int, err error) {
1627 var wn int
1628 wn, err = w.Write([]byte("export"))
1629 i += wn
1630 if err != nil {
1631 return
1632 }
1633 if n.Decl != nil {
1634 if n.Default {
1635 wn, err = w.Write([]byte(" default"))
1636 i += wn
1637 if err != nil {
1638 return
1639 }
1640 }
1641 wn, err = w.Write([]byte(" "))
1642 i += wn
1643 if err != nil {
1644 return
1645 }
1646 wn, err = n.Decl.JSWriteTo(w)
1647 i += wn
1648 return
1649 } else if len(n.List) == 1 && (len(n.List[0].Name) == 1 && n.List[0].Name[0] == '*' || n.List[0].Name == nil && len(n.List[0].Binding) == 1 && n.List[0].Binding[0] == '*') {
1650 wn, err = w.Write([]byte(" "))
1651 i += wn
1652 if err != nil {
1653 return
1654 }
1655 wn, err = n.List[0].JSWriteTo(w)
1656 i += wn
1657 if err != nil {
1658 return
1659 }
1660 } else if 0 < len(n.List) {
1661 wn, err = w.Write([]byte(" {"))
1662 i += wn
1663 if err != nil {
1664 return
1665 }
1666 for j, item := range n.List {
1667 if j != 0 {
1668 wn, err = w.Write([]byte(" ,"))
1669 i += wn
1670 if err != nil {
1671 return
1672 }
1673 }
1674 if item.Binding != nil {
1675 wn, err = w.Write([]byte(" "))
1676 i += wn
1677 if err != nil {
1678 return
1679 }
1680 wn, err = item.JSWriteTo(w)
1681 i += wn
1682 if err != nil {
1683 return
1684 }
1685 }
1686 }
1687 wn, err = w.Write([]byte(" }"))
1688 i += wn
1689 if err != nil {
1690 return
1691 }
1692 }
1693 if n.Module != nil {
1694 wn, err = w.Write([]byte(" from "))
1695 i += wn
1696 if err != nil {
1697 return
1698 }
1699 wn, err = w.Write(n.Module)
1700 i += wn
1701 if err != nil {
1702 return
1703 }
1704 }
1705 return
1706}
1707
1708// DirectivePrologueStmt is a string literal at the beginning of a function or module (usually "use strict").
1709type DirectivePrologueStmt struct {
1710 Value []byte
1711}
1712
1713func (n DirectivePrologueStmt) String() string {
1714 return "Stmt(" + string(n.Value) + ")"
1715}
1716
1717// JS converts the node back to valid JavaScript
1718func (n DirectivePrologueStmt) JS() string {
1719 return string(n.Value)
1720}
1721
1722// JS converts the node back to valid JavaScript (writes to io.Writer)
1723func (n DirectivePrologueStmt) JSWriteTo(w io.Writer) (i int, err error) {
1724 var wn int
1725 wn, err = w.Write(n.Value)
1726 i += wn
1727 return
1728}
1729
1730func (n BlockStmt) stmtNode() {}
1731func (n EmptyStmt) stmtNode() {}
1732func (n ExprStmt) stmtNode() {}
1733func (n IfStmt) stmtNode() {}
1734func (n DoWhileStmt) stmtNode() {}
1735func (n WhileStmt) stmtNode() {}
1736func (n ForStmt) stmtNode() {}
1737func (n ForInStmt) stmtNode() {}
1738func (n ForOfStmt) stmtNode() {}
1739func (n SwitchStmt) stmtNode() {}
1740func (n BranchStmt) stmtNode() {}
1741func (n ReturnStmt) stmtNode() {}
1742func (n WithStmt) stmtNode() {}
1743func (n LabelledStmt) stmtNode() {}
1744func (n ThrowStmt) stmtNode() {}
1745func (n TryStmt) stmtNode() {}
1746func (n DebuggerStmt) stmtNode() {}
1747func (n ImportStmt) stmtNode() {}
1748func (n ExportStmt) stmtNode() {}
1749func (n DirectivePrologueStmt) stmtNode() {}
1750
1751////////////////////////////////////////////////////////////////
1752
1753// PropertyName is a property name for binding properties, method names, and in object literals.
1754type PropertyName struct {
1755 Literal LiteralExpr
1756 Computed IExpr // can be nil
1757}
1758
1759// IsSet returns true is PropertyName is not nil.
1760func (n PropertyName) IsSet() bool {
1761 return n.IsComputed() || n.Literal.TokenType != ErrorToken
1762}
1763
1764// IsComputed returns true if PropertyName is computed.
1765func (n PropertyName) IsComputed() bool {
1766 return n.Computed != nil
1767}
1768
1769// IsIdent returns true if PropertyName equals the given identifier name.
1770func (n PropertyName) IsIdent(data []byte) bool {
1771 return !n.IsComputed() && n.Literal.TokenType == IdentifierToken && bytes.Equal(data, n.Literal.Data)
1772}
1773
1774func (n PropertyName) String() string {
1775 if n.Computed != nil {
1776 val := n.Computed.String()
1777 if val[0] == '(' {
1778 return "[" + val[1:len(val)-1] + "]"
1779 }
1780 return "[" + val + "]"
1781 }
1782 return string(n.Literal.Data)
1783}
1784
1785// JS converts the node back to valid JavaScript
1786func (n PropertyName) JS() string {
1787 if n.Computed != nil {
1788 return "[" + n.Computed.JS() + "]"
1789 }
1790 return string(n.Literal.Data)
1791}
1792
1793// JS converts the node back to valid JavaScript (writes to io.Writer)
1794func (n PropertyName) JSWriteTo(w io.Writer) (i int, err error) {
1795 var wn int
1796 if n.Computed != nil {
1797 wn, err = w.Write([]byte("["))
1798 i += wn
1799 if err != nil {
1800 return
1801 }
1802 wn, err = n.Computed.JSWriteTo(w)
1803 i += wn
1804 if err != nil {
1805 return
1806 }
1807 wn, err = w.Write([]byte("]"))
1808 i += wn
1809 return
1810 }
1811 wn, err = w.Write(n.Literal.Data)
1812 i += wn
1813 return
1814}
1815
1816// BindingArray is an array binding pattern.
1817type BindingArray struct {
1818 List []BindingElement
1819 Rest IBinding // can be nil
1820}
1821
1822func (n BindingArray) String() string {
1823 s := "["
1824 for i, item := range n.List {
1825 if i != 0 {
1826 s += ","
1827 }
1828 s += " " + item.String()
1829 }
1830 if n.Rest != nil {
1831 if len(n.List) != 0 {
1832 s += ","
1833 }
1834 s += " ...Binding(" + n.Rest.String() + ")"
1835 }
1836 return s + " ]"
1837}
1838
1839// JS converts the node back to valid JavaScript
1840func (n BindingArray) JS() string {
1841 s := "["
1842 for i, item := range n.List {
1843 if i != 0 {
1844 s += ", "
1845 }
1846 s += item.JS()
1847 }
1848 if n.Rest != nil {
1849 if len(n.List) != 0 {
1850 s += ", "
1851 }
1852 s += "..." + n.Rest.JS()
1853 }
1854 return s + "]"
1855}
1856
1857// JS converts the node back to valid JavaScript (writes to io.Writer)
1858func (n BindingArray) JSWriteTo(w io.Writer) (i int, err error) {
1859 var wn int
1860 wn, err = w.Write([]byte("["))
1861 i += wn
1862 if err != nil {
1863 return
1864 }
1865 for j, item := range n.List {
1866 if j != 0 {
1867 wn, err = w.Write([]byte(", "))
1868 i += wn
1869 if err != nil {
1870 return
1871 }
1872 }
1873 wn, err = item.JSWriteTo(w)
1874 i += wn
1875 if err != nil {
1876 return
1877 }
1878 }
1879 if n.Rest != nil {
1880 if len(n.List) != 0 {
1881 wn, err = w.Write([]byte(", "))
1882 i += wn
1883 if err != nil {
1884 return
1885 }
1886 }
1887 wn, err = w.Write([]byte("..."))
1888 i += wn
1889 if err != nil {
1890 return
1891 }
1892 wn, err = n.Rest.JSWriteTo(w)
1893 i += wn
1894 if err != nil {
1895 return
1896 }
1897 }
1898 wn, err = w.Write([]byte("]"))
1899 i += wn
1900 return
1901}
1902
1903// BindingObjectItem is a binding property.
1904type BindingObjectItem struct {
1905 Key *PropertyName // can be nil
1906 Value BindingElement
1907}
1908
1909func (n BindingObjectItem) String() string {
1910 s := ""
1911 if n.Key != nil {
1912 if v, ok := n.Value.Binding.(*Var); !ok || !n.Key.IsIdent(v.Data) {
1913 s += " " + n.Key.String() + ":"
1914 }
1915 }
1916 return s + " " + n.Value.String()
1917}
1918
1919// JS converts the node back to valid JavaScript
1920func (n BindingObjectItem) JS() string {
1921 s := ""
1922 if n.Key != nil {
1923 if v, ok := n.Value.Binding.(*Var); !ok || !n.Key.IsIdent(v.Data) {
1924 s += n.Key.JS() + ": "
1925 }
1926 }
1927 return s + n.Value.JS()
1928}
1929
1930// JS converts the node back to valid JavaScript (writes to io.Writer)
1931func (n BindingObjectItem) JSWriteTo(w io.Writer) (i int, err error) {
1932 var wn int
1933 if n.Key != nil {
1934 if v, ok := n.Value.Binding.(*Var); !ok || !n.Key.IsIdent(v.Data) {
1935 wn, err = n.Key.JSWriteTo(w)
1936 i += wn
1937 if err != nil {
1938 return
1939 }
1940 wn, err = w.Write([]byte(": "))
1941 i += wn
1942 if err != nil {
1943 return
1944 }
1945 }
1946 }
1947 wn, err = n.Value.JSWriteTo(w)
1948 i += wn
1949 return
1950}
1951
1952// BindingObject is an object binding pattern.
1953type BindingObject struct {
1954 List []BindingObjectItem
1955 Rest *Var // can be nil
1956}
1957
1958func (n BindingObject) String() string {
1959 s := "{"
1960 for i, item := range n.List {
1961 if i != 0 {
1962 s += ","
1963 }
1964 s += item.String()
1965 }
1966 if n.Rest != nil {
1967 if len(n.List) != 0 {
1968 s += ","
1969 }
1970 s += " ...Binding(" + string(n.Rest.Data) + ")"
1971 }
1972 return s + " }"
1973}
1974
1975// JS converts the node back to valid JavaScript
1976func (n BindingObject) JS() string {
1977 s := "{"
1978 for i, item := range n.List {
1979 if i != 0 {
1980 s += ", "
1981 }
1982 s += item.JS()
1983 }
1984 if n.Rest != nil {
1985 if len(n.List) != 0 {
1986 s += ", "
1987 }
1988 s += "..." + string(n.Rest.Data)
1989 }
1990 return s + "}"
1991}
1992
1993// JS converts the node back to valid JavaScript (writes to io.Writer)
1994func (n BindingObject) JSWriteTo(w io.Writer) (i int, err error) {
1995 var wn int
1996 wn, err = w.Write([]byte("{"))
1997 i += wn
1998 if err != nil {
1999 return
2000 }
2001 for j, item := range n.List {
2002 if j != 0 {
2003 wn, err = w.Write([]byte(", "))
2004 i += wn
2005 if err != nil {
2006 return
2007 }
2008 }
2009 wn, err = item.JSWriteTo(w)
2010 i += wn
2011 if err != nil {
2012 return
2013 }
2014 }
2015 if n.Rest != nil {
2016 if len(n.List) != 0 {
2017 wn, err = w.Write([]byte(", "))
2018 i += wn
2019 if err != nil {
2020 return
2021 }
2022 }
2023 wn, err = w.Write([]byte("..."))
2024 i += wn
2025 if err != nil {
2026 return
2027 }
2028 wn, err = w.Write(n.Rest.Data)
2029 i += wn
2030 if err != nil {
2031 return
2032 }
2033 }
2034 wn, err = w.Write([]byte("}"))
2035 i += wn
2036 return
2037}
2038
2039// BindingElement is a binding element.
2040type BindingElement struct {
2041 Binding IBinding // can be nil (in case of ellision)
2042 Default IExpr // can be nil
2043}
2044
2045func (n BindingElement) String() string {
2046 if n.Binding == nil {
2047 return "Binding()"
2048 }
2049 s := "Binding(" + n.Binding.String()
2050 if n.Default != nil {
2051 s += " = " + n.Default.String()
2052 }
2053 return s + ")"
2054}
2055
2056// JS converts the node back to valid JavaScript
2057func (n BindingElement) JS() string {
2058 if n.Binding == nil {
2059 return ""
2060 }
2061 s := n.Binding.JS()
2062 if n.Default != nil {
2063 s += " = " + n.Default.JS()
2064 }
2065 return s
2066}
2067
2068// JS converts the node back to valid JavaScript (writes to io.Writer)
2069func (n BindingElement) JSWriteTo(w io.Writer) (i int, err error) {
2070 if n.Binding == nil {
2071 return
2072 }
2073 var wn int
2074 wn, err = n.Binding.JSWriteTo(w)
2075 i += wn
2076 if err != nil {
2077 return
2078 }
2079 if n.Default != nil {
2080 wn, err = w.Write([]byte(" = "))
2081 i += wn
2082 if err != nil {
2083 return
2084 }
2085 wn, err = n.Default.JSWriteTo(w)
2086 i += wn
2087 if err != nil {
2088 return
2089 }
2090 }
2091 return
2092}
2093
2094func (v *Var) bindingNode() {}
2095func (n BindingArray) bindingNode() {}
2096func (n BindingObject) bindingNode() {}
2097
2098////////////////////////////////////////////////////////////////
2099
2100// VarDecl is a variable statement or lexical declaration.
2101type VarDecl struct {
2102 TokenType
2103 List []BindingElement
2104 Scope *Scope
2105 InFor, InForInOf bool
2106}
2107
2108func (n VarDecl) String() string {
2109 s := "Decl(" + n.TokenType.String()
2110 for _, item := range n.List {
2111 s += " " + item.String()
2112 }
2113 return s + ")"
2114}
2115
2116// JS converts the node back to valid JavaScript
2117func (n VarDecl) JS() string {
2118 s := n.TokenType.String()
2119 for i, item := range n.List {
2120 if i != 0 {
2121 s += ","
2122 }
2123 s += " " + item.JS()
2124 }
2125 return s
2126}
2127
2128// JS converts the node back to valid JavaScript (writes to io.Writer)
2129func (n VarDecl) JSWriteTo(w io.Writer) (i int, err error) {
2130 var wn int
2131 wn, err = w.Write(n.TokenType.Bytes())
2132 i += wn
2133 if err != nil {
2134 return
2135 }
2136 for j, item := range n.List {
2137 if j != 0 {
2138 wn, err = w.Write([]byte(","))
2139 i += wn
2140 if err != nil {
2141 return
2142 }
2143 }
2144 wn, err = w.Write([]byte(" "))
2145 i += wn
2146 if err != nil {
2147 return
2148 }
2149 wn, err = item.JSWriteTo(w)
2150 i += wn
2151 if err != nil {
2152 return
2153 }
2154 }
2155 return
2156}
2157
2158// Params is a list of parameters for functions, methods, and arrow function.
2159type Params struct {
2160 List []BindingElement
2161 Rest IBinding // can be nil
2162}
2163
2164func (n Params) String() string {
2165 s := "Params("
2166 for i, item := range n.List {
2167 if i != 0 {
2168 s += ", "
2169 }
2170 s += item.String()
2171 }
2172 if n.Rest != nil {
2173 if len(n.List) != 0 {
2174 s += ", "
2175 }
2176 s += "...Binding(" + n.Rest.String() + ")"
2177 }
2178 return s + ")"
2179}
2180
2181// JS converts the node back to valid JavaScript
2182func (n Params) JS() string {
2183 s := "("
2184 for i, item := range n.List {
2185 if i != 0 {
2186 s += ", "
2187 }
2188 s += item.JS()
2189 }
2190 if n.Rest != nil {
2191 if len(n.List) != 0 {
2192 s += ", "
2193 }
2194 s += "..." + n.Rest.JS()
2195 }
2196 return s + ")"
2197}
2198
2199// JS converts the node back to valid JavaScript (writes to io.Writer)
2200func (n Params) JSWriteTo(w io.Writer) (i int, err error) {
2201 var wn int
2202 wn, err = w.Write([]byte("("))
2203 i += wn
2204 if err != nil {
2205 return
2206 }
2207 for j, item := range n.List {
2208 if j != 0 {
2209 wn, err = w.Write([]byte(", "))
2210 i += wn
2211 if err != nil {
2212 return
2213 }
2214 }
2215 wn, err = item.JSWriteTo(w)
2216 i += wn
2217 if err != nil {
2218 return
2219 }
2220 }
2221 if n.Rest != nil {
2222 if len(n.List) != 0 {
2223 wn, err = w.Write([]byte(", "))
2224 i += wn
2225 if err != nil {
2226 return
2227 }
2228 }
2229 wn, err = w.Write([]byte("..."))
2230 i += wn
2231 if err != nil {
2232 return
2233 }
2234 wn, err = n.Rest.JSWriteTo(w)
2235 i += wn
2236 if err != nil {
2237 return
2238 }
2239 }
2240 wn, err = w.Write([]byte(")"))
2241 i += wn
2242 return
2243}
2244
2245// FuncDecl is an (async) (generator) function declaration or expression.
2246type FuncDecl struct {
2247 Async bool
2248 Generator bool
2249 Name *Var // can be nil
2250 Params Params
2251 Body BlockStmt
2252}
2253
2254func (n FuncDecl) String() string {
2255 s := "Decl("
2256 if n.Async {
2257 s += "async function"
2258 } else {
2259 s += "function"
2260 }
2261 if n.Generator {
2262 s += "*"
2263 }
2264 if n.Name != nil {
2265 s += " " + string(n.Name.Data)
2266 }
2267 return s + " " + n.Params.String() + " " + n.Body.String() + ")"
2268}
2269
2270// JS converts the node back to valid JavaScript
2271func (n FuncDecl) JS() string {
2272 s := ""
2273 if n.Async {
2274 s += "async function"
2275 } else {
2276 s += "function"
2277 }
2278 if n.Generator {
2279 s += "*"
2280 }
2281 if n.Name != nil {
2282 s += " " + string(n.Name.Data)
2283 }
2284 return s + " " + n.Params.JS() + " " + n.Body.JS()
2285}
2286
2287// JS converts the node back to valid JavaScript (writes to io.Writer)
2288func (n FuncDecl) JSWriteTo(w io.Writer) (i int, err error) {
2289 var wn int
2290 if n.Async {
2291 wn, err = w.Write([]byte("async function"))
2292 } else {
2293 wn, err = w.Write([]byte("function"))
2294 }
2295 i += wn
2296 if err != nil {
2297 return
2298 }
2299
2300 if n.Generator {
2301 wn, err = w.Write([]byte("*"))
2302 i += wn
2303 if err != nil {
2304 return
2305 }
2306 }
2307 if n.Name != nil {
2308 wn, err = w.Write([]byte(" "))
2309 i += wn
2310 if err != nil {
2311 return
2312 }
2313 wn, err = w.Write(n.Name.Data)
2314 i += wn
2315 if err != nil {
2316 return
2317 }
2318 }
2319 wn, err = w.Write([]byte(" "))
2320 i += wn
2321 if err != nil {
2322 return
2323 }
2324 wn, err = n.Params.JSWriteTo(w)
2325 i += wn
2326 if err != nil {
2327 return
2328 }
2329 wn, err = w.Write([]byte(" "))
2330 i += wn
2331 if err != nil {
2332 return
2333 }
2334 wn, err = n.Body.JSWriteTo(w)
2335 i += wn
2336 return
2337}
2338
2339// MethodDecl is a method definition in a class declaration.
2340type MethodDecl struct {
2341 Static bool
2342 Async bool
2343 Generator bool
2344 Get bool
2345 Set bool
2346 Name PropertyName
2347 Params Params
2348 Body BlockStmt
2349}
2350
2351func (n MethodDecl) String() string {
2352 s := ""
2353 if n.Static {
2354 s += " static"
2355 }
2356 if n.Async {
2357 s += " async"
2358 }
2359 if n.Generator {
2360 s += " *"
2361 }
2362 if n.Get {
2363 s += " get"
2364 }
2365 if n.Set {
2366 s += " set"
2367 }
2368 s += " " + n.Name.String() + " " + n.Params.String() + " " + n.Body.String()
2369 return "Method(" + s[1:] + ")"
2370}
2371
2372// JS converts the node back to valid JavaScript
2373func (n MethodDecl) JS() string {
2374 s := ""
2375 if n.Static {
2376 s += " static"
2377 }
2378 if n.Async {
2379 s += " async"
2380 }
2381 if n.Generator {
2382 s += " *"
2383 }
2384 if n.Get {
2385 s += " get"
2386 }
2387 if n.Set {
2388 s += " set"
2389 }
2390 s += " " + n.Name.JS() + " " + n.Params.JS() + " " + n.Body.JS()
2391 return s[1:]
2392}
2393
2394// JS converts the node back to valid JavaScript (writes to io.Writer)
2395func (n MethodDecl) JSWriteTo(w io.Writer) (i int, err error) {
2396 var wn int
2397 if n.Static {
2398 wn, err = w.Write([]byte("static"))
2399 i += wn
2400 if err != nil {
2401 return
2402 }
2403 }
2404 if n.Async {
2405 if wn > 0 {
2406 wn, err = w.Write([]byte(" "))
2407 i += wn
2408 if err != nil {
2409 return
2410 }
2411 }
2412 wn, err = w.Write([]byte("async"))
2413 i += wn
2414 if err != nil {
2415 return
2416 }
2417 }
2418 if n.Generator {
2419 if wn > 0 {
2420 wn, err = w.Write([]byte(" "))
2421 i += wn
2422 if err != nil {
2423 return
2424 }
2425 }
2426 wn, err = w.Write([]byte("*"))
2427 i += wn
2428 if err != nil {
2429 return
2430 }
2431 }
2432 if n.Get {
2433 if wn > 0 {
2434 wn, err = w.Write([]byte(" "))
2435 i += wn
2436 if err != nil {
2437 return
2438 }
2439 }
2440 wn, err = w.Write([]byte("get"))
2441 i += wn
2442 if err != nil {
2443 return
2444 }
2445 }
2446 if n.Set {
2447 if wn > 0 {
2448 wn, err = w.Write([]byte(" "))
2449 i += wn
2450 if err != nil {
2451 return
2452 }
2453 }
2454 wn, err = w.Write([]byte("set"))
2455 i += wn
2456 if err != nil {
2457 return
2458 }
2459 }
2460 if wn > 0 {
2461 wn, err = w.Write([]byte(" "))
2462 i += wn
2463 if err != nil {
2464 return
2465 }
2466 }
2467 wn, err = n.Name.JSWriteTo(w)
2468 i += wn
2469 if err != nil {
2470 return
2471 }
2472 wn, err = w.Write([]byte(" "))
2473 i += wn
2474 if err != nil {
2475 return
2476 }
2477 wn, err = n.Params.JSWriteTo(w)
2478 i += wn
2479 if err != nil {
2480 return
2481 }
2482 wn, err = w.Write([]byte(" "))
2483 i += wn
2484 if err != nil {
2485 return
2486 }
2487 wn, err = n.Body.JSWriteTo(w)
2488 i += wn
2489 return
2490}
2491
2492// Field is a field definition in a class declaration.
2493type Field struct {
2494 Static bool
2495 Name PropertyName
2496 Init IExpr
2497}
2498
2499func (n Field) String() string {
2500 s := "Field("
2501 if n.Static {
2502 s += "static "
2503 }
2504 s += n.Name.String()
2505 if n.Init != nil {
2506 s += " = " + n.Init.String()
2507 }
2508 return s + ")"
2509}
2510
2511// JS converts the node back to valid JavaScript
2512func (n Field) JS() string {
2513 s := ""
2514 if n.Static {
2515 s += "static "
2516 }
2517 s += n.Name.String()
2518 if n.Init != nil {
2519 s += " = " + n.Init.JS()
2520 }
2521 return s
2522}
2523
2524// JS converts the node back to valid JavaScript (writes to io.Writer)
2525func (n Field) JSWriteTo(w io.Writer) (i int, err error) {
2526 var wn int
2527 if n.Static {
2528 wn, err = w.Write([]byte("static "))
2529 i += wn
2530 if err != nil {
2531 return
2532 }
2533 }
2534 wn, err = n.Name.JSWriteTo(w)
2535 i += wn
2536 if err != nil {
2537 return
2538 }
2539 if n.Init != nil {
2540 wn, err = w.Write([]byte(" = "))
2541 i += wn
2542 if err != nil {
2543 return
2544 }
2545 wn, err = n.Init.JSWriteTo(w)
2546 i += wn
2547 if err != nil {
2548 return
2549 }
2550 }
2551 return
2552}
2553
2554// ClassElement is a class element that is either a static block, a field definition, or a class method
2555type ClassElement struct {
2556 StaticBlock *BlockStmt // can be nil
2557 Method *MethodDecl // can be nil
2558 Field
2559}
2560
2561func (n ClassElement) String() string {
2562 if n.StaticBlock != nil {
2563 return "Static(" + n.StaticBlock.String() + ")"
2564 } else if n.Method != nil {
2565 return n.Method.String()
2566 }
2567 return n.Field.String()
2568}
2569
2570// JS converts the node back to valid JavaScript
2571func (n ClassElement) JS() string {
2572 if n.StaticBlock != nil {
2573 return "static " + n.StaticBlock.JS()
2574 } else if n.Method != nil {
2575 return n.Method.JS()
2576 }
2577 return n.Field.JS()
2578}
2579
2580// JS converts the node back to valid JavaScript (writes to io.Writer)
2581func (n ClassElement) JSWriteTo(w io.Writer) (i int, err error) {
2582 var wn int
2583 if n.StaticBlock != nil {
2584 wn, err = w.Write([]byte("static "))
2585 i += wn
2586 if err != nil {
2587 return
2588 }
2589 wn, err = n.StaticBlock.JSWriteTo(w)
2590 i += wn
2591 return
2592 } else if n.Method != nil {
2593 wn, err = n.Method.JSWriteTo(w)
2594 i += wn
2595 return
2596 }
2597 wn, err = n.Field.JSWriteTo(w)
2598 i += wn
2599 return
2600}
2601
2602// ClassDecl is a class declaration.
2603type ClassDecl struct {
2604 Name *Var // can be nil
2605 Extends IExpr // can be nil
2606 List []ClassElement
2607}
2608
2609func (n ClassDecl) String() string {
2610 s := "Decl(class"
2611 if n.Name != nil {
2612 s += " " + string(n.Name.Data)
2613 }
2614 if n.Extends != nil {
2615 s += " extends " + n.Extends.String()
2616 }
2617 for _, item := range n.List {
2618 s += " " + item.String()
2619 }
2620 return s + ")"
2621}
2622
2623// JS converts the node back to valid JavaScript
2624func (n ClassDecl) JS() string {
2625 s := "class"
2626 if n.Name != nil {
2627 s += " " + string(n.Name.Data)
2628 }
2629 if n.Extends != nil {
2630 s += " extends " + n.Extends.JS()
2631 }
2632 s += " { "
2633 for _, item := range n.List {
2634 s += item.JS() + "; "
2635 }
2636 return s + "}"
2637}
2638
2639// JS converts the node back to valid JavaScript (writes to io.Writer)
2640func (n ClassDecl) JSWriteTo(w io.Writer) (i int, err error) {
2641 var wn int
2642 wn, err = w.Write([]byte("class"))
2643 i += wn
2644 if err != nil {
2645 return
2646 }
2647 if n.Name != nil {
2648 wn, err = w.Write([]byte(" "))
2649 i += wn
2650 if err != nil {
2651 return
2652 }
2653 wn, err = w.Write(n.Name.Data)
2654 i += wn
2655 if err != nil {
2656 return
2657 }
2658 }
2659 if n.Extends != nil {
2660 wn, err = w.Write([]byte(" extends "))
2661 i += wn
2662 if err != nil {
2663 return
2664 }
2665 wn, err = n.Extends.JSWriteTo(w)
2666 i += wn
2667 if err != nil {
2668 return
2669 }
2670 }
2671 wn, err = w.Write([]byte(" { "))
2672 i += wn
2673 if err != nil {
2674 return
2675 }
2676 for _, item := range n.List {
2677 wn, err = item.JSWriteTo(w)
2678 i += wn
2679 if err != nil {
2680 return
2681 }
2682 wn, err = w.Write([]byte("; "))
2683 i += wn
2684 if err != nil {
2685 return
2686 }
2687 }
2688 wn, err = w.Write([]byte("}"))
2689 i += wn
2690 return
2691}
2692
2693func (n VarDecl) stmtNode() {}
2694func (n FuncDecl) stmtNode() {}
2695func (n ClassDecl) stmtNode() {}
2696
2697func (n VarDecl) exprNode() {} // not a real IExpr, used for ForInit and ExportDecl
2698func (n FuncDecl) exprNode() {}
2699func (n ClassDecl) exprNode() {}
2700func (n MethodDecl) exprNode() {} // not a real IExpr, used for ObjectExpression PropertyName
2701
2702////////////////////////////////////////////////////////////////
2703
2704// LiteralExpr can be this, null, boolean, numeric, string, or regular expression literals.
2705type LiteralExpr struct {
2706 TokenType
2707 Data []byte
2708}
2709
2710func (n LiteralExpr) String() string {
2711 return string(n.Data)
2712}
2713
2714// JS converts the node back to valid JavaScript
2715func (n LiteralExpr) JS() string {
2716 return string(n.Data)
2717}
2718
2719// JS converts the node back to valid JavaScript (writes to io.Writer)
2720func (n LiteralExpr) JSWriteTo(w io.Writer) (i int, err error) {
2721 var wn int
2722 wn, err = w.Write(n.Data)
2723 i += wn
2724 return
2725}
2726
2727// JSON converts the node back to valid JSON
2728func (n LiteralExpr) JSON(buf *bytes.Buffer) error {
2729 if n.TokenType == TrueToken || n.TokenType == FalseToken || n.TokenType == NullToken || n.TokenType == DecimalToken {
2730 buf.Write(n.Data)
2731 return nil
2732 } else if n.TokenType == StringToken {
2733 data := n.Data
2734 if n.Data[0] == '\'' {
2735 data = parse.Copy(data)
2736 data = bytes.ReplaceAll(data, []byte(`"`), []byte(`\"`))
2737 data[0] = '"'
2738 data[len(data)-1] = '"'
2739 }
2740 buf.Write(data)
2741 return nil
2742 }
2743 return ErrInvalidJSON
2744}
2745
2746// Element is an array literal element.
2747type Element struct {
2748 Value IExpr // can be nil
2749 Spread bool
2750}
2751
2752func (n Element) String() string {
2753 s := ""
2754 if n.Value != nil {
2755 if n.Spread {
2756 s += "..."
2757 }
2758 s += n.Value.String()
2759 }
2760 return s
2761}
2762
2763// JS converts the node back to valid JavaScript
2764func (n Element) JS() string {
2765 s := ""
2766 if n.Value != nil {
2767 if n.Spread {
2768 s += "..."
2769 }
2770 s += n.Value.JS()
2771 }
2772 return s
2773}
2774
2775// JS converts the node back to valid JavaScript (writes to io.Writer)
2776func (n Element) JSWriteTo(w io.Writer) (i int, err error) {
2777 var wn int
2778 if n.Value != nil {
2779 if n.Spread {
2780 wn, err = w.Write([]byte("..."))
2781 i += wn
2782 if err != nil {
2783 return
2784 }
2785 }
2786 wn, err = n.Value.JSWriteTo(w)
2787 i += wn
2788 }
2789 return
2790}
2791
2792// ArrayExpr is an array literal.
2793type ArrayExpr struct {
2794 List []Element
2795}
2796
2797func (n ArrayExpr) String() string {
2798 s := "["
2799 for i, item := range n.List {
2800 if i != 0 {
2801 s += ", "
2802 }
2803 if item.Value != nil {
2804 if item.Spread {
2805 s += "..."
2806 }
2807 s += item.Value.String()
2808 }
2809 }
2810 if 0 < len(n.List) && n.List[len(n.List)-1].Value == nil {
2811 s += ","
2812 }
2813 return s + "]"
2814}
2815
2816// JS converts the node back to valid JavaScript
2817func (n ArrayExpr) JS() string {
2818 s := "["
2819 for i, item := range n.List {
2820 if i != 0 {
2821 s += ", "
2822 }
2823 if item.Value != nil {
2824 if item.Spread {
2825 s += "..."
2826 }
2827 s += item.Value.JS()
2828 }
2829 }
2830 if 0 < len(n.List) && n.List[len(n.List)-1].Value == nil {
2831 s += ","
2832 }
2833 return s + "]"
2834}
2835
2836// JS converts the node back to valid JavaScript (writes to io.Writer)
2837func (n ArrayExpr) JSWriteTo(w io.Writer) (i int, err error) {
2838 var wn int
2839 wn, err = w.Write([]byte("["))
2840 i += wn
2841 if err != nil {
2842 return
2843 }
2844 for j, item := range n.List {
2845 if j != 0 {
2846 wn, err = w.Write([]byte(", "))
2847 i += wn
2848 if err != nil {
2849 return
2850 }
2851 }
2852 if item.Value != nil {
2853 if item.Spread {
2854 wn, err = w.Write([]byte("..."))
2855 i += wn
2856 if err != nil {
2857 return
2858 }
2859 }
2860 wn, err = item.Value.JSWriteTo(w)
2861 i += wn
2862 if err != nil {
2863 return
2864 }
2865 }
2866 }
2867 if 0 < len(n.List) && n.List[len(n.List)-1].Value == nil {
2868 wn, err = w.Write([]byte(","))
2869 i += wn
2870 if err != nil {
2871 return
2872 }
2873 }
2874 wn, err = w.Write([]byte("]"))
2875 i += wn
2876 return
2877}
2878
2879// JSON converts the node back to valid JSON
2880func (n ArrayExpr) JSON(buf *bytes.Buffer) error {
2881 buf.WriteByte('[')
2882 for i, item := range n.List {
2883 if i != 0 {
2884 buf.WriteString(", ")
2885 }
2886 if item.Value == nil || item.Spread {
2887 return ErrInvalidJSON
2888 }
2889 val, ok := item.Value.(JSONer)
2890 if !ok {
2891 return ErrInvalidJSON
2892 } else if err := val.JSON(buf); err != nil {
2893 return err
2894 }
2895 }
2896 buf.WriteByte(']')
2897 return nil
2898}
2899
2900// Property is a property definition in an object literal.
2901type Property struct {
2902 // either Name or Spread are set. When Spread is set then Value is AssignmentExpression
2903 // if Init is set then Value is IdentifierReference, otherwise it can also be MethodDefinition
2904 Name *PropertyName // can be nil
2905 Spread bool
2906 Value IExpr
2907 Init IExpr // can be nil
2908}
2909
2910func (n Property) String() string {
2911 s := ""
2912 if n.Name != nil {
2913 if v, ok := n.Value.(*Var); !ok || !n.Name.IsIdent(v.Data) {
2914 s += n.Name.String() + ": "
2915 }
2916 } else if n.Spread {
2917 s += "..."
2918 }
2919 s += n.Value.String()
2920 if n.Init != nil {
2921 s += " = " + n.Init.String()
2922 }
2923 return s
2924}
2925
2926// JS converts the node back to valid JavaScript
2927func (n Property) JS() string {
2928 s := ""
2929 if n.Name != nil {
2930 if v, ok := n.Value.(*Var); !ok || !n.Name.IsIdent(v.Data) {
2931 s += n.Name.JS() + ": "
2932 }
2933 } else if n.Spread {
2934 s += "..."
2935 }
2936 s += n.Value.JS()
2937 if n.Init != nil {
2938 s += " = " + n.Init.JS()
2939 }
2940 return s
2941}
2942
2943// JS converts the node back to valid JavaScript (writes to io.Writer)
2944func (n Property) JSWriteTo(w io.Writer) (i int, err error) {
2945 var wn int
2946 if n.Name != nil {
2947 if v, ok := n.Value.(*Var); !ok || !n.Name.IsIdent(v.Data) {
2948 wn, err = n.Name.JSWriteTo(w)
2949 i += wn
2950 if err != nil {
2951 return
2952 }
2953 wn, err = w.Write([]byte(": "))
2954 i += wn
2955 if err != nil {
2956 return
2957 }
2958 }
2959 } else if n.Spread {
2960 wn, err = w.Write([]byte("..."))
2961 i += wn
2962 if err != nil {
2963 return
2964 }
2965 }
2966 wn, err = n.Value.JSWriteTo(w)
2967 i += wn
2968 if err != nil {
2969 return
2970 }
2971 if n.Init != nil {
2972 wn, err = w.Write([]byte(" = "))
2973 i += wn
2974 if err != nil {
2975 return
2976 }
2977 wn, err = n.Init.JSWriteTo(w)
2978 i += wn
2979 if err != nil {
2980 return
2981 }
2982 }
2983 return
2984}
2985
2986// JSON converts the node back to valid JSON
2987func (n Property) JSON(buf *bytes.Buffer) error {
2988 if n.Name == nil || n.Name.Literal.TokenType != StringToken && n.Name.Literal.TokenType != IdentifierToken || n.Spread || n.Init != nil {
2989 return ErrInvalidJSON
2990 } else if n.Name.Literal.TokenType == IdentifierToken {
2991 buf.WriteByte('"')
2992 buf.Write(n.Name.Literal.Data)
2993 buf.WriteByte('"')
2994 } else {
2995 _ = n.Name.Literal.JSON(buf)
2996 }
2997 buf.WriteString(": ")
2998
2999 val, ok := n.Value.(JSONer)
3000 if !ok {
3001 return ErrInvalidJSON
3002 } else if err := val.JSON(buf); err != nil {
3003 return err
3004 }
3005 return nil
3006}
3007
3008// ObjectExpr is an object literal.
3009type ObjectExpr struct {
3010 List []Property
3011}
3012
3013func (n ObjectExpr) String() string {
3014 s := "{"
3015 for i, item := range n.List {
3016 if i != 0 {
3017 s += ", "
3018 }
3019 s += item.String()
3020 }
3021 return s + "}"
3022}
3023
3024// JS converts the node back to valid JavaScript
3025func (n ObjectExpr) JS() string {
3026 s := "{"
3027 for i, item := range n.List {
3028 if i != 0 {
3029 s += ", "
3030 }
3031 s += item.JS()
3032 }
3033 return s + "}"
3034}
3035
3036// JS converts the node back to valid JavaScript (writes to io.Writer)
3037func (n ObjectExpr) JSWriteTo(w io.Writer) (i int, err error) {
3038 var wn int
3039 wn, err = w.Write([]byte("{"))
3040 i += wn
3041 if err != nil {
3042 return
3043 }
3044 for j, item := range n.List {
3045 if j != 0 {
3046 wn, err = w.Write([]byte(", "))
3047 i += wn
3048 if err != nil {
3049 return
3050 }
3051 }
3052 wn, err = item.JSWriteTo(w)
3053 i += wn
3054 if err != nil {
3055 return
3056 }
3057 }
3058 wn, err = w.Write([]byte("}"))
3059 i += wn
3060 return
3061}
3062
3063// JSON converts the node back to valid JSON
3064func (n ObjectExpr) JSON(buf *bytes.Buffer) error {
3065 buf.WriteByte('{')
3066 for i, item := range n.List {
3067 if i != 0 {
3068 buf.WriteString(", ")
3069 }
3070 if err := item.JSON(buf); err != nil {
3071 return err
3072 }
3073 }
3074 buf.WriteByte('}')
3075 return nil
3076}
3077
3078// TemplatePart is a template head or middle.
3079type TemplatePart struct {
3080 Value []byte
3081 Expr IExpr
3082}
3083
3084func (n TemplatePart) String() string {
3085 return string(n.Value) + n.Expr.String()
3086}
3087
3088// JS converts the node back to valid JavaScript
3089func (n TemplatePart) JS() string {
3090 return string(n.Value) + n.Expr.JS()
3091}
3092
3093// JS converts the node back to valid JavaScript (writes to io.Writer)
3094func (n TemplatePart) JSWriteTo(w io.Writer) (i int, err error) {
3095 var wn int
3096 wn, err = w.Write(n.Value)
3097 i += wn
3098 if err != nil {
3099 return
3100 }
3101 wn, err = n.Expr.JSWriteTo(w)
3102 i += wn
3103 return
3104}
3105
3106// TemplateExpr is a template literal or member/call expression, super property, or optional chain with template literal.
3107type TemplateExpr struct {
3108 Tag IExpr // can be nil
3109 List []TemplatePart
3110 Tail []byte
3111 Prec OpPrec
3112 Optional bool
3113}
3114
3115func (n TemplateExpr) String() string {
3116 s := ""
3117 if n.Tag != nil {
3118 s += n.Tag.String()
3119 if n.Optional {
3120 s += "?."
3121 }
3122 }
3123 for _, item := range n.List {
3124 s += item.String()
3125 }
3126 return s + string(n.Tail)
3127}
3128
3129// JS converts the node back to valid JavaScript
3130func (n TemplateExpr) JS() string {
3131 s := ""
3132 if n.Tag != nil {
3133 s += n.Tag.JS()
3134 if n.Optional {
3135 s += "?."
3136 }
3137 }
3138 for _, item := range n.List {
3139 s += item.JS()
3140 }
3141 return s + string(n.Tail)
3142}
3143
3144// JS converts the node back to valid JavaScript (writes to io.Writer)
3145func (n TemplateExpr) JSWriteTo(w io.Writer) (i int, err error) {
3146 var wn int
3147 if n.Tag != nil {
3148 wn, err = n.Tag.JSWriteTo(w)
3149 i += wn
3150 if err != nil {
3151 return
3152 }
3153 if n.Optional {
3154 wn, err = w.Write([]byte("?."))
3155 i += wn
3156 if err != nil {
3157 return
3158 }
3159 }
3160 }
3161 for _, item := range n.List {
3162 wn, err = item.JSWriteTo(w)
3163 i += wn
3164 if err != nil {
3165 return
3166 }
3167 }
3168 wn, err = w.Write(n.Tail)
3169 i += wn
3170 return
3171}
3172
3173// GroupExpr is a parenthesized expression.
3174type GroupExpr struct {
3175 X IExpr
3176}
3177
3178func (n GroupExpr) String() string {
3179 return "(" + n.X.String() + ")"
3180}
3181
3182// JS converts the node back to valid JavaScript
3183func (n GroupExpr) JS() string {
3184 return "(" + n.X.JS() + ")"
3185}
3186
3187// JS converts the node back to valid JavaScript (writes to io.Writer)
3188func (n GroupExpr) JSWriteTo(w io.Writer) (i int, err error) {
3189 var wn int
3190 wn, err = w.Write([]byte("("))
3191 i += wn
3192 if err != nil {
3193 return
3194 }
3195 wn, err = n.X.JSWriteTo(w)
3196 i += wn
3197 if err != nil {
3198 return
3199 }
3200 wn, err = w.Write([]byte(")"))
3201 i += wn
3202 return
3203}
3204
3205// IndexExpr is a member/call expression, super property, or optional chain with an index expression.
3206type IndexExpr struct {
3207 X IExpr
3208 Y IExpr
3209 Prec OpPrec
3210 Optional bool
3211}
3212
3213func (n IndexExpr) String() string {
3214 if n.Optional {
3215 return "(" + n.X.String() + "?.[" + n.Y.String() + "])"
3216 }
3217 return "(" + n.X.String() + "[" + n.Y.String() + "])"
3218}
3219
3220// JS converts the node back to valid JavaScript
3221func (n IndexExpr) JS() string {
3222 if n.Optional {
3223 return n.X.JS() + "?.[" + n.Y.JS() + "]"
3224 }
3225 return n.X.JS() + "[" + n.Y.JS() + "]"
3226}
3227
3228// JS converts the node back to valid JavaScript (writes to io.Writer)
3229func (n IndexExpr) JSWriteTo(w io.Writer) (i int, err error) {
3230 var wn int
3231 wn, err = n.X.JSWriteTo(w)
3232 i += wn
3233 if err != nil {
3234 return
3235 }
3236 if n.Optional {
3237 wn, err = w.Write([]byte("?.["))
3238 i += wn
3239 if err != nil {
3240 return
3241 }
3242 } else {
3243 wn, err = w.Write([]byte("["))
3244 i += wn
3245 if err != nil {
3246 return
3247 }
3248 }
3249 wn, err = n.Y.JSWriteTo(w)
3250 i += wn
3251 if err != nil {
3252 return
3253 }
3254 wn, err = w.Write([]byte("]"))
3255 i += wn
3256 return
3257}
3258
3259// DotExpr is a member/call expression, super property, or optional chain with a dot expression.
3260type DotExpr struct {
3261 X IExpr
3262 Y LiteralExpr
3263 Prec OpPrec
3264 Optional bool
3265}
3266
3267func (n DotExpr) String() string {
3268 if n.Optional {
3269 return "(" + n.X.String() + "?." + n.Y.String() + ")"
3270 }
3271 return "(" + n.X.String() + "." + n.Y.String() + ")"
3272}
3273
3274// JS converts the node back to valid JavaScript
3275func (n DotExpr) JS() string {
3276 if n.Optional {
3277 return n.X.JS() + "?." + n.Y.JS()
3278 }
3279 return n.X.JS() + "." + n.Y.JS()
3280}
3281
3282// JS converts the node back to valid JavaScript (writes to io.Writer)
3283func (n DotExpr) JSWriteTo(w io.Writer) (i int, err error) {
3284 var wn int
3285 wn, err = n.X.JSWriteTo(w)
3286 i += wn
3287 if err != nil {
3288 return
3289 }
3290 if n.Optional {
3291 wn, err = w.Write([]byte("?."))
3292 i += wn
3293 if err != nil {
3294 return
3295 }
3296 } else {
3297 wn, err = w.Write([]byte("."))
3298 i += wn
3299 if err != nil {
3300 return
3301 }
3302 }
3303 wn, err = n.Y.JSWriteTo(w)
3304 i += wn
3305 return
3306}
3307
3308// NewTargetExpr is a new target meta property.
3309type NewTargetExpr struct {
3310}
3311
3312func (n NewTargetExpr) String() string {
3313 return "(new.target)"
3314}
3315
3316// JS converts the node back to valid JavaScript
3317func (n NewTargetExpr) JS() string {
3318 return "new.target"
3319}
3320
3321// JS converts the node back to valid JavaScript (writes to io.Writer)
3322func (n NewTargetExpr) JSWriteTo(w io.Writer) (i int, err error) {
3323 var wn int
3324 wn, err = w.Write([]byte("new.target"))
3325 i += wn
3326 return
3327}
3328
3329// ImportMetaExpr is a import meta meta property.
3330type ImportMetaExpr struct {
3331}
3332
3333func (n ImportMetaExpr) String() string {
3334 return "(import.meta)"
3335}
3336
3337// JS converts the node back to valid JavaScript
3338func (n ImportMetaExpr) JS() string {
3339 return "import.meta"
3340}
3341
3342// JS converts the node back to valid JavaScript (writes to io.Writer)
3343func (n ImportMetaExpr) JSWriteTo(w io.Writer) (i int, err error) {
3344 var wn int
3345 wn, err = w.Write([]byte("import.meta"))
3346 i += wn
3347 return
3348}
3349
3350type Arg struct {
3351 Value IExpr
3352 Rest bool
3353}
3354
3355func (n Arg) String() string {
3356 s := ""
3357 if n.Rest {
3358 s += "..."
3359 }
3360 return s + n.Value.String()
3361}
3362
3363// JS converts the node back to valid JavaScript
3364func (n Arg) JS() string {
3365 s := ""
3366 if n.Rest {
3367 s += "..."
3368 }
3369 return s + n.Value.JS()
3370}
3371
3372// JS converts the node back to valid JavaScript (writes to io.Writer)
3373func (n Arg) JSWriteTo(w io.Writer) (i int, err error) {
3374 var wn int
3375 if n.Rest {
3376 wn, err = w.Write([]byte("..."))
3377 i += wn
3378 if err != nil {
3379 return
3380 }
3381 }
3382 wn, err = n.Value.JSWriteTo(w)
3383 i += wn
3384 return
3385}
3386
3387// Args is a list of arguments as used by new and call expressions.
3388type Args struct {
3389 List []Arg
3390}
3391
3392func (n Args) String() string {
3393 s := "("
3394 for i, item := range n.List {
3395 if i != 0 {
3396 s += ", "
3397 }
3398 s += item.String()
3399 }
3400 return s + ")"
3401}
3402
3403// JS converts the node back to valid JavaScript
3404func (n Args) JS() string {
3405 s := ""
3406 for i, item := range n.List {
3407 if i != 0 {
3408 s += ", "
3409 }
3410 s += item.JS()
3411 }
3412 return s
3413}
3414
3415// JS converts the node back to valid JavaScript (writes to io.Writer)
3416func (n Args) JSWriteTo(w io.Writer) (i int, err error) {
3417 var wn int
3418 for j, item := range n.List {
3419 if j != 0 {
3420 wn, err = w.Write([]byte(", "))
3421 i += wn
3422 if err != nil {
3423 return
3424 }
3425 }
3426 wn, err = item.JSWriteTo(w)
3427 i += wn
3428 if err != nil {
3429 return
3430 }
3431 }
3432 return
3433}
3434
3435// NewExpr is a new expression or new member expression.
3436type NewExpr struct {
3437 X IExpr
3438 Args *Args // can be nil
3439}
3440
3441func (n NewExpr) String() string {
3442 if n.Args != nil {
3443 return "(new " + n.X.String() + n.Args.String() + ")"
3444 }
3445 return "(new " + n.X.String() + ")"
3446}
3447
3448// JS converts the node back to valid JavaScript
3449func (n NewExpr) JS() string {
3450 if n.Args != nil {
3451 return "new " + n.X.JS() + "(" + n.Args.JS() + ")"
3452 }
3453
3454 // always use parentheses to prevent errors when chaining e.g. new Date().getTime()
3455 return "new " + n.X.JS() + "()"
3456}
3457
3458// JS converts the node back to valid JavaScript (writes to io.Writer)
3459func (n NewExpr) JSWriteTo(w io.Writer) (i int, err error) {
3460 var wn int
3461 wn, err = w.Write([]byte("new "))
3462 i += wn
3463 if err != nil {
3464 return
3465 }
3466 wn, err = n.X.JSWriteTo(w)
3467 i += wn
3468 if err != nil {
3469 return
3470 }
3471 if n.Args != nil {
3472 wn, err = w.Write([]byte("("))
3473 i += wn
3474 if err != nil {
3475 return
3476 }
3477 wn, err = n.Args.JSWriteTo(w)
3478 i += wn
3479 if err != nil {
3480 return
3481 }
3482 wn, err = w.Write([]byte(")"))
3483 i += wn
3484 if err != nil {
3485 return
3486 }
3487 } else {
3488 wn, err = w.Write([]byte("()"))
3489 i += wn
3490 if err != nil {
3491 return
3492 }
3493 }
3494 return
3495}
3496
3497// CallExpr is a call expression.
3498type CallExpr struct {
3499 X IExpr
3500 Args Args
3501 Optional bool
3502}
3503
3504func (n CallExpr) String() string {
3505 if n.Optional {
3506 return "(" + n.X.String() + "?." + n.Args.String() + ")"
3507 }
3508 return "(" + n.X.String() + n.Args.String() + ")"
3509}
3510
3511// JS converts the node back to valid JavaScript
3512func (n CallExpr) JS() string {
3513 if n.Optional {
3514 return n.X.JS() + "?.(" + n.Args.JS() + ")"
3515 }
3516 return n.X.JS() + "(" + n.Args.JS() + ")"
3517}
3518
3519// JS converts the node back to valid JavaScript (writes to io.Writer)
3520func (n CallExpr) JSWriteTo(w io.Writer) (i int, err error) {
3521 var wn int
3522 wn, err = n.X.JSWriteTo(w)
3523 i += wn
3524 if err != nil {
3525 return
3526 }
3527 if n.Optional {
3528 wn, err = w.Write([]byte("?.("))
3529 i += wn
3530 if err != nil {
3531 return
3532 }
3533 } else {
3534 wn, err = w.Write([]byte("("))
3535 i += wn
3536 if err != nil {
3537 return
3538 }
3539 }
3540 wn, err = n.Args.JSWriteTo(w)
3541 i += wn
3542 if err != nil {
3543 return
3544 }
3545 wn, err = w.Write([]byte(")"))
3546 i += wn
3547 if err != nil {
3548 return
3549 }
3550 return
3551}
3552
3553// UnaryExpr is an update or unary expression.
3554type UnaryExpr struct {
3555 Op TokenType
3556 X IExpr
3557}
3558
3559func (n UnaryExpr) String() string {
3560 if n.Op == PostIncrToken || n.Op == PostDecrToken {
3561 return "(" + n.X.String() + n.Op.String() + ")"
3562 } else if IsIdentifierName(n.Op) {
3563 return "(" + n.Op.String() + " " + n.X.String() + ")"
3564 }
3565 return "(" + n.Op.String() + n.X.String() + ")"
3566}
3567
3568// JS converts the node back to valid JavaScript
3569func (n UnaryExpr) JS() string {
3570 if n.Op == PostIncrToken || n.Op == PostDecrToken {
3571 return n.X.JS() + n.Op.String()
3572 } else if IsIdentifierName(n.Op) {
3573 return n.Op.String() + " " + n.X.JS()
3574 }
3575 return n.Op.String() + n.X.JS()
3576}
3577
3578// JS converts the node back to valid JavaScript (writes to io.Writer)
3579func (n UnaryExpr) JSWriteTo(w io.Writer) (i int, err error) {
3580 var wn int
3581 if n.Op == PostIncrToken || n.Op == PostDecrToken {
3582 wn, err = n.X.JSWriteTo(w)
3583 i += wn
3584 if err != nil {
3585 return
3586 }
3587 wn, err = w.Write(n.Op.Bytes())
3588 i += wn
3589 return
3590 } else if IsIdentifierName(n.Op) {
3591 wn, err = w.Write(n.Op.Bytes())
3592 i += wn
3593 if err != nil {
3594 return
3595 }
3596 wn, err = w.Write([]byte(" "))
3597 i += wn
3598 if err != nil {
3599 return
3600 }
3601 wn, err = n.X.JSWriteTo(w)
3602 i += wn
3603 return
3604 }
3605 wn, err = w.Write(n.Op.Bytes())
3606 i += wn
3607 if err != nil {
3608 return
3609 }
3610 wn, err = n.X.JSWriteTo(w)
3611 i += wn
3612 return
3613}
3614
3615// JSON converts the node back to valid JSON
3616func (n UnaryExpr) JSON(buf *bytes.Buffer) error {
3617 if lit, ok := n.X.(*LiteralExpr); ok && n.Op == NegToken && lit.TokenType == DecimalToken {
3618 buf.WriteByte('-')
3619 buf.Write(lit.Data)
3620 return nil
3621 }
3622 return ErrInvalidJSON
3623}
3624
3625// BinaryExpr is a binary expression.
3626type BinaryExpr struct {
3627 Op TokenType
3628 X, Y IExpr
3629}
3630
3631func (n BinaryExpr) String() string {
3632 if IsIdentifierName(n.Op) {
3633 return "(" + n.X.String() + " " + n.Op.String() + " " + n.Y.String() + ")"
3634 }
3635 return "(" + n.X.String() + n.Op.String() + n.Y.String() + ")"
3636}
3637
3638// JS converts the node back to valid JavaScript
3639func (n BinaryExpr) JS() string {
3640 return n.X.JS() + " " + n.Op.String() + " " + n.Y.JS()
3641}
3642
3643// JS converts the node back to valid JavaScript (writes to io.Writer)
3644func (n BinaryExpr) JSWriteTo(w io.Writer) (i int, err error) {
3645 var wn int
3646 wn, err = n.X.JSWriteTo(w)
3647 i += wn
3648 if err != nil {
3649 return
3650 }
3651 wn, err = w.Write([]byte(" "))
3652 i += wn
3653 if err != nil {
3654 return
3655 }
3656 wn, err = w.Write(n.Op.Bytes())
3657 i += wn
3658 if err != nil {
3659 return
3660 }
3661 wn, err = w.Write([]byte(" "))
3662 i += wn
3663 if err != nil {
3664 return
3665 }
3666 wn, err = n.Y.JSWriteTo(w)
3667 i += wn
3668 return
3669}
3670
3671// CondExpr is a conditional expression.
3672type CondExpr struct {
3673 Cond, X, Y IExpr
3674}
3675
3676func (n CondExpr) String() string {
3677 return "(" + n.Cond.String() + " ? " + n.X.String() + " : " + n.Y.String() + ")"
3678}
3679
3680// JS converts the node back to valid JavaScript
3681func (n CondExpr) JS() string {
3682 return n.Cond.JS() + " ? " + n.X.JS() + " : " + n.Y.JS()
3683}
3684
3685// JS converts the node back to valid JavaScript (writes to io.Writer)
3686func (n CondExpr) JSWriteTo(w io.Writer) (i int, err error) {
3687 var wn int
3688 wn, err = n.Cond.JSWriteTo(w)
3689 i += wn
3690 if err != nil {
3691 return
3692 }
3693 wn, err = w.Write([]byte(" ? "))
3694 i += wn
3695 if err != nil {
3696 return
3697 }
3698 wn, err = n.X.JSWriteTo(w)
3699 i += wn
3700 if err != nil {
3701 return
3702 }
3703 wn, err = w.Write([]byte(" : "))
3704 i += wn
3705 if err != nil {
3706 return
3707 }
3708 wn, err = n.Y.JSWriteTo(w)
3709 i += wn
3710 return
3711}
3712
3713// YieldExpr is a yield expression.
3714type YieldExpr struct {
3715 Generator bool
3716 X IExpr // can be nil
3717}
3718
3719func (n YieldExpr) String() string {
3720 if n.X == nil {
3721 return "(yield)"
3722 }
3723 s := "(yield"
3724 if n.Generator {
3725 s += "*"
3726 }
3727 return s + " " + n.X.String() + ")"
3728}
3729
3730// JS converts the node back to valid JavaScript
3731func (n YieldExpr) JS() string {
3732 if n.X == nil {
3733 return "yield"
3734 }
3735 s := "yield"
3736 if n.Generator {
3737 s += "*"
3738 }
3739 return s + " " + n.X.JS()
3740}
3741
3742// JS converts the node back to valid JavaScript (writes to io.Writer)
3743func (n YieldExpr) JSWriteTo(w io.Writer) (i int, err error) {
3744 var wn int
3745 wn, err = w.Write([]byte("yield"))
3746 i += wn
3747 if err != nil {
3748 return
3749 }
3750 if n.X == nil {
3751 return
3752 }
3753 if n.Generator {
3754 wn, err = w.Write([]byte("*"))
3755 i += wn
3756 if err != nil {
3757 return
3758 }
3759 }
3760 wn, err = w.Write([]byte(" "))
3761 i += wn
3762 if err != nil {
3763 return
3764 }
3765 wn, err = n.X.JSWriteTo(w)
3766 i += wn
3767 return
3768}
3769
3770// ArrowFunc is an (async) arrow function.
3771type ArrowFunc struct {
3772 Async bool
3773 Params Params
3774 Body BlockStmt
3775}
3776
3777func (n ArrowFunc) String() string {
3778 s := "("
3779 if n.Async {
3780 s += "async "
3781 }
3782 return s + n.Params.String() + " => " + n.Body.String() + ")"
3783}
3784
3785// JS converts the node back to valid JavaScript
3786func (n ArrowFunc) JS() string {
3787 s := ""
3788 if n.Async {
3789 s += "async "
3790 }
3791 return s + n.Params.JS() + " => " + n.Body.JS()
3792}
3793
3794// JS converts the node back to valid JavaScript (writes to io.Writer)
3795func (n ArrowFunc) JSWriteTo(w io.Writer) (i int, err error) {
3796 var wn int
3797 if n.Async {
3798 wn, err = w.Write([]byte("async "))
3799 i += wn
3800 if err != nil {
3801 return
3802 }
3803 }
3804 wn, err = n.Params.JSWriteTo(w)
3805 i += wn
3806 if err != nil {
3807 return
3808 }
3809 wn, err = w.Write([]byte(" => "))
3810 i += wn
3811 if err != nil {
3812 return
3813 }
3814 wn, err = n.Body.JSWriteTo(w)
3815 i += wn
3816 return
3817}
3818
3819// CommaExpr is a series of comma expressions.
3820type CommaExpr struct {
3821 List []IExpr
3822}
3823
3824func (n CommaExpr) String() string {
3825 s := "("
3826 for i, item := range n.List {
3827 if i != 0 {
3828 s += ","
3829 }
3830 s += item.String()
3831 }
3832 return s + ")"
3833}
3834
3835// JS converts the node back to valid JavaScript
3836func (n CommaExpr) JS() string {
3837 s := ""
3838 for i, item := range n.List {
3839 if i != 0 {
3840 s += ","
3841 }
3842 s += item.JS()
3843 }
3844 return s
3845}
3846
3847// JS converts the node back to valid JavaScript (writes to io.Writer)
3848func (n CommaExpr) JSWriteTo(w io.Writer) (i int, err error) {
3849 var wn int
3850 for j, item := range n.List {
3851 if j != 0 {
3852 wn, err = w.Write([]byte(","))
3853 i += wn
3854 if err != nil {
3855 return
3856 }
3857 }
3858 wn, err = item.JSWriteTo(w)
3859 i += wn
3860 if err != nil {
3861 return
3862 }
3863 }
3864 return
3865}
3866
3867func (v *Var) exprNode() {}
3868func (n LiteralExpr) exprNode() {}
3869func (n ArrayExpr) exprNode() {}
3870func (n ObjectExpr) exprNode() {}
3871func (n TemplateExpr) exprNode() {}
3872func (n GroupExpr) exprNode() {}
3873func (n DotExpr) exprNode() {}
3874func (n IndexExpr) exprNode() {}
3875func (n NewTargetExpr) exprNode() {}
3876func (n ImportMetaExpr) exprNode() {}
3877func (n NewExpr) exprNode() {}
3878func (n CallExpr) exprNode() {}
3879func (n UnaryExpr) exprNode() {}
3880func (n BinaryExpr) exprNode() {}
3881func (n CondExpr) exprNode() {}
3882func (n YieldExpr) exprNode() {}
3883func (n ArrowFunc) exprNode() {}
3884func (n CommaExpr) exprNode() {}