mirror of
https://github.com/robertkrimen/otto
synced 2025-10-19 19:55:30 +08:00

Previously, it was a publically accessible but invalid value (valueEmpty). * Deprecate internal use of UndefinedValue(), NullValue(), FalseValue(), TrueValue() * Guard against Empty, Result, Reference values from escaping the package
631 lines
14 KiB
Go
631 lines
14 KiB
Go
package otto
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
|
|
"github.com/robertkrimen/otto/ast"
|
|
"github.com/robertkrimen/otto/token"
|
|
)
|
|
|
|
var trueLiteral = &_nodeLiteral{value: toValue_bool(true)}
|
|
var falseLiteral = &_nodeLiteral{value: toValue_bool(false)}
|
|
var nullLiteral = &_nodeLiteral{value: nullValue}
|
|
var emptyStatement = &_nodeEmptyStatement{}
|
|
|
|
func parseExpression(x ast.Expression) _nodeExpression {
|
|
if x == nil {
|
|
return nil
|
|
}
|
|
|
|
switch x := x.(type) {
|
|
|
|
case *ast.ArrayLiteral:
|
|
y := &_nodeArrayLiteral{
|
|
value: make([]_nodeExpression, len(x.Value)),
|
|
}
|
|
for i, value := range x.Value {
|
|
y.value[i] = parseExpression(value)
|
|
}
|
|
return y
|
|
|
|
case *ast.AssignExpression:
|
|
return &_nodeAssignExpression{
|
|
operator: x.Operator,
|
|
left: parseExpression(x.Left),
|
|
right: parseExpression(x.Right),
|
|
}
|
|
|
|
case *ast.BinaryExpression:
|
|
return &_nodeBinaryExpression{
|
|
operator: x.Operator,
|
|
left: parseExpression(x.Left),
|
|
right: parseExpression(x.Right),
|
|
comparison: x.Comparison,
|
|
}
|
|
|
|
case *ast.BooleanLiteral:
|
|
if x.Value {
|
|
return trueLiteral
|
|
}
|
|
return falseLiteral
|
|
|
|
case *ast.BracketExpression:
|
|
return &_nodeBracketExpression{
|
|
left: parseExpression(x.Left),
|
|
member: parseExpression(x.Member),
|
|
}
|
|
|
|
case *ast.CallExpression:
|
|
y := &_nodeCallExpression{
|
|
callee: parseExpression(x.Callee),
|
|
argumentList: make([]_nodeExpression, len(x.ArgumentList)),
|
|
}
|
|
for i, value := range x.ArgumentList {
|
|
y.argumentList[i] = parseExpression(value)
|
|
}
|
|
return y
|
|
|
|
case *ast.ConditionalExpression:
|
|
return &_nodeConditionalExpression{
|
|
test: parseExpression(x.Test),
|
|
consequent: parseExpression(x.Consequent),
|
|
alternate: parseExpression(x.Alternate),
|
|
}
|
|
|
|
case *ast.DotExpression:
|
|
return &_nodeDotExpression{
|
|
left: parseExpression(x.Left),
|
|
identifier: x.Identifier.Name,
|
|
}
|
|
|
|
case *ast.FunctionLiteral:
|
|
name := ""
|
|
if x.Name != nil {
|
|
name = x.Name.Name
|
|
}
|
|
y := &_nodeFunctionLiteral{
|
|
name: name,
|
|
body: parseStatement(x.Body),
|
|
source: x.Source,
|
|
}
|
|
if x.ParameterList != nil {
|
|
list := x.ParameterList.List
|
|
y.parameterList = make([]string, len(list))
|
|
for i, value := range list {
|
|
y.parameterList[i] = value.Name
|
|
}
|
|
}
|
|
for _, value := range x.DeclarationList {
|
|
switch value := value.(type) {
|
|
case *ast.FunctionDeclaration:
|
|
y.functionList = append(y.functionList, parseExpression(value.Function).(*_nodeFunctionLiteral))
|
|
case *ast.VariableDeclaration:
|
|
for _, value := range value.List {
|
|
y.varList = append(y.varList, value.Name)
|
|
}
|
|
default:
|
|
panic(fmt.Errorf("Here be dragons: parseProgram.declaration(%T)", value))
|
|
}
|
|
}
|
|
return y
|
|
|
|
case *ast.Identifier:
|
|
return &_nodeIdentifier{
|
|
name: x.Name,
|
|
}
|
|
|
|
case *ast.NewExpression:
|
|
y := &_nodeNewExpression{
|
|
callee: parseExpression(x.Callee),
|
|
argumentList: make([]_nodeExpression, len(x.ArgumentList)),
|
|
}
|
|
for i, value := range x.ArgumentList {
|
|
y.argumentList[i] = parseExpression(value)
|
|
}
|
|
return y
|
|
|
|
case *ast.NullLiteral:
|
|
return nullLiteral
|
|
|
|
case *ast.NumberLiteral:
|
|
return &_nodeLiteral{
|
|
value: toValue(x.Value),
|
|
}
|
|
|
|
case *ast.ObjectLiteral:
|
|
y := &_nodeObjectLiteral{
|
|
value: make([]_nodeProperty, len(x.Value)),
|
|
}
|
|
for i, value := range x.Value {
|
|
y.value[i] = _nodeProperty{
|
|
key: value.Key,
|
|
kind: value.Kind,
|
|
value: parseExpression(value.Value),
|
|
}
|
|
}
|
|
return y
|
|
|
|
case *ast.RegExpLiteral:
|
|
return &_nodeRegExpLiteral{
|
|
flags: x.Flags,
|
|
pattern: x.Pattern,
|
|
}
|
|
|
|
case *ast.SequenceExpression:
|
|
y := &_nodeSequenceExpression{
|
|
sequence: make([]_nodeExpression, len(x.Sequence)),
|
|
}
|
|
for i, value := range x.Sequence {
|
|
y.sequence[i] = parseExpression(value)
|
|
}
|
|
return y
|
|
|
|
case *ast.StringLiteral:
|
|
return &_nodeLiteral{
|
|
value: toValue_string(x.Value),
|
|
}
|
|
|
|
case *ast.ThisExpression:
|
|
return &_nodeThisExpression{}
|
|
|
|
case *ast.UnaryExpression:
|
|
return &_nodeUnaryExpression{
|
|
operator: x.Operator,
|
|
operand: parseExpression(x.Operand),
|
|
postfix: x.Postfix,
|
|
}
|
|
|
|
case *ast.VariableExpression:
|
|
return &_nodeVariableExpression{
|
|
name: x.Name,
|
|
initializer: parseExpression(x.Initializer),
|
|
}
|
|
|
|
}
|
|
|
|
panic(fmt.Errorf("Here be dragons: parseExpression(%T)", x))
|
|
}
|
|
|
|
func parseStatement(x ast.Statement) _nodeStatement {
|
|
if x == nil {
|
|
return nil
|
|
}
|
|
|
|
switch x := x.(type) {
|
|
|
|
case *ast.BlockStatement:
|
|
y := &_nodeBlockStatement{
|
|
list: make([]_nodeStatement, len(x.List)),
|
|
}
|
|
for i, value := range x.List {
|
|
y.list[i] = parseStatement(value)
|
|
}
|
|
return y
|
|
|
|
case *ast.BranchStatement:
|
|
y := &_nodeBranchStatement{
|
|
branch: x.Token,
|
|
}
|
|
if x.Label != nil {
|
|
y.label = x.Label.Name
|
|
}
|
|
return y
|
|
|
|
case *ast.DebuggerStatement:
|
|
return &_nodeDebuggerStatement{}
|
|
|
|
case *ast.DoWhileStatement:
|
|
y := &_nodeDoWhileStatement{
|
|
test: parseExpression(x.Test),
|
|
}
|
|
body := parseStatement(x.Body)
|
|
if block, ok := body.(*_nodeBlockStatement); ok {
|
|
y.body = block.list
|
|
} else {
|
|
y.body = append(y.body, body)
|
|
}
|
|
return y
|
|
|
|
case *ast.EmptyStatement:
|
|
return emptyStatement
|
|
|
|
case *ast.ExpressionStatement:
|
|
return &_nodeExpressionStatement{
|
|
expression: parseExpression(x.Expression),
|
|
}
|
|
|
|
case *ast.ForInStatement:
|
|
y := &_nodeForInStatement{
|
|
into: parseExpression(x.Into),
|
|
source: parseExpression(x.Source),
|
|
}
|
|
body := parseStatement(x.Body)
|
|
if block, ok := body.(*_nodeBlockStatement); ok {
|
|
y.body = block.list
|
|
} else {
|
|
y.body = append(y.body, body)
|
|
}
|
|
return y
|
|
|
|
case *ast.ForStatement:
|
|
y := &_nodeForStatement{
|
|
initializer: parseExpression(x.Initializer),
|
|
update: parseExpression(x.Update),
|
|
test: parseExpression(x.Test),
|
|
}
|
|
body := parseStatement(x.Body)
|
|
if block, ok := body.(*_nodeBlockStatement); ok {
|
|
y.body = block.list
|
|
} else {
|
|
y.body = append(y.body, body)
|
|
}
|
|
return y
|
|
|
|
case *ast.IfStatement:
|
|
return &_nodeIfStatement{
|
|
test: parseExpression(x.Test),
|
|
consequent: parseStatement(x.Consequent),
|
|
alternate: parseStatement(x.Alternate),
|
|
}
|
|
|
|
case *ast.LabelledStatement:
|
|
return &_nodeLabelledStatement{
|
|
label: x.Label.Name,
|
|
statement: parseStatement(x.Statement),
|
|
}
|
|
|
|
case *ast.ReturnStatement:
|
|
return &_nodeReturnStatement{
|
|
argument: parseExpression(x.Argument),
|
|
}
|
|
|
|
case *ast.SwitchStatement:
|
|
y := &_nodeSwitchStatement{
|
|
discriminant: parseExpression(x.Discriminant),
|
|
default_: x.Default,
|
|
body: make([]*_nodeCaseStatement, len(x.Body)),
|
|
}
|
|
for i, p := range x.Body {
|
|
q := &_nodeCaseStatement{
|
|
test: parseExpression(p.Test),
|
|
consequent: make([]_nodeStatement, len(p.Consequent)),
|
|
}
|
|
for j, value := range p.Consequent {
|
|
q.consequent[j] = parseStatement(value)
|
|
}
|
|
y.body[i] = q
|
|
}
|
|
return y
|
|
|
|
case *ast.ThrowStatement:
|
|
return &_nodeThrowStatement{
|
|
argument: parseExpression(x.Argument),
|
|
}
|
|
|
|
case *ast.TryStatement:
|
|
y := &_nodeTryStatement{
|
|
body: parseStatement(x.Body),
|
|
finally: parseStatement(x.Finally),
|
|
}
|
|
if x.Catch != nil {
|
|
y.catch = &_nodeCatchStatement{
|
|
parameter: x.Catch.Parameter.Name,
|
|
body: parseStatement(x.Catch.Body),
|
|
}
|
|
}
|
|
return y
|
|
|
|
case *ast.VariableStatement:
|
|
y := &_nodeVariableStatement{
|
|
list: make([]_nodeExpression, len(x.List)),
|
|
}
|
|
for i, value := range x.List {
|
|
y.list[i] = parseExpression(value)
|
|
}
|
|
return y
|
|
|
|
case *ast.WhileStatement:
|
|
y := &_nodeWhileStatement{
|
|
test: parseExpression(x.Test),
|
|
}
|
|
body := parseStatement(x.Body)
|
|
if block, ok := body.(*_nodeBlockStatement); ok {
|
|
y.body = block.list
|
|
} else {
|
|
y.body = append(y.body, body)
|
|
}
|
|
return y
|
|
|
|
case *ast.WithStatement:
|
|
return &_nodeWithStatement{
|
|
object: parseExpression(x.Object),
|
|
body: parseStatement(x.Body),
|
|
}
|
|
|
|
}
|
|
|
|
panic(fmt.Errorf("Here be dragons: parseStatement(%T)", x))
|
|
}
|
|
|
|
func cmpl_parse(x *ast.Program) *_nodeProgram {
|
|
y := &_nodeProgram{
|
|
body: make([]_nodeStatement, len(x.Body)),
|
|
}
|
|
for i, value := range x.Body {
|
|
y.body[i] = parseStatement(value)
|
|
}
|
|
for _, value := range x.DeclarationList {
|
|
switch value := value.(type) {
|
|
case *ast.FunctionDeclaration:
|
|
y.functionList = append(y.functionList, parseExpression(value.Function).(*_nodeFunctionLiteral))
|
|
case *ast.VariableDeclaration:
|
|
for _, value := range value.List {
|
|
y.varList = append(y.varList, value.Name)
|
|
}
|
|
default:
|
|
panic(fmt.Errorf("Here be dragons: parseProgram.DeclarationList(%T)", value))
|
|
}
|
|
}
|
|
return y
|
|
}
|
|
|
|
type _nodeProgram struct {
|
|
body []_nodeStatement
|
|
|
|
varList []string
|
|
functionList []*_nodeFunctionLiteral
|
|
|
|
variableList []_nodeDeclaration
|
|
}
|
|
|
|
type _nodeDeclaration struct {
|
|
name string
|
|
definition _node
|
|
}
|
|
|
|
type _node interface {
|
|
}
|
|
|
|
type (
|
|
_nodeExpression interface {
|
|
_node
|
|
_expressionNode()
|
|
}
|
|
|
|
_nodeArrayLiteral struct {
|
|
value []_nodeExpression
|
|
}
|
|
|
|
_nodeAssignExpression struct {
|
|
operator token.Token
|
|
left _nodeExpression
|
|
right _nodeExpression
|
|
}
|
|
|
|
_nodeBinaryExpression struct {
|
|
operator token.Token
|
|
left _nodeExpression
|
|
right _nodeExpression
|
|
comparison bool
|
|
}
|
|
|
|
_nodeBracketExpression struct {
|
|
left _nodeExpression
|
|
member _nodeExpression
|
|
}
|
|
|
|
_nodeCallExpression struct {
|
|
callee _nodeExpression
|
|
argumentList []_nodeExpression
|
|
}
|
|
|
|
_nodeConditionalExpression struct {
|
|
test _nodeExpression
|
|
consequent _nodeExpression
|
|
alternate _nodeExpression
|
|
}
|
|
|
|
_nodeDotExpression struct {
|
|
left _nodeExpression
|
|
identifier string
|
|
}
|
|
|
|
_nodeFunctionLiteral struct {
|
|
name string
|
|
body _nodeStatement
|
|
source string
|
|
parameterList []string
|
|
varList []string
|
|
functionList []*_nodeFunctionLiteral
|
|
}
|
|
|
|
_nodeIdentifier struct {
|
|
name string
|
|
}
|
|
|
|
_nodeLiteral struct {
|
|
value Value
|
|
}
|
|
|
|
_nodeNewExpression struct {
|
|
callee _nodeExpression
|
|
argumentList []_nodeExpression
|
|
}
|
|
|
|
_nodeObjectLiteral struct {
|
|
value []_nodeProperty
|
|
}
|
|
|
|
_nodeProperty struct {
|
|
key string
|
|
kind string
|
|
value _nodeExpression
|
|
}
|
|
|
|
_nodeRegExpLiteral struct {
|
|
flags string
|
|
pattern string // Value?
|
|
regexp *regexp.Regexp
|
|
}
|
|
|
|
_nodeSequenceExpression struct {
|
|
sequence []_nodeExpression
|
|
}
|
|
|
|
_nodeThisExpression struct {
|
|
}
|
|
|
|
_nodeUnaryExpression struct {
|
|
operator token.Token
|
|
operand _nodeExpression
|
|
postfix bool
|
|
}
|
|
|
|
_nodeVariableExpression struct {
|
|
name string
|
|
initializer _nodeExpression
|
|
}
|
|
)
|
|
|
|
type (
|
|
_nodeStatement interface {
|
|
_node
|
|
_statementNode()
|
|
}
|
|
|
|
_nodeBlockStatement struct {
|
|
list []_nodeStatement
|
|
}
|
|
|
|
_nodeBranchStatement struct {
|
|
branch token.Token
|
|
label string
|
|
}
|
|
|
|
_nodeCaseStatement struct {
|
|
test _nodeExpression
|
|
consequent []_nodeStatement
|
|
}
|
|
|
|
_nodeCatchStatement struct {
|
|
parameter string
|
|
body _nodeStatement
|
|
}
|
|
|
|
_nodeDebuggerStatement struct {
|
|
}
|
|
|
|
_nodeDoWhileStatement struct {
|
|
test _nodeExpression
|
|
body []_nodeStatement
|
|
}
|
|
|
|
_nodeEmptyStatement struct {
|
|
}
|
|
|
|
_nodeExpressionStatement struct {
|
|
expression _nodeExpression
|
|
}
|
|
|
|
_nodeForInStatement struct {
|
|
into _nodeExpression
|
|
source _nodeExpression
|
|
body []_nodeStatement
|
|
}
|
|
|
|
_nodeForStatement struct {
|
|
initializer _nodeExpression
|
|
update _nodeExpression
|
|
test _nodeExpression
|
|
body []_nodeStatement
|
|
}
|
|
|
|
_nodeIfStatement struct {
|
|
test _nodeExpression
|
|
consequent _nodeStatement
|
|
alternate _nodeStatement
|
|
}
|
|
|
|
_nodeLabelledStatement struct {
|
|
label string
|
|
statement _nodeStatement
|
|
}
|
|
|
|
_nodeReturnStatement struct {
|
|
argument _nodeExpression
|
|
}
|
|
|
|
_nodeSwitchStatement struct {
|
|
discriminant _nodeExpression
|
|
default_ int
|
|
body []*_nodeCaseStatement
|
|
}
|
|
|
|
_nodeThrowStatement struct {
|
|
argument _nodeExpression
|
|
}
|
|
|
|
_nodeTryStatement struct {
|
|
body _nodeStatement
|
|
catch *_nodeCatchStatement
|
|
finally _nodeStatement
|
|
}
|
|
|
|
_nodeVariableStatement struct {
|
|
list []_nodeExpression
|
|
}
|
|
|
|
_nodeWhileStatement struct {
|
|
test _nodeExpression
|
|
body []_nodeStatement
|
|
}
|
|
|
|
_nodeWithStatement struct {
|
|
object _nodeExpression
|
|
body _nodeStatement
|
|
}
|
|
)
|
|
|
|
// _expressionNode
|
|
|
|
func (*_nodeArrayLiteral) _expressionNode() {}
|
|
func (*_nodeAssignExpression) _expressionNode() {}
|
|
func (*_nodeBinaryExpression) _expressionNode() {}
|
|
func (*_nodeBracketExpression) _expressionNode() {}
|
|
func (*_nodeCallExpression) _expressionNode() {}
|
|
func (*_nodeConditionalExpression) _expressionNode() {}
|
|
func (*_nodeDotExpression) _expressionNode() {}
|
|
func (*_nodeFunctionLiteral) _expressionNode() {}
|
|
func (*_nodeIdentifier) _expressionNode() {}
|
|
func (*_nodeLiteral) _expressionNode() {}
|
|
func (*_nodeNewExpression) _expressionNode() {}
|
|
func (*_nodeObjectLiteral) _expressionNode() {}
|
|
func (*_nodeRegExpLiteral) _expressionNode() {}
|
|
func (*_nodeSequenceExpression) _expressionNode() {}
|
|
func (*_nodeThisExpression) _expressionNode() {}
|
|
func (*_nodeUnaryExpression) _expressionNode() {}
|
|
func (*_nodeVariableExpression) _expressionNode() {}
|
|
|
|
// _statementNode
|
|
|
|
func (*_nodeBlockStatement) _statementNode() {}
|
|
func (*_nodeBranchStatement) _statementNode() {}
|
|
func (*_nodeCaseStatement) _statementNode() {}
|
|
func (*_nodeCatchStatement) _statementNode() {}
|
|
func (*_nodeDebuggerStatement) _statementNode() {}
|
|
func (*_nodeDoWhileStatement) _statementNode() {}
|
|
func (*_nodeEmptyStatement) _statementNode() {}
|
|
func (*_nodeExpressionStatement) _statementNode() {}
|
|
func (*_nodeForInStatement) _statementNode() {}
|
|
func (*_nodeForStatement) _statementNode() {}
|
|
func (*_nodeIfStatement) _statementNode() {}
|
|
func (*_nodeLabelledStatement) _statementNode() {}
|
|
func (*_nodeReturnStatement) _statementNode() {}
|
|
func (*_nodeSwitchStatement) _statementNode() {}
|
|
func (*_nodeThrowStatement) _statementNode() {}
|
|
func (*_nodeTryStatement) _statementNode() {}
|
|
func (*_nodeVariableStatement) _statementNode() {}
|
|
func (*_nodeWhileStatement) _statementNode() {}
|
|
func (*_nodeWithStatement) _statementNode() {}
|