mirror of
https://github.com/robertkrimen/otto
synced 2025-10-12 20:27:30 +08:00
fix(ast): walk missing nodes (#471)
Fix ast.Walk missing out: * DotExpressions.Identifier * LabelledStatement.Label Fixes #299
This commit is contained in:
parent
8d121dcad1
commit
93fb47cccc
|
@ -93,6 +93,7 @@ func Walk(v Visitor, n Node) {
|
||||||
case *DotExpression:
|
case *DotExpression:
|
||||||
if n != nil {
|
if n != nil {
|
||||||
Walk(v, n.Left)
|
Walk(v, n.Left)
|
||||||
|
Walk(v, n.Identifier)
|
||||||
}
|
}
|
||||||
case *EmptyExpression:
|
case *EmptyExpression:
|
||||||
case *EmptyStatement:
|
case *EmptyStatement:
|
||||||
|
@ -134,6 +135,7 @@ func Walk(v Visitor, n Node) {
|
||||||
}
|
}
|
||||||
case *LabelledStatement:
|
case *LabelledStatement:
|
||||||
if n != nil {
|
if n != nil {
|
||||||
|
Walk(v, n.Label)
|
||||||
Walk(v, n.Statement)
|
Walk(v, n.Statement)
|
||||||
}
|
}
|
||||||
case *NewExpression:
|
case *NewExpression:
|
||||||
|
|
|
@ -1,18 +1,20 @@
|
||||||
package ast_test
|
package ast_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/robertkrimen/otto/ast"
|
"github.com/robertkrimen/otto/ast"
|
||||||
"github.com/robertkrimen/otto/file"
|
"github.com/robertkrimen/otto/file"
|
||||||
"github.com/robertkrimen/otto/parser"
|
"github.com/robertkrimen/otto/parser"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
type walker struct {
|
type walker struct {
|
||||||
stack []ast.Node
|
stack []ast.Node
|
||||||
source string
|
source string
|
||||||
shift file.Idx
|
shift file.Idx
|
||||||
|
seen map[ast.Node]struct{}
|
||||||
|
duplicate int
|
||||||
}
|
}
|
||||||
|
|
||||||
// push and pop below are to prove the symmetry of Enter/Exit calls
|
// push and pop below are to prove the symmetry of Enter/Exit calls
|
||||||
|
@ -38,18 +40,25 @@ func (w *walker) pop(n ast.Node) {
|
||||||
|
|
||||||
func (w *walker) Enter(n ast.Node) ast.Visitor {
|
func (w *walker) Enter(n ast.Node) ast.Visitor {
|
||||||
w.push(n)
|
w.push(n)
|
||||||
|
if _, ok := w.seen[n]; ok {
|
||||||
|
// Skip items we've already seen which occurs due to declarations.
|
||||||
|
w.duplicate++
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
|
w.seen[n] = struct{}{}
|
||||||
|
|
||||||
if id, ok := n.(*ast.Identifier); ok && id != nil {
|
if id, ok := n.(*ast.Identifier); ok && id != nil {
|
||||||
idx := n.Idx0() + w.shift - 1
|
idx := n.Idx0() + w.shift - 1
|
||||||
s := w.source[:idx] + "new_" + w.source[idx:]
|
s := w.source[:idx] + "IDENT_" + w.source[idx:]
|
||||||
w.source = s
|
w.source = s
|
||||||
w.shift += 4
|
w.shift += 6
|
||||||
}
|
}
|
||||||
if v, ok := n.(*ast.VariableExpression); ok && v != nil {
|
if v, ok := n.(*ast.VariableExpression); ok && v != nil {
|
||||||
idx := n.Idx0() + w.shift - 1
|
idx := n.Idx0() + w.shift - 1
|
||||||
s := w.source[:idx] + "varnew_" + w.source[idx:]
|
s := w.source[:idx] + "VAR_" + w.source[idx:]
|
||||||
w.source = s
|
w.source = s
|
||||||
w.shift += 7
|
w.shift += 4
|
||||||
}
|
}
|
||||||
|
|
||||||
return w
|
return w
|
||||||
|
@ -60,23 +69,27 @@ func (w *walker) Exit(n ast.Node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVisitorRewrite(t *testing.T) {
|
func TestVisitorRewrite(t *testing.T) {
|
||||||
source := `var b = function() {test(); try {} catch(e) {} var test = "test(); var test = 1"} // test`
|
source := `var b = function() {
|
||||||
|
test();
|
||||||
|
try {} catch(e) {}
|
||||||
|
var test = "test(); var test = 1"
|
||||||
|
} // test`
|
||||||
program, err := parser.ParseFile(nil, "", source, 0)
|
program, err := parser.ParseFile(nil, "", source, 0)
|
||||||
if err != nil {
|
require.NoError(t, err)
|
||||||
log.Fatal(err)
|
|
||||||
|
w := &walker{
|
||||||
|
source: source,
|
||||||
|
seen: make(map[ast.Node]struct{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
w := &walker{source: source}
|
|
||||||
|
|
||||||
ast.Walk(w, program)
|
ast.Walk(w, program)
|
||||||
|
|
||||||
xformed := `var varnew_b = function() {new_test(); try {} catch(new_e) {} var varnew_test = "test(); var test = 1"} // test`
|
xformed := `var VAR_b = function() {
|
||||||
|
IDENT_test();
|
||||||
|
try {} catch(IDENT_e) {}
|
||||||
|
var VAR_test = "test(); var test = 1"
|
||||||
|
} // test`
|
||||||
|
|
||||||
if w.source != xformed {
|
require.Equal(t, xformed, w.source)
|
||||||
t.Errorf("source is `%s` not `%s`", w.source, xformed)
|
require.Len(t, w.stack, 0)
|
||||||
}
|
require.Equal(t, w.duplicate, 0)
|
||||||
|
|
||||||
if len(w.stack) != 0 {
|
|
||||||
t.Errorf("stack should be empty, but is length: %d", len(w.stack))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user