rum-goggles/v1/vendor/github.com/robertkrimen/otto/cmpl_parse.go

645 lines
15 KiB
Go
Raw Permalink Normal View History

package otto
import (
"fmt"
"github.com/robertkrimen/otto/ast"
"github.com/robertkrimen/otto/file"
"github.com/robertkrimen/otto/token"
)
2024-04-04 14:46:14 +00:00
var (
trueLiteral = &nodeLiteral{value: boolValue(true)}
falseLiteral = &nodeLiteral{value: boolValue(false)}
nullLiteral = &nodeLiteral{value: nullValue}
emptyStatement = &nodeEmptyStatement{}
)
2024-04-04 14:46:14 +00:00
func (cmpl *compiler) parseExpression(expr ast.Expression) nodeExpression {
if expr == nil {
return nil
}
2024-04-04 14:46:14 +00:00
switch expr := expr.(type) {
case *ast.ArrayLiteral:
2024-04-04 14:46:14 +00:00
out := &nodeArrayLiteral{
value: make([]nodeExpression, len(expr.Value)),
}
2024-04-04 14:46:14 +00:00
for i, value := range expr.Value {
out.value[i] = cmpl.parseExpression(value)
}
return out
case *ast.AssignExpression:
2024-04-04 14:46:14 +00:00
return &nodeAssignExpression{
operator: expr.Operator,
left: cmpl.parseExpression(expr.Left),
right: cmpl.parseExpression(expr.Right),
}
case *ast.BinaryExpression:
2024-04-04 14:46:14 +00:00
return &nodeBinaryExpression{
operator: expr.Operator,
left: cmpl.parseExpression(expr.Left),
right: cmpl.parseExpression(expr.Right),
comparison: expr.Comparison,
}
case *ast.BooleanLiteral:
2024-04-04 14:46:14 +00:00
if expr.Value {
return trueLiteral
}
return falseLiteral
case *ast.BracketExpression:
2024-04-04 14:46:14 +00:00
return &nodeBracketExpression{
idx: expr.Left.Idx0(),
left: cmpl.parseExpression(expr.Left),
member: cmpl.parseExpression(expr.Member),
}
case *ast.CallExpression:
2024-04-04 14:46:14 +00:00
out := &nodeCallExpression{
callee: cmpl.parseExpression(expr.Callee),
argumentList: make([]nodeExpression, len(expr.ArgumentList)),
}
2024-04-04 14:46:14 +00:00
for i, value := range expr.ArgumentList {
out.argumentList[i] = cmpl.parseExpression(value)
}
return out
case *ast.ConditionalExpression:
2024-04-04 14:46:14 +00:00
return &nodeConditionalExpression{
test: cmpl.parseExpression(expr.Test),
consequent: cmpl.parseExpression(expr.Consequent),
alternate: cmpl.parseExpression(expr.Alternate),
}
case *ast.DotExpression:
2024-04-04 14:46:14 +00:00
return &nodeDotExpression{
idx: expr.Left.Idx0(),
left: cmpl.parseExpression(expr.Left),
identifier: expr.Identifier.Name,
}
case *ast.EmptyExpression:
return nil
case *ast.FunctionLiteral:
name := ""
2024-04-04 14:46:14 +00:00
if expr.Name != nil {
name = expr.Name.Name
}
2024-04-04 14:46:14 +00:00
out := &nodeFunctionLiteral{
name: name,
2024-04-04 14:46:14 +00:00
body: cmpl.parseStatement(expr.Body),
source: expr.Source,
file: cmpl.file,
}
2024-04-04 14:46:14 +00:00
if expr.ParameterList != nil {
list := expr.ParameterList.List
out.parameterList = make([]string, len(list))
for i, value := range list {
out.parameterList[i] = value.Name
}
}
2024-04-04 14:46:14 +00:00
for _, value := range expr.DeclarationList {
switch value := value.(type) {
case *ast.FunctionDeclaration:
2024-04-04 14:46:14 +00:00
out.functionList = append(out.functionList, cmpl.parseExpression(value.Function).(*nodeFunctionLiteral))
case *ast.VariableDeclaration:
for _, value := range value.List {
out.varList = append(out.varList, value.Name)
}
default:
2024-04-04 14:46:14 +00:00
panic(fmt.Sprintf("parse expression unknown function declaration type %T", value))
}
}
return out
case *ast.Identifier:
2024-04-04 14:46:14 +00:00
return &nodeIdentifier{
idx: expr.Idx,
name: expr.Name,
}
case *ast.NewExpression:
2024-04-04 14:46:14 +00:00
out := &nodeNewExpression{
callee: cmpl.parseExpression(expr.Callee),
argumentList: make([]nodeExpression, len(expr.ArgumentList)),
}
2024-04-04 14:46:14 +00:00
for i, value := range expr.ArgumentList {
out.argumentList[i] = cmpl.parseExpression(value)
}
return out
case *ast.NullLiteral:
return nullLiteral
case *ast.NumberLiteral:
2024-04-04 14:46:14 +00:00
return &nodeLiteral{
value: toValue(expr.Value),
}
case *ast.ObjectLiteral:
2024-04-04 14:46:14 +00:00
out := &nodeObjectLiteral{
value: make([]nodeProperty, len(expr.Value)),
}
2024-04-04 14:46:14 +00:00
for i, value := range expr.Value {
out.value[i] = nodeProperty{
key: value.Key,
kind: value.Kind,
value: cmpl.parseExpression(value.Value),
}
}
return out
case *ast.RegExpLiteral:
2024-04-04 14:46:14 +00:00
return &nodeRegExpLiteral{
flags: expr.Flags,
pattern: expr.Pattern,
}
case *ast.SequenceExpression:
2024-04-04 14:46:14 +00:00
out := &nodeSequenceExpression{
sequence: make([]nodeExpression, len(expr.Sequence)),
}
2024-04-04 14:46:14 +00:00
for i, value := range expr.Sequence {
out.sequence[i] = cmpl.parseExpression(value)
}
return out
case *ast.StringLiteral:
2024-04-04 14:46:14 +00:00
return &nodeLiteral{
value: stringValue(expr.Value),
}
case *ast.ThisExpression:
2024-04-04 14:46:14 +00:00
return &nodeThisExpression{}
case *ast.UnaryExpression:
2024-04-04 14:46:14 +00:00
return &nodeUnaryExpression{
operator: expr.Operator,
operand: cmpl.parseExpression(expr.Operand),
postfix: expr.Postfix,
}
case *ast.VariableExpression:
2024-04-04 14:46:14 +00:00
return &nodeVariableExpression{
idx: expr.Idx0(),
name: expr.Name,
initializer: cmpl.parseExpression(expr.Initializer),
}
2024-04-04 14:46:14 +00:00
default:
panic(fmt.Errorf("parse expression unknown node type %T", expr))
}
}
2024-04-04 14:46:14 +00:00
func (cmpl *compiler) parseStatement(stmt ast.Statement) nodeStatement {
if stmt == nil {
return nil
}
2024-04-04 14:46:14 +00:00
switch stmt := stmt.(type) {
case *ast.BlockStatement:
2024-04-04 14:46:14 +00:00
out := &nodeBlockStatement{
list: make([]nodeStatement, len(stmt.List)),
}
2024-04-04 14:46:14 +00:00
for i, value := range stmt.List {
out.list[i] = cmpl.parseStatement(value)
}
return out
case *ast.BranchStatement:
2024-04-04 14:46:14 +00:00
out := &nodeBranchStatement{
branch: stmt.Token,
}
2024-04-04 14:46:14 +00:00
if stmt.Label != nil {
out.label = stmt.Label.Name
}
return out
case *ast.DebuggerStatement:
2024-04-04 14:46:14 +00:00
return &nodeDebuggerStatement{}
case *ast.DoWhileStatement:
2024-04-04 14:46:14 +00:00
out := &nodeDoWhileStatement{
test: cmpl.parseExpression(stmt.Test),
}
2024-04-04 14:46:14 +00:00
body := cmpl.parseStatement(stmt.Body)
if block, ok := body.(*nodeBlockStatement); ok {
out.body = block.list
} else {
out.body = append(out.body, body)
}
return out
case *ast.EmptyStatement:
return emptyStatement
case *ast.ExpressionStatement:
2024-04-04 14:46:14 +00:00
return &nodeExpressionStatement{
expression: cmpl.parseExpression(stmt.Expression),
}
case *ast.ForInStatement:
2024-04-04 14:46:14 +00:00
out := &nodeForInStatement{
into: cmpl.parseExpression(stmt.Into),
source: cmpl.parseExpression(stmt.Source),
}
2024-04-04 14:46:14 +00:00
body := cmpl.parseStatement(stmt.Body)
if block, ok := body.(*nodeBlockStatement); ok {
out.body = block.list
} else {
out.body = append(out.body, body)
}
return out
case *ast.ForStatement:
2024-04-04 14:46:14 +00:00
out := &nodeForStatement{
initializer: cmpl.parseExpression(stmt.Initializer),
update: cmpl.parseExpression(stmt.Update),
test: cmpl.parseExpression(stmt.Test),
}
2024-04-04 14:46:14 +00:00
body := cmpl.parseStatement(stmt.Body)
if block, ok := body.(*nodeBlockStatement); ok {
out.body = block.list
} else {
out.body = append(out.body, body)
}
return out
case *ast.FunctionStatement:
return emptyStatement
case *ast.IfStatement:
2024-04-04 14:46:14 +00:00
return &nodeIfStatement{
test: cmpl.parseExpression(stmt.Test),
consequent: cmpl.parseStatement(stmt.Consequent),
alternate: cmpl.parseStatement(stmt.Alternate),
}
case *ast.LabelledStatement:
2024-04-04 14:46:14 +00:00
return &nodeLabelledStatement{
label: stmt.Label.Name,
statement: cmpl.parseStatement(stmt.Statement),
}
case *ast.ReturnStatement:
2024-04-04 14:46:14 +00:00
return &nodeReturnStatement{
argument: cmpl.parseExpression(stmt.Argument),
}
case *ast.SwitchStatement:
2024-04-04 14:46:14 +00:00
out := &nodeSwitchStatement{
discriminant: cmpl.parseExpression(stmt.Discriminant),
defaultIdx: stmt.Default,
body: make([]*nodeCaseStatement, len(stmt.Body)),
}
2024-04-04 14:46:14 +00:00
for i, clause := range stmt.Body {
out.body[i] = &nodeCaseStatement{
test: cmpl.parseExpression(clause.Test),
2024-04-04 14:46:14 +00:00
consequent: make([]nodeStatement, len(clause.Consequent)),
}
for j, value := range clause.Consequent {
out.body[i].consequent[j] = cmpl.parseStatement(value)
}
}
return out
case *ast.ThrowStatement:
2024-04-04 14:46:14 +00:00
return &nodeThrowStatement{
argument: cmpl.parseExpression(stmt.Argument),
}
case *ast.TryStatement:
2024-04-04 14:46:14 +00:00
out := &nodeTryStatement{
body: cmpl.parseStatement(stmt.Body),
finally: cmpl.parseStatement(stmt.Finally),
}
if stmt.Catch != nil {
out.catch = &nodeCatchStatement{
parameter: stmt.Catch.Parameter.Name,
body: cmpl.parseStatement(stmt.Catch.Body),
}
}
return out
case *ast.VariableStatement:
2024-04-04 14:46:14 +00:00
out := &nodeVariableStatement{
list: make([]nodeExpression, len(stmt.List)),
}
2024-04-04 14:46:14 +00:00
for i, value := range stmt.List {
out.list[i] = cmpl.parseExpression(value)
}
return out
case *ast.WhileStatement:
2024-04-04 14:46:14 +00:00
out := &nodeWhileStatement{
test: cmpl.parseExpression(stmt.Test),
}
2024-04-04 14:46:14 +00:00
body := cmpl.parseStatement(stmt.Body)
if block, ok := body.(*nodeBlockStatement); ok {
out.body = block.list
} else {
out.body = append(out.body, body)
}
return out
case *ast.WithStatement:
2024-04-04 14:46:14 +00:00
return &nodeWithStatement{
object: cmpl.parseExpression(stmt.Object),
body: cmpl.parseStatement(stmt.Body),
}
2024-04-04 14:46:14 +00:00
default:
panic(fmt.Sprintf("parse statement: unknown type %T", stmt))
}
}
2024-04-04 14:46:14 +00:00
func cmplParse(in *ast.Program) *nodeProgram {
cmpl := compiler{
program: in,
}
2024-04-04 14:46:14 +00:00
if cmpl.program != nil {
cmpl.file = cmpl.program.File
}
return cmpl.parse()
}
2024-04-04 14:46:14 +00:00
func (cmpl *compiler) parse() *nodeProgram {
out := &nodeProgram{
body: make([]nodeStatement, len(cmpl.program.Body)),
file: cmpl.program.File,
}
2024-04-04 14:46:14 +00:00
for i, value := range cmpl.program.Body {
out.body[i] = cmpl.parseStatement(value)
}
2024-04-04 14:46:14 +00:00
for _, value := range cmpl.program.DeclarationList {
switch value := value.(type) {
case *ast.FunctionDeclaration:
2024-04-04 14:46:14 +00:00
out.functionList = append(out.functionList, cmpl.parseExpression(value.Function).(*nodeFunctionLiteral))
case *ast.VariableDeclaration:
for _, value := range value.List {
out.varList = append(out.varList, value.Name)
}
default:
2024-04-04 14:46:14 +00:00
panic(fmt.Sprintf("Here be dragons: cmpl.parseProgram.DeclarationList(%T)", value))
}
}
return out
}
2024-04-04 14:46:14 +00:00
type nodeProgram struct {
body []nodeStatement
varList []string
2024-04-04 14:46:14 +00:00
functionList []*nodeFunctionLiteral
file *file.File
}
2024-04-04 14:46:14 +00:00
type node interface{}
type (
2024-04-04 14:46:14 +00:00
nodeExpression interface {
node
expressionNode()
}
2024-04-04 14:46:14 +00:00
nodeArrayLiteral struct {
value []nodeExpression
}
2024-04-04 14:46:14 +00:00
nodeAssignExpression struct {
operator token.Token
2024-04-04 14:46:14 +00:00
left nodeExpression
right nodeExpression
}
2024-04-04 14:46:14 +00:00
nodeBinaryExpression struct {
operator token.Token
2024-04-04 14:46:14 +00:00
left nodeExpression
right nodeExpression
comparison bool
}
2024-04-04 14:46:14 +00:00
nodeBracketExpression struct {
idx file.Idx
2024-04-04 14:46:14 +00:00
left nodeExpression
member nodeExpression
}
2024-04-04 14:46:14 +00:00
nodeCallExpression struct {
callee nodeExpression
argumentList []nodeExpression
}
2024-04-04 14:46:14 +00:00
nodeConditionalExpression struct {
test nodeExpression
consequent nodeExpression
alternate nodeExpression
}
2024-04-04 14:46:14 +00:00
nodeDotExpression struct {
idx file.Idx
2024-04-04 14:46:14 +00:00
left nodeExpression
identifier string
}
2024-04-04 14:46:14 +00:00
nodeFunctionLiteral struct {
name string
2024-04-04 14:46:14 +00:00
body nodeStatement
source string
parameterList []string
varList []string
2024-04-04 14:46:14 +00:00
functionList []*nodeFunctionLiteral
file *file.File
}
2024-04-04 14:46:14 +00:00
nodeIdentifier struct {
idx file.Idx
name string
}
2024-04-04 14:46:14 +00:00
nodeLiteral struct {
value Value
}
2024-04-04 14:46:14 +00:00
nodeNewExpression struct {
callee nodeExpression
argumentList []nodeExpression
}
2024-04-04 14:46:14 +00:00
nodeObjectLiteral struct {
value []nodeProperty
}
2024-04-04 14:46:14 +00:00
nodeProperty struct {
key string
kind string
2024-04-04 14:46:14 +00:00
value nodeExpression
}
2024-04-04 14:46:14 +00:00
nodeRegExpLiteral struct {
flags string
pattern string // Value?
}
2024-04-04 14:46:14 +00:00
nodeSequenceExpression struct {
sequence []nodeExpression
}
2024-04-04 14:46:14 +00:00
nodeThisExpression struct{}
2024-04-04 14:46:14 +00:00
nodeUnaryExpression struct {
operator token.Token
2024-04-04 14:46:14 +00:00
operand nodeExpression
postfix bool
}
2024-04-04 14:46:14 +00:00
nodeVariableExpression struct {
idx file.Idx
name string
2024-04-04 14:46:14 +00:00
initializer nodeExpression
}
)
type (
2024-04-04 14:46:14 +00:00
nodeStatement interface {
node
statementNode()
}
2024-04-04 14:46:14 +00:00
nodeBlockStatement struct {
list []nodeStatement
}
2024-04-04 14:46:14 +00:00
nodeBranchStatement struct {
branch token.Token
label string
}
2024-04-04 14:46:14 +00:00
nodeCaseStatement struct {
test nodeExpression
consequent []nodeStatement
}
2024-04-04 14:46:14 +00:00
nodeCatchStatement struct {
parameter string
2024-04-04 14:46:14 +00:00
body nodeStatement
}
2024-04-04 14:46:14 +00:00
nodeDebuggerStatement struct{}
2024-04-04 14:46:14 +00:00
nodeDoWhileStatement struct {
test nodeExpression
body []nodeStatement
}
2024-04-04 14:46:14 +00:00
nodeEmptyStatement struct{}
2024-04-04 14:46:14 +00:00
nodeExpressionStatement struct {
expression nodeExpression
}
2024-04-04 14:46:14 +00:00
nodeForInStatement struct {
into nodeExpression
source nodeExpression
body []nodeStatement
}
2024-04-04 14:46:14 +00:00
nodeForStatement struct {
initializer nodeExpression
update nodeExpression
test nodeExpression
body []nodeStatement
}
2024-04-04 14:46:14 +00:00
nodeIfStatement struct {
test nodeExpression
consequent nodeStatement
alternate nodeStatement
}
2024-04-04 14:46:14 +00:00
nodeLabelledStatement struct {
label string
2024-04-04 14:46:14 +00:00
statement nodeStatement
}
2024-04-04 14:46:14 +00:00
nodeReturnStatement struct {
argument nodeExpression
}
2024-04-04 14:46:14 +00:00
nodeSwitchStatement struct {
discriminant nodeExpression
defaultIdx int
body []*nodeCaseStatement
}
2024-04-04 14:46:14 +00:00
nodeThrowStatement struct {
argument nodeExpression
}
2024-04-04 14:46:14 +00:00
nodeTryStatement struct {
body nodeStatement
catch *nodeCatchStatement
finally nodeStatement
}
2024-04-04 14:46:14 +00:00
nodeVariableStatement struct {
list []nodeExpression
}
2024-04-04 14:46:14 +00:00
nodeWhileStatement struct {
test nodeExpression
body []nodeStatement
}
2024-04-04 14:46:14 +00:00
nodeWithStatement struct {
object nodeExpression
body nodeStatement
}
)
2024-04-04 14:46:14 +00:00
// 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() {}