summaryrefslogtreecommitdiff
path: root/vendor/github.com/tdewolff/parse/v2/js/ast.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/tdewolff/parse/v2/js/ast.go')
-rw-r--r--vendor/github.com/tdewolff/parse/v2/js/ast.go3884
1 files changed, 3884 insertions, 0 deletions
diff --git a/vendor/github.com/tdewolff/parse/v2/js/ast.go b/vendor/github.com/tdewolff/parse/v2/js/ast.go
new file mode 100644
index 0000000..92e80d7
--- /dev/null
+++ b/vendor/github.com/tdewolff/parse/v2/js/ast.go
@@ -0,0 +1,3884 @@
+package js
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "strconv"
+
+ "github.com/tdewolff/parse/v2"
+)
+
+var ErrInvalidJSON = fmt.Errorf("invalid JSON")
+
+type JSONer interface {
+ JSON(*bytes.Buffer) error
+}
+
+// AST is the full ECMAScript abstract syntax tree.
+type AST struct {
+ Comments [][]byte // first comments in file
+ BlockStmt // module
+}
+
+func (ast *AST) String() string {
+ s := ""
+ for i, item := range ast.BlockStmt.List {
+ if i != 0 {
+ s += " "
+ }
+ s += item.String()
+ }
+ return s
+}
+
+////////////////////////////////////////////////////////////////
+
+// DeclType specifies the kind of declaration.
+type DeclType uint16
+
+// DeclType values.
+const (
+ NoDecl DeclType = iota // undeclared variables
+ VariableDecl // var
+ FunctionDecl // function
+ ArgumentDecl // function and method arguments
+ LexicalDecl // let, const, class
+ CatchDecl // catch statement argument
+ ExprDecl // function expression name or class expression name
+)
+
+func (decl DeclType) String() string {
+ switch decl {
+ case NoDecl:
+ return "NoDecl"
+ case VariableDecl:
+ return "VariableDecl"
+ case FunctionDecl:
+ return "FunctionDecl"
+ case ArgumentDecl:
+ return "ArgumentDecl"
+ case LexicalDecl:
+ return "LexicalDecl"
+ case CatchDecl:
+ return "CatchDecl"
+ case ExprDecl:
+ return "ExprDecl"
+ }
+ return "Invalid(" + strconv.Itoa(int(decl)) + ")"
+}
+
+// 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.
+type Var struct {
+ Data []byte
+ 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
+ Uses uint16
+ Decl DeclType
+}
+
+// Name returns the variable name.
+func (v *Var) Name() []byte {
+ for v.Link != nil {
+ v = v.Link
+ }
+ return v.Data
+}
+
+func (v Var) String() string {
+ return string(v.Name())
+}
+
+// JS converts the node back to valid JavaScript
+func (v Var) JS() string {
+ return v.String()
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (v Var) JSWriteTo(w io.Writer) (i int, err error) {
+ return w.Write(v.Name())
+}
+
+// VarsByUses is sortable by uses in descending order.
+// TODO: write custom sorter for varsbyuses
+type VarsByUses VarArray
+
+func (vs VarsByUses) Len() int {
+ return len(vs)
+}
+
+func (vs VarsByUses) Swap(i, j int) {
+ vs[i], vs[j] = vs[j], vs[i]
+}
+
+func (vs VarsByUses) Less(i, j int) bool {
+ return vs[i].Uses > vs[j].Uses
+}
+
+////////////////////////////////////////////////////////////////
+
+// VarArray is a set of variables in scopes.
+type VarArray []*Var
+
+func (vs VarArray) String() string {
+ s := "["
+ for i, v := range vs {
+ if i != 0 {
+ s += ", "
+ }
+ links := 0
+ for v.Link != nil {
+ v = v.Link
+ links++
+ }
+ s += fmt.Sprintf("Var{%v %s %v %v}", v.Decl, string(v.Data), links, v.Uses)
+ }
+ return s + "]"
+}
+
+// Scope is a function or block scope with a list of variables declared and used.
+type Scope struct {
+ Parent, Func *Scope // Parent is nil for global scope
+ Declared VarArray // Link in Var are always nil
+ Undeclared VarArray
+ VarDecls []*VarDecl
+ NumForDecls uint16 // offset into Declared to mark variables used in for statements
+ NumFuncArgs uint16 // offset into Declared to mark variables used in function arguments
+ NumArgUses uint16 // offset into Undeclared to mark variables used in arguments
+ IsGlobalOrFunc bool
+ HasWith bool
+}
+
+func (s Scope) String() string {
+ return "Scope{Declared: " + s.Declared.String() + ", Undeclared: " + s.Undeclared.String() + "}"
+}
+
+// Declare declares a new variable.
+func (s *Scope) Declare(decl DeclType, name []byte) (*Var, bool) {
+ // refer to new variable for previously undeclared symbols in the current and lower scopes
+ // this happens in `{ a = 5; } var a` where both a's refer to the same variable
+ curScope := s
+ if decl == VariableDecl || decl == FunctionDecl {
+ // find function scope for var and function declarations
+ for s != s.Func {
+ // make sure that `{let i;{var i}}` is an error
+ if v := s.findDeclared(name, false); v != nil && v.Decl != decl && v.Decl != CatchDecl {
+ return nil, false
+ }
+ s = s.Parent
+ }
+ }
+
+ if v := s.findDeclared(name, true); v != nil {
+ // variable already declared, might be an error or a duplicate declaration
+ if (ArgumentDecl < v.Decl || FunctionDecl < decl) && v.Decl != ExprDecl {
+ // only allow (v.Decl,decl) of: (var|function|argument,var|function), (expr,*), any other combination is a syntax error
+ return nil, false
+ }
+ if v.Decl == ExprDecl {
+ v.Decl = decl
+ }
+ v.Uses++
+ for s != curScope {
+ curScope.AddUndeclared(v) // add variable declaration as used variable to the current scope
+ curScope = curScope.Parent
+ }
+ return v, true
+ }
+
+ var v *Var
+ // reuse variable if previously used, as in: a;var a
+ if decl != ArgumentDecl { // in case of function f(a=b,b), where the first b is different from the second
+ for i, uv := range s.Undeclared[s.NumArgUses:] {
+ // no need to evaluate v.Link as v.Data stays the same and Link is nil in the active scope
+ if 0 < uv.Uses && uv.Decl == NoDecl && bytes.Equal(name, uv.Data) {
+ // must be NoDecl so that it can't be a var declaration that has been added
+ v = uv
+ s.Undeclared = append(s.Undeclared[:int(s.NumArgUses)+i], s.Undeclared[int(s.NumArgUses)+i+1:]...)
+ break
+ }
+ }
+ }
+ if v == nil {
+ // add variable to the context list and to the scope
+ v = &Var{name, nil, 0, decl}
+ } else {
+ v.Decl = decl
+ }
+ v.Uses++
+ s.Declared = append(s.Declared, v)
+ for s != curScope {
+ curScope.AddUndeclared(v) // add variable declaration as used variable to the current scope
+ curScope = curScope.Parent
+ }
+ return v, true
+}
+
+// Use increments the usage of a variable.
+func (s *Scope) Use(name []byte) *Var {
+ // check if variable is declared in the current scope
+ v := s.findDeclared(name, false)
+ if v == nil {
+ // check if variable is already used before in the current or lower scopes
+ v = s.findUndeclared(name)
+ if v == nil {
+ // add variable to the context list and to the scope's undeclared
+ v = &Var{name, nil, 0, NoDecl}
+ s.Undeclared = append(s.Undeclared, v)
+ }
+ }
+ v.Uses++
+ return v
+}
+
+// findDeclared finds a declared variable in the current scope.
+func (s *Scope) findDeclared(name []byte, skipForDeclared bool) *Var {
+ start := 0
+ if skipForDeclared {
+ // we skip the for initializer for declarations (only has effect for let/const)
+ start = int(s.NumForDecls)
+ }
+ // reverse order to find the inner let first in `for(let a in []){let a; {a}}`
+ for i := len(s.Declared) - 1; start <= i; i-- {
+ v := s.Declared[i]
+ // no need to evaluate v.Link as v.Data stays the same, and Link is always nil in Declared
+ if bytes.Equal(name, v.Data) {
+ return v
+ }
+ }
+ return nil
+}
+
+// findUndeclared finds an undeclared variable in the current and contained scopes.
+func (s *Scope) findUndeclared(name []byte) *Var {
+ for _, v := range s.Undeclared {
+ // no need to evaluate v.Link as v.Data stays the same and Link is nil in the active scope
+ if 0 < v.Uses && bytes.Equal(name, v.Data) {
+ return v
+ }
+ }
+ return nil
+}
+
+// add undeclared variable to scope, this is called for the block scope when declaring a var in it
+func (s *Scope) AddUndeclared(v *Var) {
+ // don't add undeclared symbol if it's already there
+ for _, vorig := range s.Undeclared {
+ if v == vorig {
+ return
+ }
+ }
+ s.Undeclared = append(s.Undeclared, v) // add variable declaration as used variable to the current scope
+}
+
+// MarkForStmt marks the declared variables in current scope as for statement initializer to distinguish from declarations in body.
+func (s *Scope) MarkForStmt() {
+ s.NumForDecls = uint16(len(s.Declared))
+ s.NumArgUses = uint16(len(s.Undeclared)) // ensures for different b's in for(var a in b){let b}
+}
+
+// MarkFuncArgs marks the declared/undeclared variables in the current scope as function arguments.
+func (s *Scope) MarkFuncArgs() {
+ s.NumFuncArgs = uint16(len(s.Declared))
+ s.NumArgUses = uint16(len(s.Undeclared)) // ensures different b's in `function f(a=b){var b}`.
+}
+
+// HoistUndeclared copies all undeclared variables of the current scope to the parent scope.
+func (s *Scope) HoistUndeclared() {
+ for i, vorig := range s.Undeclared {
+ // no need to evaluate vorig.Link as vorig.Data stays the same
+ if 0 < vorig.Uses && vorig.Decl == NoDecl {
+ if v := s.Parent.findDeclared(vorig.Data, false); v != nil {
+ // check if variable is declared in parent scope
+ v.Uses += vorig.Uses
+ vorig.Link = v
+ s.Undeclared[i] = v // point reference to existing var (to avoid many Link chains)
+ } else if v := s.Parent.findUndeclared(vorig.Data); v != nil {
+ // check if variable is already used before in parent scope
+ v.Uses += vorig.Uses
+ vorig.Link = v
+ s.Undeclared[i] = v // point reference to existing var (to avoid many Link chains)
+ } else {
+ // add variable to the context list and to the scope's undeclared
+ s.Parent.Undeclared = append(s.Parent.Undeclared, vorig)
+ }
+ }
+ }
+}
+
+// UndeclareScope undeclares all declared variables in the current scope and adds them to the parent scope.
+// Called when possible arrow func ends up being a parenthesized expression, scope is not further used.
+func (s *Scope) UndeclareScope() {
+ // look if the variable already exists in the parent scope, if so replace the Var pointer in original use
+ for _, vorig := range s.Declared {
+ // no need to evaluate vorig.Link as vorig.Data stays the same, and Link is always nil in Declared
+ // vorig.Uses will be atleast 1
+ if v := s.Parent.findDeclared(vorig.Data, false); v != nil {
+ // check if variable has been declared in this scope
+ v.Uses += vorig.Uses
+ vorig.Link = v
+ } else if v := s.Parent.findUndeclared(vorig.Data); v != nil {
+ // check if variable is already used before in the current or lower scopes
+ v.Uses += vorig.Uses
+ vorig.Link = v
+ } else {
+ // add variable to the context list and to the scope's undeclared
+ vorig.Decl = NoDecl
+ s.Parent.Undeclared = append(s.Parent.Undeclared, vorig)
+ }
+ }
+ s.Declared = s.Declared[:0]
+ s.Undeclared = s.Undeclared[:0]
+}
+
+// Unscope moves all declared variables of the current scope to the parent scope. Undeclared variables are already in the parent scope.
+func (s *Scope) Unscope() {
+ for _, vorig := range s.Declared {
+ // no need to evaluate vorig.Link as vorig.Data stays the same, and Link is always nil in Declared
+ // vorig.Uses will be atleast 1
+ s.Parent.Declared = append(s.Parent.Declared, vorig)
+ }
+ s.Declared = s.Declared[:0]
+ s.Undeclared = s.Undeclared[:0]
+}
+
+////////////////////////////////////////////////////////////////
+
+// INode is an interface for AST nodes
+type INode interface {
+ String() string
+ JS() string
+ JSWriteTo(io.Writer) (int, error)
+}
+
+// IStmt is a dummy interface for statements.
+type IStmt interface {
+ INode
+ stmtNode()
+}
+
+// IBinding is a dummy interface for bindings.
+type IBinding interface {
+ INode
+ bindingNode()
+}
+
+// IExpr is a dummy interface for expressions.
+type IExpr interface {
+ INode
+ exprNode()
+}
+
+////////////////////////////////////////////////////////////////
+
+// BlockStmt is a block statement.
+type BlockStmt struct {
+ List []IStmt
+ Scope
+}
+
+func (n BlockStmt) String() string {
+ s := "Stmt({"
+ for _, item := range n.List {
+ s += " " + item.String()
+ }
+ return s + " })"
+}
+
+// JS converts the node back to valid JavaScript
+func (n BlockStmt) JS() string {
+ s := ""
+ if n.Scope.Parent != nil {
+ s += "{ "
+ }
+ for _, item := range n.List {
+ if _, isEmpty := item.(*EmptyStmt); !isEmpty {
+ s += item.JS() + "; "
+ }
+ }
+ if n.Scope.Parent != nil {
+ s += "}"
+ }
+ return s
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n BlockStmt) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ if n.Scope.Parent != nil {
+ wn, err = w.Write([]byte("{ "))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ for _, item := range n.List {
+ if _, isEmpty := item.(*EmptyStmt); !isEmpty {
+ wn, err = item.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte("; "))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ }
+ if n.Scope.Parent != nil {
+ wn, err = w.Write([]byte{'}'})
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ return
+}
+
+// EmptyStmt is an empty statement.
+type EmptyStmt struct {
+}
+
+func (n EmptyStmt) String() string {
+ return "Stmt(;)"
+}
+
+// JS converts the node back to valid JavaScript
+func (n EmptyStmt) JS() string {
+ return ";"
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n EmptyStmt) JSWriteTo(w io.Writer) (i int, err error) {
+ wn, err := w.Write([]byte{';'})
+ i = wn
+ return
+}
+
+// ExprStmt is an expression statement.
+type ExprStmt struct {
+ Value IExpr
+}
+
+func (n ExprStmt) String() string {
+ val := n.Value.String()
+ if val[0] == '(' && val[len(val)-1] == ')' {
+ return "Stmt" + n.Value.String()
+ }
+ return "Stmt(" + n.Value.String() + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n ExprStmt) JS() string {
+ return n.Value.JS()
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n ExprStmt) JSWriteTo(w io.Writer) (i int, err error) {
+ return n.Value.JSWriteTo(w)
+}
+
+// IfStmt is an if statement.
+type IfStmt struct {
+ Cond IExpr
+ Body IStmt
+ Else IStmt // can be nil
+}
+
+func (n IfStmt) String() string {
+ s := "Stmt(if " + n.Cond.String() + " " + n.Body.String()
+ if n.Else != nil {
+ s += " else " + n.Else.String()
+ }
+ return s + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n IfStmt) JS() string {
+ s := "if (" + n.Cond.JS() + ") "
+ switch n.Body.(type) {
+ case *BlockStmt:
+ s += n.Body.JS()
+ default:
+ s += "{ " + n.Body.JS() + " }"
+ }
+ if n.Else != nil {
+ switch n.Else.(type) {
+ case *BlockStmt:
+ s += " else " + n.Else.JS()
+ default:
+ s += " else { " + n.Else.JS() + " }"
+ }
+ }
+ return s
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n IfStmt) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write([]byte("if ("))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Cond.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(") "))
+ i += wn
+ if err != nil {
+ return
+ }
+ switch n.Body.(type) {
+ case *BlockStmt:
+ wn, err = n.Body.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ default:
+ wn, err = w.Write([]byte("{ "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Body.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(" }"))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ if n.Else != nil {
+ switch n.Else.(type) {
+ case *BlockStmt:
+ wn, err = w.Write([]byte(" else "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Else.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ default:
+ wn, err = w.Write([]byte(" else { "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Else.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(" }"))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ }
+ return
+}
+
+// DoWhileStmt is a do-while iteration statement.
+type DoWhileStmt struct {
+ Cond IExpr
+ Body IStmt
+}
+
+func (n DoWhileStmt) String() string {
+ return "Stmt(do " + n.Body.String() + " while " + n.Cond.String() + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n DoWhileStmt) JS() string {
+ s := "do "
+ switch n.Body.(type) {
+ case *BlockStmt:
+ s += n.Body.JS()
+ default:
+ s += "{ " + n.Body.JS() + " }"
+ }
+ return s + " while (" + n.Cond.JS() + ")"
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n DoWhileStmt) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write([]byte("do "))
+ i += wn
+ if err != nil {
+ return
+ }
+ switch n.Body.(type) {
+ case *BlockStmt:
+ wn, err = n.Body.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ default:
+ wn, err = w.Write([]byte("{ "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Body.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(" }"))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = w.Write([]byte(" while ("))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Cond.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(")"))
+ i += wn
+ return
+}
+
+// WhileStmt is a while iteration statement.
+type WhileStmt struct {
+ Cond IExpr
+ Body IStmt
+}
+
+func (n WhileStmt) String() string {
+ return "Stmt(while " + n.Cond.String() + " " + n.Body.String() + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n WhileStmt) JS() string {
+ s := "while (" + n.Cond.JS() + ") "
+ if n.Body != nil {
+ s += n.Body.JS()
+ }
+ return s
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n WhileStmt) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write([]byte("while ("))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Cond.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(") "))
+ i += wn
+ if err != nil {
+ return
+ }
+ if n.Body != nil {
+ wn, err = n.Body.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ return
+}
+
+// ForStmt is a regular for iteration statement.
+type ForStmt struct {
+ Init IExpr // can be nil
+ Cond IExpr // can be nil
+ Post IExpr // can be nil
+ Body *BlockStmt
+}
+
+func (n ForStmt) String() string {
+ s := "Stmt(for"
+ if v, ok := n.Init.(*VarDecl); !ok && n.Init != nil || ok && len(v.List) != 0 {
+ s += " " + n.Init.String()
+ }
+ s += " ;"
+ if n.Cond != nil {
+ s += " " + n.Cond.String()
+ }
+ s += " ;"
+ if n.Post != nil {
+ s += " " + n.Post.String()
+ }
+ return s + " " + n.Body.String() + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n ForStmt) JS() string {
+ s := "for ("
+ if v, ok := n.Init.(*VarDecl); !ok && n.Init != nil || ok && len(v.List) != 0 {
+ s += n.Init.JS()
+ } else {
+ s += " "
+ }
+ s += "; "
+ if n.Cond != nil {
+ s += n.Cond.JS()
+ }
+ s += "; "
+ if n.Post != nil {
+ s += n.Post.JS()
+ }
+ return s + ") " + n.Body.JS()
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n ForStmt) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write([]byte("for ("))
+ i += wn
+ if err != nil {
+ return
+ }
+ if v, ok := n.Init.(*VarDecl); !ok && n.Init != nil || ok && len(v.List) != 0 {
+ wn, err = n.Init.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ } else {
+ wn, err = w.Write([]byte(" "))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = w.Write([]byte("; "))
+ i += wn
+ if err != nil {
+ return
+ }
+ if n.Cond != nil {
+ wn, err = n.Cond.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = w.Write([]byte("; "))
+ i += wn
+ if err != nil {
+ return
+ }
+ if n.Post != nil {
+ wn, err = n.Post.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = w.Write([]byte(") "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Body.JSWriteTo(w)
+ i += wn
+ return
+}
+
+// ForInStmt is a for-in iteration statement.
+type ForInStmt struct {
+ Init IExpr
+ Value IExpr
+ Body *BlockStmt
+}
+
+func (n ForInStmt) String() string {
+ return "Stmt(for " + n.Init.String() + " in " + n.Value.String() + " " + n.Body.String() + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n ForInStmt) JS() string {
+ return "for (" + n.Init.JS() + " in " + n.Value.JS() + ") " + n.Body.JS()
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n ForInStmt) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write([]byte("for ("))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Init.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(" in "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Value.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(") "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Body.JSWriteTo(w)
+ i += wn
+ return
+}
+
+// ForOfStmt is a for-of iteration statement.
+type ForOfStmt struct {
+ Await bool
+ Init IExpr
+ Value IExpr
+ Body *BlockStmt
+}
+
+func (n ForOfStmt) String() string {
+ s := "Stmt(for"
+ if n.Await {
+ s += " await"
+ }
+ return s + " " + n.Init.String() + " of " + n.Value.String() + " " + n.Body.String() + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n ForOfStmt) JS() string {
+ s := "for"
+ if n.Await {
+ s += " await"
+ }
+ return s + " (" + n.Init.JS() + " of " + n.Value.JS() + ") " + n.Body.JS()
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n ForOfStmt) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write([]byte("for"))
+ i += wn
+ if err != nil {
+ return
+ }
+ if n.Await {
+ wn, err = w.Write([]byte(" await"))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = w.Write([]byte(" ("))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Init.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(" of "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Value.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(") "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Body.JSWriteTo(w)
+ i += wn
+ return
+}
+
+// CaseClause is a case clause or default clause for a switch statement.
+type CaseClause struct {
+ TokenType
+ Cond IExpr // can be nil
+ List []IStmt
+}
+
+func (n CaseClause) String() string {
+ s := " Clause(" + n.TokenType.String()
+ if n.Cond != nil {
+ s += " " + n.Cond.String()
+ }
+ for _, item := range n.List {
+ s += " " + item.String()
+ }
+ return s + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n CaseClause) JS() string {
+ s := " "
+ if n.Cond != nil {
+ s += "case " + n.Cond.JS()
+ } else {
+ s += "default"
+ }
+ s += ":"
+ for _, item := range n.List {
+ s += " " + item.JS() + ";"
+ }
+ return s
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n CaseClause) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write([]byte(" "))
+ i += wn
+ if err != nil {
+ return
+ }
+ if n.Cond != nil {
+ wn, err = w.Write([]byte("case "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Cond.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ } else {
+ wn, err = w.Write([]byte("default"))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = w.Write([]byte(":"))
+ i += wn
+ if err != nil {
+ return
+ }
+ for _, item := range n.List {
+ wn, err = w.Write([]byte(" "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = item.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(";"))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ return
+}
+
+// SwitchStmt is a switch statement.
+type SwitchStmt struct {
+ Init IExpr
+ List []CaseClause
+ Scope
+}
+
+func (n SwitchStmt) String() string {
+ s := "Stmt(switch " + n.Init.String()
+ for _, clause := range n.List {
+ s += clause.String()
+ }
+ return s + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n SwitchStmt) JS() string {
+ s := "switch (" + n.Init.JS() + ") {"
+ for _, clause := range n.List {
+ s += clause.JS()
+ }
+ return s + " }"
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n SwitchStmt) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write([]byte("switch ("))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Init.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(") {"))
+ i += wn
+ if err != nil {
+ return
+ }
+ for _, clause := range n.List {
+ wn, err = clause.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = w.Write([]byte(" }"))
+ i += wn
+ return
+}
+
+// BranchStmt is a continue or break statement.
+type BranchStmt struct {
+ Type TokenType
+ Label []byte // can be nil
+}
+
+func (n BranchStmt) String() string {
+ s := "Stmt(" + n.Type.String()
+ if n.Label != nil {
+ s += " " + string(n.Label)
+ }
+ return s + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n BranchStmt) JS() string {
+ s := n.Type.String()
+ if n.Label != nil {
+ s += " " + string(n.Label)
+ }
+ return s
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n BranchStmt) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write(n.Type.Bytes())
+ i += wn
+ if err != nil {
+ return
+ }
+ if n.Label != nil {
+ wn, err = w.Write([]byte(" "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write(n.Label)
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ return
+}
+
+// ReturnStmt is a return statement.
+type ReturnStmt struct {
+ Value IExpr // can be nil
+}
+
+func (n ReturnStmt) String() string {
+ s := "Stmt(return"
+ if n.Value != nil {
+ s += " " + n.Value.String()
+ }
+ return s + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n ReturnStmt) JS() string {
+ s := "return"
+ if n.Value != nil {
+ s += " " + n.Value.JS()
+ }
+ return s
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n ReturnStmt) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write([]byte("return"))
+ i += wn
+ if err != nil {
+ return
+ }
+ if n.Value != nil {
+ wn, err = w.Write([]byte(" "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Value.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ return
+}
+
+// WithStmt is a with statement.
+type WithStmt struct {
+ Cond IExpr
+ Body IStmt
+}
+
+func (n WithStmt) String() string {
+ return "Stmt(with " + n.Cond.String() + " " + n.Body.String() + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n WithStmt) JS() string {
+ return "with (" + n.Cond.JS() + ") " + n.Body.JS()
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n WithStmt) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write([]byte("with ("))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Cond.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(") "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Body.JSWriteTo(w)
+ i += wn
+ return
+}
+
+// LabelledStmt is a labelled statement.
+type LabelledStmt struct {
+ Label []byte
+ Value IStmt
+}
+
+func (n LabelledStmt) String() string {
+ return "Stmt(" + string(n.Label) + " : " + n.Value.String() + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n LabelledStmt) JS() string {
+ return string(n.Label) + ": " + n.Value.JS()
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n LabelledStmt) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write(n.Label)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(": "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Value.JSWriteTo(w)
+ i += wn
+ return
+}
+
+// ThrowStmt is a throw statement.
+type ThrowStmt struct {
+ Value IExpr
+}
+
+func (n ThrowStmt) String() string {
+ return "Stmt(throw " + n.Value.String() + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n ThrowStmt) JS() string {
+ return "throw " + n.Value.JS()
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n ThrowStmt) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write([]byte("throw "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Value.JSWriteTo(w)
+ i += wn
+ return
+}
+
+// TryStmt is a try statement.
+type TryStmt struct {
+ Body *BlockStmt
+ Binding IBinding // can be nil
+ Catch *BlockStmt // can be nil
+ Finally *BlockStmt // can be nil
+}
+
+func (n TryStmt) String() string {
+ s := "Stmt(try " + n.Body.String()
+ if n.Catch != nil {
+ s += " catch"
+ if n.Binding != nil {
+ s += " Binding(" + n.Binding.String() + ")"
+ }
+ s += " " + n.Catch.String()
+ }
+ if n.Finally != nil {
+ s += " finally " + n.Finally.String()
+ }
+ return s + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n TryStmt) JS() string {
+ s := "try " + n.Body.JS()
+ if n.Catch != nil {
+ s += " catch"
+ if n.Binding != nil {
+ s += "(" + n.Binding.JS() + ")"
+ }
+ s += " " + n.Catch.JS()
+ }
+ if n.Finally != nil {
+ s += " finally " + n.Finally.JS()
+ }
+ return s
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n TryStmt) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write([]byte("try "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Body.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ if n.Catch != nil {
+ wn, err = w.Write([]byte(" catch"))
+ i += wn
+ if err != nil {
+ return
+ }
+ if n.Binding != nil {
+ wn, err = w.Write([]byte("("))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Binding.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(")"))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = w.Write([]byte(" "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Catch.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ if n.Finally != nil {
+ wn, err = w.Write([]byte(" finally "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Finally.JSWriteTo(w)
+ i += wn
+ }
+ return
+}
+
+// DebuggerStmt is a debugger statement.
+type DebuggerStmt struct {
+}
+
+func (n DebuggerStmt) String() string {
+ return "Stmt(debugger)"
+}
+
+// JS converts the node back to valid JavaScript
+func (n DebuggerStmt) JS() string {
+ return "debugger"
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n DebuggerStmt) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write([]byte("debugger"))
+ i += wn
+ return
+}
+
+// Alias is a name space import or import/export specifier for import/export statements.
+type Alias struct {
+ Name []byte // can be nil
+ Binding []byte // can be nil
+}
+
+func (alias Alias) String() string {
+ s := ""
+ if alias.Name != nil {
+ s += string(alias.Name) + " as "
+ }
+ return s + string(alias.Binding)
+}
+
+// JS converts the node back to valid JavaScript
+func (alias Alias) JS() string {
+ return alias.String()
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (alias Alias) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ if alias.Name != nil {
+ wn, err = w.Write(alias.Name)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(" as "))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = w.Write(alias.Binding)
+ i += wn
+ return
+}
+
+// ImportStmt is an import statement.
+type ImportStmt struct {
+ List []Alias
+ Default []byte // can be nil
+ Module []byte
+}
+
+func (n ImportStmt) String() string {
+ s := "Stmt(import"
+ if n.Default != nil {
+ s += " " + string(n.Default)
+ if len(n.List) != 0 {
+ s += " ,"
+ }
+ }
+ if len(n.List) == 1 && len(n.List[0].Name) == 1 && n.List[0].Name[0] == '*' {
+ s += " " + n.List[0].String()
+ } else if 0 < len(n.List) {
+ s += " {"
+ for i, item := range n.List {
+ if i != 0 {
+ s += " ,"
+ }
+ if item.Binding != nil {
+ s += " " + item.String()
+ }
+ }
+ s += " }"
+ }
+ if n.Default != nil || len(n.List) != 0 {
+ s += " from"
+ }
+ return s + " " + string(n.Module) + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n ImportStmt) JS() string {
+ s := "import"
+ if n.Default != nil {
+ s += " " + string(n.Default)
+ if len(n.List) != 0 {
+ s += " ,"
+ }
+ }
+ if len(n.List) == 1 && len(n.List[0].Name) == 1 && n.List[0].Name[0] == '*' {
+ s += " " + n.List[0].JS()
+ } else if 0 < len(n.List) {
+ s += " {"
+ for i, item := range n.List {
+ if i != 0 {
+ s += " ,"
+ }
+ if item.Binding != nil {
+ s += " " + item.JS()
+ }
+ }
+ s += " }"
+ }
+ if n.Default != nil || len(n.List) != 0 {
+ s += " from"
+ }
+ return s + " " + string(n.Module)
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n ImportStmt) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write([]byte("import"))
+ i += wn
+ if err != nil {
+ return
+ }
+ if n.Default != nil {
+ wn, err = w.Write([]byte(" "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write(n.Default)
+ i += wn
+ if err != nil {
+ return
+ }
+ if len(n.List) != 0 {
+ wn, err = w.Write([]byte(" ,"))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ }
+ if len(n.List) == 1 && len(n.List[0].Name) == 1 && n.List[0].Name[0] == '*' {
+ wn, err = w.Write([]byte(" "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.List[0].JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ } else if 0 < len(n.List) {
+ wn, err = w.Write([]byte(" {"))
+ i += wn
+ if err != nil {
+ return
+ }
+ for j, item := range n.List {
+ if j != 0 {
+ wn, err = w.Write([]byte(" ,"))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ if item.Binding != nil {
+ wn, err = w.Write([]byte(" "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = item.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ }
+ wn, err = w.Write([]byte(" }"))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ if n.Default != nil || len(n.List) != 0 {
+ wn, err = w.Write([]byte(" from"))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = w.Write([]byte(" "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write(n.Module)
+ i += wn
+ return
+}
+
+// ExportStmt is an export statement.
+type ExportStmt struct {
+ List []Alias
+ Module []byte // can be nil
+ Default bool
+ Decl IExpr
+}
+
+func (n ExportStmt) String() string {
+ s := "Stmt(export"
+ if n.Decl != nil {
+ if n.Default {
+ s += " default"
+ }
+ return s + " " + n.Decl.String() + ")"
+ } 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] == '*') {
+ s += " " + n.List[0].String()
+ } else if 0 < len(n.List) {
+ s += " {"
+ for i, item := range n.List {
+ if i != 0 {
+ s += " ,"
+ }
+ if item.Binding != nil {
+ s += " " + item.String()
+ }
+ }
+ s += " }"
+ }
+ if n.Module != nil {
+ s += " from " + string(n.Module)
+ }
+ return s + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n ExportStmt) JS() string {
+ s := "export"
+ if n.Decl != nil {
+ if n.Default {
+ s += " default"
+ }
+ return s + " " + n.Decl.JS()
+ } 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] == '*') {
+ s += " " + n.List[0].JS()
+ } else if 0 < len(n.List) {
+ s += " {"
+ for i, item := range n.List {
+ if i != 0 {
+ s += " ,"
+ }
+ if item.Binding != nil {
+ s += " " + item.JS()
+ }
+ }
+ s += " }"
+ }
+ if n.Module != nil {
+ s += " from " + string(n.Module)
+ }
+ return s
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n ExportStmt) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write([]byte("export"))
+ i += wn
+ if err != nil {
+ return
+ }
+ if n.Decl != nil {
+ if n.Default {
+ wn, err = w.Write([]byte(" default"))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = w.Write([]byte(" "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Decl.JSWriteTo(w)
+ i += wn
+ return
+ } 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] == '*') {
+ wn, err = w.Write([]byte(" "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.List[0].JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ } else if 0 < len(n.List) {
+ wn, err = w.Write([]byte(" {"))
+ i += wn
+ if err != nil {
+ return
+ }
+ for j, item := range n.List {
+ if j != 0 {
+ wn, err = w.Write([]byte(" ,"))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ if item.Binding != nil {
+ wn, err = w.Write([]byte(" "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = item.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ }
+ wn, err = w.Write([]byte(" }"))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ if n.Module != nil {
+ wn, err = w.Write([]byte(" from "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write(n.Module)
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ return
+}
+
+// DirectivePrologueStmt is a string literal at the beginning of a function or module (usually "use strict").
+type DirectivePrologueStmt struct {
+ Value []byte
+}
+
+func (n DirectivePrologueStmt) String() string {
+ return "Stmt(" + string(n.Value) + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n DirectivePrologueStmt) JS() string {
+ return string(n.Value)
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n DirectivePrologueStmt) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write(n.Value)
+ i += wn
+ return
+}
+
+func (n BlockStmt) stmtNode() {}
+func (n EmptyStmt) stmtNode() {}
+func (n ExprStmt) stmtNode() {}
+func (n IfStmt) stmtNode() {}
+func (n DoWhileStmt) stmtNode() {}
+func (n WhileStmt) stmtNode() {}
+func (n ForStmt) stmtNode() {}
+func (n ForInStmt) stmtNode() {}
+func (n ForOfStmt) stmtNode() {}
+func (n SwitchStmt) stmtNode() {}
+func (n BranchStmt) stmtNode() {}
+func (n ReturnStmt) stmtNode() {}
+func (n WithStmt) stmtNode() {}
+func (n LabelledStmt) stmtNode() {}
+func (n ThrowStmt) stmtNode() {}
+func (n TryStmt) stmtNode() {}
+func (n DebuggerStmt) stmtNode() {}
+func (n ImportStmt) stmtNode() {}
+func (n ExportStmt) stmtNode() {}
+func (n DirectivePrologueStmt) stmtNode() {}
+
+////////////////////////////////////////////////////////////////
+
+// PropertyName is a property name for binding properties, method names, and in object literals.
+type PropertyName struct {
+ Literal LiteralExpr
+ Computed IExpr // can be nil
+}
+
+// IsSet returns true is PropertyName is not nil.
+func (n PropertyName) IsSet() bool {
+ return n.IsComputed() || n.Literal.TokenType != ErrorToken
+}
+
+// IsComputed returns true if PropertyName is computed.
+func (n PropertyName) IsComputed() bool {
+ return n.Computed != nil
+}
+
+// IsIdent returns true if PropertyName equals the given identifier name.
+func (n PropertyName) IsIdent(data []byte) bool {
+ return !n.IsComputed() && n.Literal.TokenType == IdentifierToken && bytes.Equal(data, n.Literal.Data)
+}
+
+func (n PropertyName) String() string {
+ if n.Computed != nil {
+ val := n.Computed.String()
+ if val[0] == '(' {
+ return "[" + val[1:len(val)-1] + "]"
+ }
+ return "[" + val + "]"
+ }
+ return string(n.Literal.Data)
+}
+
+// JS converts the node back to valid JavaScript
+func (n PropertyName) JS() string {
+ if n.Computed != nil {
+ return "[" + n.Computed.JS() + "]"
+ }
+ return string(n.Literal.Data)
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n PropertyName) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ if n.Computed != nil {
+ wn, err = w.Write([]byte("["))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Computed.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte("]"))
+ i += wn
+ return
+ }
+ wn, err = w.Write(n.Literal.Data)
+ i += wn
+ return
+}
+
+// BindingArray is an array binding pattern.
+type BindingArray struct {
+ List []BindingElement
+ Rest IBinding // can be nil
+}
+
+func (n BindingArray) String() string {
+ s := "["
+ for i, item := range n.List {
+ if i != 0 {
+ s += ","
+ }
+ s += " " + item.String()
+ }
+ if n.Rest != nil {
+ if len(n.List) != 0 {
+ s += ","
+ }
+ s += " ...Binding(" + n.Rest.String() + ")"
+ }
+ return s + " ]"
+}
+
+// JS converts the node back to valid JavaScript
+func (n BindingArray) JS() string {
+ s := "["
+ for i, item := range n.List {
+ if i != 0 {
+ s += ", "
+ }
+ s += item.JS()
+ }
+ if n.Rest != nil {
+ if len(n.List) != 0 {
+ s += ", "
+ }
+ s += "..." + n.Rest.JS()
+ }
+ return s + "]"
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n BindingArray) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write([]byte("["))
+ i += wn
+ if err != nil {
+ return
+ }
+ for j, item := range n.List {
+ if j != 0 {
+ wn, err = w.Write([]byte(", "))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = item.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ if n.Rest != nil {
+ if len(n.List) != 0 {
+ wn, err = w.Write([]byte(", "))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = w.Write([]byte("..."))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Rest.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = w.Write([]byte("]"))
+ i += wn
+ return
+}
+
+// BindingObjectItem is a binding property.
+type BindingObjectItem struct {
+ Key *PropertyName // can be nil
+ Value BindingElement
+}
+
+func (n BindingObjectItem) String() string {
+ s := ""
+ if n.Key != nil {
+ if v, ok := n.Value.Binding.(*Var); !ok || !n.Key.IsIdent(v.Data) {
+ s += " " + n.Key.String() + ":"
+ }
+ }
+ return s + " " + n.Value.String()
+}
+
+// JS converts the node back to valid JavaScript
+func (n BindingObjectItem) JS() string {
+ s := ""
+ if n.Key != nil {
+ if v, ok := n.Value.Binding.(*Var); !ok || !n.Key.IsIdent(v.Data) {
+ s += n.Key.JS() + ": "
+ }
+ }
+ return s + n.Value.JS()
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n BindingObjectItem) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ if n.Key != nil {
+ if v, ok := n.Value.Binding.(*Var); !ok || !n.Key.IsIdent(v.Data) {
+ wn, err = n.Key.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(": "))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ }
+ wn, err = n.Value.JSWriteTo(w)
+ i += wn
+ return
+}
+
+// BindingObject is an object binding pattern.
+type BindingObject struct {
+ List []BindingObjectItem
+ Rest *Var // can be nil
+}
+
+func (n BindingObject) String() string {
+ s := "{"
+ for i, item := range n.List {
+ if i != 0 {
+ s += ","
+ }
+ s += item.String()
+ }
+ if n.Rest != nil {
+ if len(n.List) != 0 {
+ s += ","
+ }
+ s += " ...Binding(" + string(n.Rest.Data) + ")"
+ }
+ return s + " }"
+}
+
+// JS converts the node back to valid JavaScript
+func (n BindingObject) JS() string {
+ s := "{"
+ for i, item := range n.List {
+ if i != 0 {
+ s += ", "
+ }
+ s += item.JS()
+ }
+ if n.Rest != nil {
+ if len(n.List) != 0 {
+ s += ", "
+ }
+ s += "..." + string(n.Rest.Data)
+ }
+ return s + "}"
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n BindingObject) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write([]byte("{"))
+ i += wn
+ if err != nil {
+ return
+ }
+ for j, item := range n.List {
+ if j != 0 {
+ wn, err = w.Write([]byte(", "))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = item.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ if n.Rest != nil {
+ if len(n.List) != 0 {
+ wn, err = w.Write([]byte(", "))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = w.Write([]byte("..."))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write(n.Rest.Data)
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = w.Write([]byte("}"))
+ i += wn
+ return
+}
+
+// BindingElement is a binding element.
+type BindingElement struct {
+ Binding IBinding // can be nil (in case of ellision)
+ Default IExpr // can be nil
+}
+
+func (n BindingElement) String() string {
+ if n.Binding == nil {
+ return "Binding()"
+ }
+ s := "Binding(" + n.Binding.String()
+ if n.Default != nil {
+ s += " = " + n.Default.String()
+ }
+ return s + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n BindingElement) JS() string {
+ if n.Binding == nil {
+ return ""
+ }
+ s := n.Binding.JS()
+ if n.Default != nil {
+ s += " = " + n.Default.JS()
+ }
+ return s
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n BindingElement) JSWriteTo(w io.Writer) (i int, err error) {
+ if n.Binding == nil {
+ return
+ }
+ var wn int
+ wn, err = n.Binding.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ if n.Default != nil {
+ wn, err = w.Write([]byte(" = "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Default.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ return
+}
+
+func (v *Var) bindingNode() {}
+func (n BindingArray) bindingNode() {}
+func (n BindingObject) bindingNode() {}
+
+////////////////////////////////////////////////////////////////
+
+// VarDecl is a variable statement or lexical declaration.
+type VarDecl struct {
+ TokenType
+ List []BindingElement
+ Scope *Scope
+ InFor, InForInOf bool
+}
+
+func (n VarDecl) String() string {
+ s := "Decl(" + n.TokenType.String()
+ for _, item := range n.List {
+ s += " " + item.String()
+ }
+ return s + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n VarDecl) JS() string {
+ s := n.TokenType.String()
+ for i, item := range n.List {
+ if i != 0 {
+ s += ","
+ }
+ s += " " + item.JS()
+ }
+ return s
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n VarDecl) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write(n.TokenType.Bytes())
+ i += wn
+ if err != nil {
+ return
+ }
+ for j, item := range n.List {
+ if j != 0 {
+ wn, err = w.Write([]byte(","))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = w.Write([]byte(" "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = item.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ return
+}
+
+// Params is a list of parameters for functions, methods, and arrow function.
+type Params struct {
+ List []BindingElement
+ Rest IBinding // can be nil
+}
+
+func (n Params) String() string {
+ s := "Params("
+ for i, item := range n.List {
+ if i != 0 {
+ s += ", "
+ }
+ s += item.String()
+ }
+ if n.Rest != nil {
+ if len(n.List) != 0 {
+ s += ", "
+ }
+ s += "...Binding(" + n.Rest.String() + ")"
+ }
+ return s + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n Params) JS() string {
+ s := "("
+ for i, item := range n.List {
+ if i != 0 {
+ s += ", "
+ }
+ s += item.JS()
+ }
+ if n.Rest != nil {
+ if len(n.List) != 0 {
+ s += ", "
+ }
+ s += "..." + n.Rest.JS()
+ }
+ return s + ")"
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n Params) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write([]byte("("))
+ i += wn
+ if err != nil {
+ return
+ }
+ for j, item := range n.List {
+ if j != 0 {
+ wn, err = w.Write([]byte(", "))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = item.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ if n.Rest != nil {
+ if len(n.List) != 0 {
+ wn, err = w.Write([]byte(", "))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = w.Write([]byte("..."))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Rest.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = w.Write([]byte(")"))
+ i += wn
+ return
+}
+
+// FuncDecl is an (async) (generator) function declaration or expression.
+type FuncDecl struct {
+ Async bool
+ Generator bool
+ Name *Var // can be nil
+ Params Params
+ Body BlockStmt
+}
+
+func (n FuncDecl) String() string {
+ s := "Decl("
+ if n.Async {
+ s += "async function"
+ } else {
+ s += "function"
+ }
+ if n.Generator {
+ s += "*"
+ }
+ if n.Name != nil {
+ s += " " + string(n.Name.Data)
+ }
+ return s + " " + n.Params.String() + " " + n.Body.String() + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n FuncDecl) JS() string {
+ s := ""
+ if n.Async {
+ s += "async function"
+ } else {
+ s += "function"
+ }
+ if n.Generator {
+ s += "*"
+ }
+ if n.Name != nil {
+ s += " " + string(n.Name.Data)
+ }
+ return s + " " + n.Params.JS() + " " + n.Body.JS()
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n FuncDecl) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ if n.Async {
+ wn, err = w.Write([]byte("async function"))
+ } else {
+ wn, err = w.Write([]byte("function"))
+ }
+ i += wn
+ if err != nil {
+ return
+ }
+
+ if n.Generator {
+ wn, err = w.Write([]byte("*"))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ if n.Name != nil {
+ wn, err = w.Write([]byte(" "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write(n.Name.Data)
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = w.Write([]byte(" "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Params.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(" "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Body.JSWriteTo(w)
+ i += wn
+ return
+}
+
+// MethodDecl is a method definition in a class declaration.
+type MethodDecl struct {
+ Static bool
+ Async bool
+ Generator bool
+ Get bool
+ Set bool
+ Name PropertyName
+ Params Params
+ Body BlockStmt
+}
+
+func (n MethodDecl) String() string {
+ s := ""
+ if n.Static {
+ s += " static"
+ }
+ if n.Async {
+ s += " async"
+ }
+ if n.Generator {
+ s += " *"
+ }
+ if n.Get {
+ s += " get"
+ }
+ if n.Set {
+ s += " set"
+ }
+ s += " " + n.Name.String() + " " + n.Params.String() + " " + n.Body.String()
+ return "Method(" + s[1:] + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n MethodDecl) JS() string {
+ s := ""
+ if n.Static {
+ s += " static"
+ }
+ if n.Async {
+ s += " async"
+ }
+ if n.Generator {
+ s += " *"
+ }
+ if n.Get {
+ s += " get"
+ }
+ if n.Set {
+ s += " set"
+ }
+ s += " " + n.Name.JS() + " " + n.Params.JS() + " " + n.Body.JS()
+ return s[1:]
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n MethodDecl) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ if n.Static {
+ wn, err = w.Write([]byte("static"))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ if n.Async {
+ if wn > 0 {
+ wn, err = w.Write([]byte(" "))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = w.Write([]byte("async"))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ if n.Generator {
+ if wn > 0 {
+ wn, err = w.Write([]byte(" "))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = w.Write([]byte("*"))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ if n.Get {
+ if wn > 0 {
+ wn, err = w.Write([]byte(" "))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = w.Write([]byte("get"))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ if n.Set {
+ if wn > 0 {
+ wn, err = w.Write([]byte(" "))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = w.Write([]byte("set"))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ if wn > 0 {
+ wn, err = w.Write([]byte(" "))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = n.Name.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(" "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Params.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(" "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Body.JSWriteTo(w)
+ i += wn
+ return
+}
+
+// Field is a field definition in a class declaration.
+type Field struct {
+ Static bool
+ Name PropertyName
+ Init IExpr
+}
+
+func (n Field) String() string {
+ s := "Field("
+ if n.Static {
+ s += "static "
+ }
+ s += n.Name.String()
+ if n.Init != nil {
+ s += " = " + n.Init.String()
+ }
+ return s + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n Field) JS() string {
+ s := ""
+ if n.Static {
+ s += "static "
+ }
+ s += n.Name.String()
+ if n.Init != nil {
+ s += " = " + n.Init.JS()
+ }
+ return s
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n Field) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ if n.Static {
+ wn, err = w.Write([]byte("static "))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = n.Name.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ if n.Init != nil {
+ wn, err = w.Write([]byte(" = "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Init.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ return
+}
+
+// ClassElement is a class element that is either a static block, a field definition, or a class method
+type ClassElement struct {
+ StaticBlock *BlockStmt // can be nil
+ Method *MethodDecl // can be nil
+ Field
+}
+
+func (n ClassElement) String() string {
+ if n.StaticBlock != nil {
+ return "Static(" + n.StaticBlock.String() + ")"
+ } else if n.Method != nil {
+ return n.Method.String()
+ }
+ return n.Field.String()
+}
+
+// JS converts the node back to valid JavaScript
+func (n ClassElement) JS() string {
+ if n.StaticBlock != nil {
+ return "static " + n.StaticBlock.JS()
+ } else if n.Method != nil {
+ return n.Method.JS()
+ }
+ return n.Field.JS()
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n ClassElement) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ if n.StaticBlock != nil {
+ wn, err = w.Write([]byte("static "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.StaticBlock.JSWriteTo(w)
+ i += wn
+ return
+ } else if n.Method != nil {
+ wn, err = n.Method.JSWriteTo(w)
+ i += wn
+ return
+ }
+ wn, err = n.Field.JSWriteTo(w)
+ i += wn
+ return
+}
+
+// ClassDecl is a class declaration.
+type ClassDecl struct {
+ Name *Var // can be nil
+ Extends IExpr // can be nil
+ List []ClassElement
+}
+
+func (n ClassDecl) String() string {
+ s := "Decl(class"
+ if n.Name != nil {
+ s += " " + string(n.Name.Data)
+ }
+ if n.Extends != nil {
+ s += " extends " + n.Extends.String()
+ }
+ for _, item := range n.List {
+ s += " " + item.String()
+ }
+ return s + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n ClassDecl) JS() string {
+ s := "class"
+ if n.Name != nil {
+ s += " " + string(n.Name.Data)
+ }
+ if n.Extends != nil {
+ s += " extends " + n.Extends.JS()
+ }
+ s += " { "
+ for _, item := range n.List {
+ s += item.JS() + "; "
+ }
+ return s + "}"
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n ClassDecl) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write([]byte("class"))
+ i += wn
+ if err != nil {
+ return
+ }
+ if n.Name != nil {
+ wn, err = w.Write([]byte(" "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write(n.Name.Data)
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ if n.Extends != nil {
+ wn, err = w.Write([]byte(" extends "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Extends.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = w.Write([]byte(" { "))
+ i += wn
+ if err != nil {
+ return
+ }
+ for _, item := range n.List {
+ wn, err = item.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte("; "))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = w.Write([]byte("}"))
+ i += wn
+ return
+}
+
+func (n VarDecl) stmtNode() {}
+func (n FuncDecl) stmtNode() {}
+func (n ClassDecl) stmtNode() {}
+
+func (n VarDecl) exprNode() {} // not a real IExpr, used for ForInit and ExportDecl
+func (n FuncDecl) exprNode() {}
+func (n ClassDecl) exprNode() {}
+func (n MethodDecl) exprNode() {} // not a real IExpr, used for ObjectExpression PropertyName
+
+////////////////////////////////////////////////////////////////
+
+// LiteralExpr can be this, null, boolean, numeric, string, or regular expression literals.
+type LiteralExpr struct {
+ TokenType
+ Data []byte
+}
+
+func (n LiteralExpr) String() string {
+ return string(n.Data)
+}
+
+// JS converts the node back to valid JavaScript
+func (n LiteralExpr) JS() string {
+ return string(n.Data)
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n LiteralExpr) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write(n.Data)
+ i += wn
+ return
+}
+
+// JSON converts the node back to valid JSON
+func (n LiteralExpr) JSON(buf *bytes.Buffer) error {
+ if n.TokenType == TrueToken || n.TokenType == FalseToken || n.TokenType == NullToken || n.TokenType == DecimalToken {
+ buf.Write(n.Data)
+ return nil
+ } else if n.TokenType == StringToken {
+ data := n.Data
+ if n.Data[0] == '\'' {
+ data = parse.Copy(data)
+ data = bytes.ReplaceAll(data, []byte(`"`), []byte(`\"`))
+ data[0] = '"'
+ data[len(data)-1] = '"'
+ }
+ buf.Write(data)
+ return nil
+ }
+ return ErrInvalidJSON
+}
+
+// Element is an array literal element.
+type Element struct {
+ Value IExpr // can be nil
+ Spread bool
+}
+
+func (n Element) String() string {
+ s := ""
+ if n.Value != nil {
+ if n.Spread {
+ s += "..."
+ }
+ s += n.Value.String()
+ }
+ return s
+}
+
+// JS converts the node back to valid JavaScript
+func (n Element) JS() string {
+ s := ""
+ if n.Value != nil {
+ if n.Spread {
+ s += "..."
+ }
+ s += n.Value.JS()
+ }
+ return s
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n Element) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ if n.Value != nil {
+ if n.Spread {
+ wn, err = w.Write([]byte("..."))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = n.Value.JSWriteTo(w)
+ i += wn
+ }
+ return
+}
+
+// ArrayExpr is an array literal.
+type ArrayExpr struct {
+ List []Element
+}
+
+func (n ArrayExpr) String() string {
+ s := "["
+ for i, item := range n.List {
+ if i != 0 {
+ s += ", "
+ }
+ if item.Value != nil {
+ if item.Spread {
+ s += "..."
+ }
+ s += item.Value.String()
+ }
+ }
+ if 0 < len(n.List) && n.List[len(n.List)-1].Value == nil {
+ s += ","
+ }
+ return s + "]"
+}
+
+// JS converts the node back to valid JavaScript
+func (n ArrayExpr) JS() string {
+ s := "["
+ for i, item := range n.List {
+ if i != 0 {
+ s += ", "
+ }
+ if item.Value != nil {
+ if item.Spread {
+ s += "..."
+ }
+ s += item.Value.JS()
+ }
+ }
+ if 0 < len(n.List) && n.List[len(n.List)-1].Value == nil {
+ s += ","
+ }
+ return s + "]"
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n ArrayExpr) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write([]byte("["))
+ i += wn
+ if err != nil {
+ return
+ }
+ for j, item := range n.List {
+ if j != 0 {
+ wn, err = w.Write([]byte(", "))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ if item.Value != nil {
+ if item.Spread {
+ wn, err = w.Write([]byte("..."))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = item.Value.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ }
+ if 0 < len(n.List) && n.List[len(n.List)-1].Value == nil {
+ wn, err = w.Write([]byte(","))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = w.Write([]byte("]"))
+ i += wn
+ return
+}
+
+// JSON converts the node back to valid JSON
+func (n ArrayExpr) JSON(buf *bytes.Buffer) error {
+ buf.WriteByte('[')
+ for i, item := range n.List {
+ if i != 0 {
+ buf.WriteString(", ")
+ }
+ if item.Value == nil || item.Spread {
+ return ErrInvalidJSON
+ }
+ val, ok := item.Value.(JSONer)
+ if !ok {
+ return ErrInvalidJSON
+ } else if err := val.JSON(buf); err != nil {
+ return err
+ }
+ }
+ buf.WriteByte(']')
+ return nil
+}
+
+// Property is a property definition in an object literal.
+type Property struct {
+ // either Name or Spread are set. When Spread is set then Value is AssignmentExpression
+ // if Init is set then Value is IdentifierReference, otherwise it can also be MethodDefinition
+ Name *PropertyName // can be nil
+ Spread bool
+ Value IExpr
+ Init IExpr // can be nil
+}
+
+func (n Property) String() string {
+ s := ""
+ if n.Name != nil {
+ if v, ok := n.Value.(*Var); !ok || !n.Name.IsIdent(v.Data) {
+ s += n.Name.String() + ": "
+ }
+ } else if n.Spread {
+ s += "..."
+ }
+ s += n.Value.String()
+ if n.Init != nil {
+ s += " = " + n.Init.String()
+ }
+ return s
+}
+
+// JS converts the node back to valid JavaScript
+func (n Property) JS() string {
+ s := ""
+ if n.Name != nil {
+ if v, ok := n.Value.(*Var); !ok || !n.Name.IsIdent(v.Data) {
+ s += n.Name.JS() + ": "
+ }
+ } else if n.Spread {
+ s += "..."
+ }
+ s += n.Value.JS()
+ if n.Init != nil {
+ s += " = " + n.Init.JS()
+ }
+ return s
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n Property) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ if n.Name != nil {
+ if v, ok := n.Value.(*Var); !ok || !n.Name.IsIdent(v.Data) {
+ wn, err = n.Name.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(": "))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ } else if n.Spread {
+ wn, err = w.Write([]byte("..."))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = n.Value.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ if n.Init != nil {
+ wn, err = w.Write([]byte(" = "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Init.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ return
+}
+
+// JSON converts the node back to valid JSON
+func (n Property) JSON(buf *bytes.Buffer) error {
+ if n.Name == nil || n.Name.Literal.TokenType != StringToken && n.Name.Literal.TokenType != IdentifierToken || n.Spread || n.Init != nil {
+ return ErrInvalidJSON
+ } else if n.Name.Literal.TokenType == IdentifierToken {
+ buf.WriteByte('"')
+ buf.Write(n.Name.Literal.Data)
+ buf.WriteByte('"')
+ } else {
+ _ = n.Name.Literal.JSON(buf)
+ }
+ buf.WriteString(": ")
+
+ val, ok := n.Value.(JSONer)
+ if !ok {
+ return ErrInvalidJSON
+ } else if err := val.JSON(buf); err != nil {
+ return err
+ }
+ return nil
+}
+
+// ObjectExpr is an object literal.
+type ObjectExpr struct {
+ List []Property
+}
+
+func (n ObjectExpr) String() string {
+ s := "{"
+ for i, item := range n.List {
+ if i != 0 {
+ s += ", "
+ }
+ s += item.String()
+ }
+ return s + "}"
+}
+
+// JS converts the node back to valid JavaScript
+func (n ObjectExpr) JS() string {
+ s := "{"
+ for i, item := range n.List {
+ if i != 0 {
+ s += ", "
+ }
+ s += item.JS()
+ }
+ return s + "}"
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n ObjectExpr) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write([]byte("{"))
+ i += wn
+ if err != nil {
+ return
+ }
+ for j, item := range n.List {
+ if j != 0 {
+ wn, err = w.Write([]byte(", "))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = item.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = w.Write([]byte("}"))
+ i += wn
+ return
+}
+
+// JSON converts the node back to valid JSON
+func (n ObjectExpr) JSON(buf *bytes.Buffer) error {
+ buf.WriteByte('{')
+ for i, item := range n.List {
+ if i != 0 {
+ buf.WriteString(", ")
+ }
+ if err := item.JSON(buf); err != nil {
+ return err
+ }
+ }
+ buf.WriteByte('}')
+ return nil
+}
+
+// TemplatePart is a template head or middle.
+type TemplatePart struct {
+ Value []byte
+ Expr IExpr
+}
+
+func (n TemplatePart) String() string {
+ return string(n.Value) + n.Expr.String()
+}
+
+// JS converts the node back to valid JavaScript
+func (n TemplatePart) JS() string {
+ return string(n.Value) + n.Expr.JS()
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n TemplatePart) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write(n.Value)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Expr.JSWriteTo(w)
+ i += wn
+ return
+}
+
+// TemplateExpr is a template literal or member/call expression, super property, or optional chain with template literal.
+type TemplateExpr struct {
+ Tag IExpr // can be nil
+ List []TemplatePart
+ Tail []byte
+ Prec OpPrec
+ Optional bool
+}
+
+func (n TemplateExpr) String() string {
+ s := ""
+ if n.Tag != nil {
+ s += n.Tag.String()
+ if n.Optional {
+ s += "?."
+ }
+ }
+ for _, item := range n.List {
+ s += item.String()
+ }
+ return s + string(n.Tail)
+}
+
+// JS converts the node back to valid JavaScript
+func (n TemplateExpr) JS() string {
+ s := ""
+ if n.Tag != nil {
+ s += n.Tag.JS()
+ if n.Optional {
+ s += "?."
+ }
+ }
+ for _, item := range n.List {
+ s += item.JS()
+ }
+ return s + string(n.Tail)
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n TemplateExpr) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ if n.Tag != nil {
+ wn, err = n.Tag.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ if n.Optional {
+ wn, err = w.Write([]byte("?."))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ }
+ for _, item := range n.List {
+ wn, err = item.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = w.Write(n.Tail)
+ i += wn
+ return
+}
+
+// GroupExpr is a parenthesized expression.
+type GroupExpr struct {
+ X IExpr
+}
+
+func (n GroupExpr) String() string {
+ return "(" + n.X.String() + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n GroupExpr) JS() string {
+ return "(" + n.X.JS() + ")"
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n GroupExpr) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write([]byte("("))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.X.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(")"))
+ i += wn
+ return
+}
+
+// IndexExpr is a member/call expression, super property, or optional chain with an index expression.
+type IndexExpr struct {
+ X IExpr
+ Y IExpr
+ Prec OpPrec
+ Optional bool
+}
+
+func (n IndexExpr) String() string {
+ if n.Optional {
+ return "(" + n.X.String() + "?.[" + n.Y.String() + "])"
+ }
+ return "(" + n.X.String() + "[" + n.Y.String() + "])"
+}
+
+// JS converts the node back to valid JavaScript
+func (n IndexExpr) JS() string {
+ if n.Optional {
+ return n.X.JS() + "?.[" + n.Y.JS() + "]"
+ }
+ return n.X.JS() + "[" + n.Y.JS() + "]"
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n IndexExpr) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = n.X.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ if n.Optional {
+ wn, err = w.Write([]byte("?.["))
+ i += wn
+ if err != nil {
+ return
+ }
+ } else {
+ wn, err = w.Write([]byte("["))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = n.Y.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte("]"))
+ i += wn
+ return
+}
+
+// DotExpr is a member/call expression, super property, or optional chain with a dot expression.
+type DotExpr struct {
+ X IExpr
+ Y LiteralExpr
+ Prec OpPrec
+ Optional bool
+}
+
+func (n DotExpr) String() string {
+ if n.Optional {
+ return "(" + n.X.String() + "?." + n.Y.String() + ")"
+ }
+ return "(" + n.X.String() + "." + n.Y.String() + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n DotExpr) JS() string {
+ if n.Optional {
+ return n.X.JS() + "?." + n.Y.JS()
+ }
+ return n.X.JS() + "." + n.Y.JS()
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n DotExpr) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = n.X.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ if n.Optional {
+ wn, err = w.Write([]byte("?."))
+ i += wn
+ if err != nil {
+ return
+ }
+ } else {
+ wn, err = w.Write([]byte("."))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = n.Y.JSWriteTo(w)
+ i += wn
+ return
+}
+
+// NewTargetExpr is a new target meta property.
+type NewTargetExpr struct {
+}
+
+func (n NewTargetExpr) String() string {
+ return "(new.target)"
+}
+
+// JS converts the node back to valid JavaScript
+func (n NewTargetExpr) JS() string {
+ return "new.target"
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n NewTargetExpr) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write([]byte("new.target"))
+ i += wn
+ return
+}
+
+// ImportMetaExpr is a import meta meta property.
+type ImportMetaExpr struct {
+}
+
+func (n ImportMetaExpr) String() string {
+ return "(import.meta)"
+}
+
+// JS converts the node back to valid JavaScript
+func (n ImportMetaExpr) JS() string {
+ return "import.meta"
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n ImportMetaExpr) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write([]byte("import.meta"))
+ i += wn
+ return
+}
+
+type Arg struct {
+ Value IExpr
+ Rest bool
+}
+
+func (n Arg) String() string {
+ s := ""
+ if n.Rest {
+ s += "..."
+ }
+ return s + n.Value.String()
+}
+
+// JS converts the node back to valid JavaScript
+func (n Arg) JS() string {
+ s := ""
+ if n.Rest {
+ s += "..."
+ }
+ return s + n.Value.JS()
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n Arg) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ if n.Rest {
+ wn, err = w.Write([]byte("..."))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = n.Value.JSWriteTo(w)
+ i += wn
+ return
+}
+
+// Args is a list of arguments as used by new and call expressions.
+type Args struct {
+ List []Arg
+}
+
+func (n Args) String() string {
+ s := "("
+ for i, item := range n.List {
+ if i != 0 {
+ s += ", "
+ }
+ s += item.String()
+ }
+ return s + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n Args) JS() string {
+ s := ""
+ for i, item := range n.List {
+ if i != 0 {
+ s += ", "
+ }
+ s += item.JS()
+ }
+ return s
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n Args) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ for j, item := range n.List {
+ if j != 0 {
+ wn, err = w.Write([]byte(", "))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = item.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ return
+}
+
+// NewExpr is a new expression or new member expression.
+type NewExpr struct {
+ X IExpr
+ Args *Args // can be nil
+}
+
+func (n NewExpr) String() string {
+ if n.Args != nil {
+ return "(new " + n.X.String() + n.Args.String() + ")"
+ }
+ return "(new " + n.X.String() + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n NewExpr) JS() string {
+ if n.Args != nil {
+ return "new " + n.X.JS() + "(" + n.Args.JS() + ")"
+ }
+
+ // always use parentheses to prevent errors when chaining e.g. new Date().getTime()
+ return "new " + n.X.JS() + "()"
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n NewExpr) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write([]byte("new "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.X.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ if n.Args != nil {
+ wn, err = w.Write([]byte("("))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Args.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(")"))
+ i += wn
+ if err != nil {
+ return
+ }
+ } else {
+ wn, err = w.Write([]byte("()"))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ return
+}
+
+// CallExpr is a call expression.
+type CallExpr struct {
+ X IExpr
+ Args Args
+ Optional bool
+}
+
+func (n CallExpr) String() string {
+ if n.Optional {
+ return "(" + n.X.String() + "?." + n.Args.String() + ")"
+ }
+ return "(" + n.X.String() + n.Args.String() + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n CallExpr) JS() string {
+ if n.Optional {
+ return n.X.JS() + "?.(" + n.Args.JS() + ")"
+ }
+ return n.X.JS() + "(" + n.Args.JS() + ")"
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n CallExpr) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = n.X.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ if n.Optional {
+ wn, err = w.Write([]byte("?.("))
+ i += wn
+ if err != nil {
+ return
+ }
+ } else {
+ wn, err = w.Write([]byte("("))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = n.Args.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(")"))
+ i += wn
+ if err != nil {
+ return
+ }
+ return
+}
+
+// UnaryExpr is an update or unary expression.
+type UnaryExpr struct {
+ Op TokenType
+ X IExpr
+}
+
+func (n UnaryExpr) String() string {
+ if n.Op == PostIncrToken || n.Op == PostDecrToken {
+ return "(" + n.X.String() + n.Op.String() + ")"
+ } else if IsIdentifierName(n.Op) {
+ return "(" + n.Op.String() + " " + n.X.String() + ")"
+ }
+ return "(" + n.Op.String() + n.X.String() + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n UnaryExpr) JS() string {
+ if n.Op == PostIncrToken || n.Op == PostDecrToken {
+ return n.X.JS() + n.Op.String()
+ } else if IsIdentifierName(n.Op) {
+ return n.Op.String() + " " + n.X.JS()
+ }
+ return n.Op.String() + n.X.JS()
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n UnaryExpr) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ if n.Op == PostIncrToken || n.Op == PostDecrToken {
+ wn, err = n.X.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write(n.Op.Bytes())
+ i += wn
+ return
+ } else if IsIdentifierName(n.Op) {
+ wn, err = w.Write(n.Op.Bytes())
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(" "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.X.JSWriteTo(w)
+ i += wn
+ return
+ }
+ wn, err = w.Write(n.Op.Bytes())
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.X.JSWriteTo(w)
+ i += wn
+ return
+}
+
+// JSON converts the node back to valid JSON
+func (n UnaryExpr) JSON(buf *bytes.Buffer) error {
+ if lit, ok := n.X.(*LiteralExpr); ok && n.Op == NegToken && lit.TokenType == DecimalToken {
+ buf.WriteByte('-')
+ buf.Write(lit.Data)
+ return nil
+ }
+ return ErrInvalidJSON
+}
+
+// BinaryExpr is a binary expression.
+type BinaryExpr struct {
+ Op TokenType
+ X, Y IExpr
+}
+
+func (n BinaryExpr) String() string {
+ if IsIdentifierName(n.Op) {
+ return "(" + n.X.String() + " " + n.Op.String() + " " + n.Y.String() + ")"
+ }
+ return "(" + n.X.String() + n.Op.String() + n.Y.String() + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n BinaryExpr) JS() string {
+ return n.X.JS() + " " + n.Op.String() + " " + n.Y.JS()
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n BinaryExpr) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = n.X.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(" "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write(n.Op.Bytes())
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(" "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Y.JSWriteTo(w)
+ i += wn
+ return
+}
+
+// CondExpr is a conditional expression.
+type CondExpr struct {
+ Cond, X, Y IExpr
+}
+
+func (n CondExpr) String() string {
+ return "(" + n.Cond.String() + " ? " + n.X.String() + " : " + n.Y.String() + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n CondExpr) JS() string {
+ return n.Cond.JS() + " ? " + n.X.JS() + " : " + n.Y.JS()
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n CondExpr) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = n.Cond.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(" ? "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.X.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(" : "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Y.JSWriteTo(w)
+ i += wn
+ return
+}
+
+// YieldExpr is a yield expression.
+type YieldExpr struct {
+ Generator bool
+ X IExpr // can be nil
+}
+
+func (n YieldExpr) String() string {
+ if n.X == nil {
+ return "(yield)"
+ }
+ s := "(yield"
+ if n.Generator {
+ s += "*"
+ }
+ return s + " " + n.X.String() + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n YieldExpr) JS() string {
+ if n.X == nil {
+ return "yield"
+ }
+ s := "yield"
+ if n.Generator {
+ s += "*"
+ }
+ return s + " " + n.X.JS()
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n YieldExpr) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ wn, err = w.Write([]byte("yield"))
+ i += wn
+ if err != nil {
+ return
+ }
+ if n.X == nil {
+ return
+ }
+ if n.Generator {
+ wn, err = w.Write([]byte("*"))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = w.Write([]byte(" "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.X.JSWriteTo(w)
+ i += wn
+ return
+}
+
+// ArrowFunc is an (async) arrow function.
+type ArrowFunc struct {
+ Async bool
+ Params Params
+ Body BlockStmt
+}
+
+func (n ArrowFunc) String() string {
+ s := "("
+ if n.Async {
+ s += "async "
+ }
+ return s + n.Params.String() + " => " + n.Body.String() + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n ArrowFunc) JS() string {
+ s := ""
+ if n.Async {
+ s += "async "
+ }
+ return s + n.Params.JS() + " => " + n.Body.JS()
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n ArrowFunc) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ if n.Async {
+ wn, err = w.Write([]byte("async "))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = n.Params.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = w.Write([]byte(" => "))
+ i += wn
+ if err != nil {
+ return
+ }
+ wn, err = n.Body.JSWriteTo(w)
+ i += wn
+ return
+}
+
+// CommaExpr is a series of comma expressions.
+type CommaExpr struct {
+ List []IExpr
+}
+
+func (n CommaExpr) String() string {
+ s := "("
+ for i, item := range n.List {
+ if i != 0 {
+ s += ","
+ }
+ s += item.String()
+ }
+ return s + ")"
+}
+
+// JS converts the node back to valid JavaScript
+func (n CommaExpr) JS() string {
+ s := ""
+ for i, item := range n.List {
+ if i != 0 {
+ s += ","
+ }
+ s += item.JS()
+ }
+ return s
+}
+
+// JS converts the node back to valid JavaScript (writes to io.Writer)
+func (n CommaExpr) JSWriteTo(w io.Writer) (i int, err error) {
+ var wn int
+ for j, item := range n.List {
+ if j != 0 {
+ wn, err = w.Write([]byte(","))
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ wn, err = item.JSWriteTo(w)
+ i += wn
+ if err != nil {
+ return
+ }
+ }
+ return
+}
+
+func (v *Var) exprNode() {}
+func (n LiteralExpr) exprNode() {}
+func (n ArrayExpr) exprNode() {}
+func (n ObjectExpr) exprNode() {}
+func (n TemplateExpr) exprNode() {}
+func (n GroupExpr) exprNode() {}
+func (n DotExpr) exprNode() {}
+func (n IndexExpr) exprNode() {}
+func (n NewTargetExpr) exprNode() {}
+func (n ImportMetaExpr) exprNode() {}
+func (n NewExpr) exprNode() {}
+func (n CallExpr) exprNode() {}
+func (n UnaryExpr) exprNode() {}
+func (n BinaryExpr) exprNode() {}
+func (n CondExpr) exprNode() {}
+func (n YieldExpr) exprNode() {}
+func (n ArrowFunc) exprNode() {}
+func (n CommaExpr) exprNode() {}