mirror of
https://github.com/robertkrimen/otto
synced 2025-10-12 20:27:30 +08:00

* (#257) Change Walk/Visit to follow an explicit Enter/Exit pattern * (#257) Convert walk example into test. * (#257) restore walk/visitor example * (#257) Fix godoc comment in the Visitor interface ... typo referred to `End` method instead of `Exit`
83 lines
1.6 KiB
Go
83 lines
1.6 KiB
Go
package ast_test
|
|
|
|
import (
|
|
"log"
|
|
"testing"
|
|
|
|
"github.com/robertkrimen/otto/ast"
|
|
"github.com/robertkrimen/otto/file"
|
|
"github.com/robertkrimen/otto/parser"
|
|
)
|
|
|
|
type walker struct {
|
|
stack []ast.Node
|
|
source string
|
|
shift file.Idx
|
|
}
|
|
|
|
// push and pop below are to prove the symmetry of Enter/Exit calls
|
|
|
|
func (w *walker) push(n ast.Node) {
|
|
w.stack = append(w.stack, n)
|
|
}
|
|
|
|
func (w *walker) pop(n ast.Node) {
|
|
size := len(w.stack)
|
|
if size <= 0 {
|
|
panic("pop of empty stack")
|
|
}
|
|
|
|
toPop := w.stack[size-1]
|
|
if toPop != n {
|
|
panic("pop: nodes do not equal")
|
|
}
|
|
|
|
w.stack[size-1] = nil
|
|
w.stack = w.stack[:size-1]
|
|
}
|
|
|
|
func (w *walker) Enter(n ast.Node) ast.Visitor {
|
|
w.push(n)
|
|
|
|
if id, ok := n.(*ast.Identifier); ok && id != nil {
|
|
idx := n.Idx0() + w.shift - 1
|
|
s := w.source[:idx] + "new_" + w.source[idx:]
|
|
w.source = s
|
|
w.shift += 4
|
|
}
|
|
if v, ok := n.(*ast.VariableExpression); ok && v != nil {
|
|
idx := n.Idx0() + w.shift - 1
|
|
s := w.source[:idx] + "varnew_" + w.source[idx:]
|
|
w.source = s
|
|
w.shift += 7
|
|
}
|
|
|
|
return w
|
|
}
|
|
|
|
func (w *walker) Exit(n ast.Node) {
|
|
w.pop(n)
|
|
}
|
|
|
|
func TestVisitorRewrite(t *testing.T) {
|
|
source := `var b = function() {test(); try {} catch(e) {} var test = "test(); var test = 1"} // test`
|
|
program, err := parser.ParseFile(nil, "", source, 0)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
w := &walker{source: source}
|
|
|
|
ast.Walk(w, program)
|
|
|
|
xformed := `var varnew_b = function() {new_test(); try {} catch(new_e) {} var varnew_test = "test(); var test = 1"} // test`
|
|
|
|
if w.source != xformed {
|
|
t.Errorf("source is `%s` not `%s`", w.source, xformed)
|
|
}
|
|
|
|
if len(w.stack) != 0 {
|
|
t.Errorf("stack should be empty, but is length: %d", len(w.stack))
|
|
}
|
|
}
|