package otto import ( "fmt" "regexp" "github.com/robertkrimen/otto/ast" "github.com/robertkrimen/otto/file" "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 (cmpl *_compiler) parseExpression(in ast.Expression) _nodeExpression { if in == nil { return nil } switch in := in.(type) { case *ast.ArrayLiteral: out := &_nodeArrayLiteral{ value: make([]_nodeExpression, len(in.Value)), } for i, value := range in.Value { out.value[i] = cmpl.parseExpression(value) } return out case *ast.AssignExpression: return &_nodeAssignExpression{ operator: in.Operator, left: cmpl.parseExpression(in.Left), right: cmpl.parseExpression(in.Right), } case *ast.BinaryExpression: return &_nodeBinaryExpression{ operator: in.Operator, left: cmpl.parseExpression(in.Left), right: cmpl.parseExpression(in.Right), comparison: in.Comparison, } case *ast.BooleanLiteral: if in.Value { return trueLiteral } return falseLiteral case *ast.BracketExpression: return &_nodeBracketExpression{ idx: in.Left.Idx0(), left: cmpl.parseExpression(in.Left), member: cmpl.parseExpression(in.Member), } case *ast.CallExpression: out := &_nodeCallExpression{ callee: cmpl.parseExpression(in.Callee), argumentList: make([]_nodeExpression, len(in.ArgumentList)), } for i, value := range in.ArgumentList { out.argumentList[i] = cmpl.parseExpression(value) } return out case *ast.ConditionalExpression: return &_nodeConditionalExpression{ test: cmpl.parseExpression(in.Test), consequent: cmpl.parseExpression(in.Consequent), alternate: cmpl.parseExpression(in.Alternate), } case *ast.DotExpression: return &_nodeDotExpression{ idx: in.Left.Idx0(), left: cmpl.parseExpression(in.Left), identifier: in.Identifier.Name, } case *ast.EmptyExpression: return nil case *ast.FunctionLiteral: name := "" if in.Name != nil { name = in.Name.Name } out := &_nodeFunctionLiteral{ name: name, body: cmpl.parseStatement(in.Body), source: in.Source, file: cmpl.file, } if in.ParameterList != nil { list := in.ParameterList.List out.parameterList = make([]string, len(list)) for i, value := range list { out.parameterList[i] = value.Name } } for _, value := range in.DeclarationList { switch value := value.(type) { case *ast.FunctionDeclaration: 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: panic(fmt.Errorf("Here be dragons: parseProgram.declaration(%T)", value)) } } return out case *ast.Identifier: return &_nodeIdentifier{ idx: in.Idx, name: in.Name, } case *ast.NewExpression: out := &_nodeNewExpression{ callee: cmpl.parseExpression(in.Callee), argumentList: make([]_nodeExpression, len(in.ArgumentList)), } for i, value := range in.ArgumentList { out.argumentList[i] = cmpl.parseExpression(value) } return out case *ast.NullLiteral: return nullLiteral case *ast.NumberLiteral: return &_nodeLiteral{ value: toValue(in.Value), } case *ast.ObjectLiteral: out := &_nodeObjectLiteral{ value: make([]_nodeProperty, len(in.Value)), } for i, value := range in.Value { out.value[i] = _nodeProperty{ key: value.Key, kind: value.Kind, value: cmpl.parseExpression(value.Value), } } return out case *ast.RegExpLiteral: return &_nodeRegExpLiteral{ flags: in.Flags, pattern: in.Pattern, } case *ast.SequenceExpression: out := &_nodeSequenceExpression{ sequence: make([]_nodeExpression, len(in.Sequence)), } for i, value := range in.Sequence { out.sequence[i] = cmpl.parseExpression(value) } return out case *ast.StringLiteral: return &_nodeLiteral{ value: toValue_string(in.Value), } case *ast.ThisExpression: return &_nodeThisExpression{} case *ast.UnaryExpression: return &_nodeUnaryExpression{ operator: in.Operator, operand: cmpl.parseExpression(in.Operand), postfix: in.Postfix, } case *ast.VariableExpression: return &_nodeVariableExpression{ idx: in.Idx0(), name: in.Name, initializer: cmpl.parseExpression(in.Initializer), } } panic(fmt.Errorf("Here be dragons: cmpl.parseExpression(%T)", in)) } func (cmpl *_compiler) parseStatement(in ast.Statement) _nodeStatement { if in == nil { return nil } switch in := in.(type) { case *ast.BlockStatement: out := &_nodeBlockStatement{ list: make([]_nodeStatement, len(in.List)), } for i, value := range in.List { out.list[i] = cmpl.parseStatement(value) } return out case *ast.BranchStatement: out := &_nodeBranchStatement{ branch: in.Token, } if in.Label != nil { out.label = in.Label.Name } return out case *ast.DebuggerStatement: return &_nodeDebuggerStatement{} case *ast.DoWhileStatement: out := &_nodeDoWhileStatement{ test: cmpl.parseExpression(in.Test), } body := cmpl.parseStatement(in.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: return &_nodeExpressionStatement{ expression: cmpl.parseExpression(in.Expression), } case *ast.ForInStatement: out := &_nodeForInStatement{ into: cmpl.parseExpression(in.Into), source: cmpl.parseExpression(in.Source), } body := cmpl.parseStatement(in.Body) if block, ok := body.(*_nodeBlockStatement); ok { out.body = block.list } else { out.body = append(out.body, body) } return out case *ast.ForStatement: out := &_nodeForStatement{ initializer: cmpl.parseExpression(in.Initializer), update: cmpl.parseExpression(in.Update), test: cmpl.parseExpression(in.Test), } body := cmpl.parseStatement(in.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: return &_nodeIfStatement{ test: cmpl.parseExpression(in.Test), consequent: cmpl.parseStatement(in.Consequent), alternate: cmpl.parseStatement(in.Alternate), } case *ast.LabelledStatement: return &_nodeLabelledStatement{ label: in.Label.Name, statement: cmpl.parseStatement(in.Statement), } case *ast.ReturnStatement: return &_nodeReturnStatement{ argument: cmpl.parseExpression(in.Argument), } case *ast.SwitchStatement: out := &_nodeSwitchStatement{ discriminant: cmpl.parseExpression(in.Discriminant), default_: in.Default, body: make([]*_nodeCaseStatement, len(in.Body)), } for i, clause := range in.Body { out.body[i] = &_nodeCaseStatement{ test: cmpl.parseExpression(clause.Test), 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: return &_nodeThrowStatement{ argument: cmpl.parseExpression(in.Argument), } case *ast.TryStatement: out := &_nodeTryStatement{ body: cmpl.parseStatement(in.Body), finally: cmpl.parseStatement(in.Finally), } if in.Catch != nil { out.catch = &_nodeCatchStatement{ parameter: in.Catch.Parameter.Name, body: cmpl.parseStatement(in.Catch.Body), } } return out case *ast.VariableStatement: out := &_nodeVariableStatement{ list: make([]_nodeExpression, len(in.List)), } for i, value := range in.List { out.list[i] = cmpl.parseExpression(value) } return out case *ast.WhileStatement: out := &_nodeWhileStatement{ test: cmpl.parseExpression(in.Test), } body := cmpl.parseStatement(in.Body) if block, ok := body.(*_nodeBlockStatement); ok { out.body = block.list } else { out.body = append(out.body, body) } return out case *ast.WithStatement: return &_nodeWithStatement{ object: cmpl.parseExpression(in.Object), body: cmpl.parseStatement(in.Body), } } panic(fmt.Errorf("Here be dragons: cmpl.parseStatement(%T)", in)) } func cmpl_parse(in *ast.Program) *_nodeProgram { cmpl := _compiler{ program: in, } return cmpl.parse() } func (cmpl *_compiler) _parse(in *ast.Program) *_nodeProgram { out := &_nodeProgram{ body: make([]_nodeStatement, len(in.Body)), file: in.File, } for i, value := range in.Body { out.body[i] = cmpl.parseStatement(value) } for _, value := range in.DeclarationList { switch value := value.(type) { case *ast.FunctionDeclaration: 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: panic(fmt.Errorf("Here be dragons: cmpl.parseProgram.DeclarationList(%T)", value)) } } return out } type _nodeProgram struct { body []_nodeStatement varList []string functionList []*_nodeFunctionLiteral variableList []_nodeDeclaration file *file.File } 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 { idx file.Idx left _nodeExpression member _nodeExpression } _nodeCallExpression struct { callee _nodeExpression argumentList []_nodeExpression } _nodeConditionalExpression struct { test _nodeExpression consequent _nodeExpression alternate _nodeExpression } _nodeDotExpression struct { idx file.Idx left _nodeExpression identifier string } _nodeFunctionLiteral struct { name string body _nodeStatement source string parameterList []string varList []string functionList []*_nodeFunctionLiteral file *file.File } _nodeIdentifier struct { idx file.Idx 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 { idx file.Idx 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() {}