From c6cc0108ca7738023b45e0eeac0fa2390532dd93 Mon Sep 17 00:00:00 2001 From: Mitja Felicijan Date: Fri, 25 Oct 2024 00:47:47 +0200 Subject: Added vendor lock on deps --- vendor/github.com/tdewolff/parse/v2/js/ast.go | 3884 +++++++++++++++++++++++++ 1 file changed, 3884 insertions(+) create mode 100644 vendor/github.com/tdewolff/parse/v2/js/ast.go (limited to 'vendor/github.com/tdewolff/parse/v2/js/ast.go') 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() {} -- cgit v1.2.3