1
0
mirror of https://github.com/robertkrimen/otto synced 2025-10-12 20:27:30 +08:00
otto/evaluate.go
Robert Krimen ad8a97c028 New parser
* Faster, more straightforward, etc.
* More advanced object literals (get ..., set ...)
* More tests using JavaScript from the wild (http://cdnjs.com/)
2014-04-10 20:42:25 -07:00

201 lines
4.6 KiB
Go

package otto
import (
"fmt"
"runtime"
"github.com/robertkrimen/otto/ast"
"github.com/robertkrimen/otto/token"
)
func (self *_runtime) evaluateBody(body []ast.Statement) Value {
bodyValue := Value{}
for _, node := range body {
value := self.evaluate(node)
if value.isResult() {
return value
}
if !value.isEmpty() {
// We have GetValue here to (for example) trigger a
// ReferenceError (of the not defined variety)
// Not sure if this is the best way to error out early
// for such errors or if there is a better way
bodyValue = self.GetValue(value)
}
}
return bodyValue
}
func (self *_runtime) evaluate(node ast.Node) Value {
defer func() {
// This defer is lame (unecessary overhead)
// It would be better to mark the errors at the source
if caught := recover(); caught != nil {
switch caught := caught.(type) {
case _error:
if caught.Line == -1 {
//caught.Line = ast.position()
}
panic(caught) // Panic the modified _error
}
panic(caught)
}
}()
// Allow interpreter interruption
// If the Interrupt channel is nil, then
// we avoid runtime.Gosched() overhead (if any)
if self.Otto.Interrupt != nil {
runtime.Gosched()
select {
case value := <-self.Otto.Interrupt:
value()
default:
}
}
switch node := node.(type) {
case *ast.VariableExpression:
return self.evaluateVariableExpression(node)
case *ast.VarStatement:
// Variables are already defined, this is initialization only
for _, variable := range node.List {
self.evaluateVariableExpression(variable.(*ast.VariableExpression))
}
return Value{}
case *ast.Program:
self.functionDeclaration(node.FunctionList)
self.variableDeclaration(node.VariableList)
return self.evaluateBody(node.Body)
case *ast.ExpressionStatement:
return self.evaluate(node.Expression)
case *ast.BlockStatement:
return self.evaluateBlockStatement(node)
case *ast.NullLiteral:
return NullValue()
case *ast.BooleanLiteral:
return toValue_bool(node.Value)
case *ast.StringLiteral:
return toValue_string(node.Value)
case *ast.NumberLiteral:
return toValue_float64(stringToFloat(node.Literal))
case *ast.ObjectLiteral:
return self.evaluateObject(node)
case *ast.RegExpLiteral:
return self.evaluateRegExpLiteral(node)
case *ast.ArrayLiteral:
return self.evaluateArray(node)
case *ast.Identifier:
return self.evaluateIdentifier(node)
case *ast.LabelledStatement:
self.labels = append(self.labels, node.Label.Name)
defer func() {
if len(self.labels) > 0 {
self.labels = self.labels[:len(self.labels)-1] // Pop the label
} else {
self.labels = nil
}
}()
return self.evaluate(node.Statement)
case *ast.BinaryExpression:
if node.Comparison {
return self.evaluateComparison(node)
} else {
return self.evaluateBinaryExpression(node)
}
case *ast.AssignExpression:
return self.evaluateAssignExpression(node)
case *ast.UnaryExpression:
return self.evaluateUnaryExpression(node)
case *ast.ReturnStatement:
return self.evaluateReturnStatement(node)
case *ast.IfStatement:
return self.evaluateIfStatement(node)
case *ast.DoWhileStatement:
return self.evaluateDoWhileStatement(node)
case *ast.WhileStatement:
return self.evaluateWhileStatement(node)
case *ast.CallExpression:
return self.evaluateCall(node, nil)
case *ast.BranchStatement:
target := ""
if node.Label != nil {
target = node.Label.Name
}
switch node.Token {
case token.BREAK:
return toValue(newBreakResult(target))
case token.CONTINUE:
return toValue(newContinueResult(target))
}
case *ast.SwitchStatement:
return self.evaluateSwitchStatement(node)
case *ast.ForStatement:
return self.evaluateForStatement(node)
case *ast.ForInStatement:
return self.evaluateForInStatement(node)
case *ast.ThrowStatement:
return self.evaluateThrowStatement(node)
case *ast.EmptyStatement:
return Value{}
case *ast.TryStatement:
return self.evaluateTryStatement(node)
case *ast.DotExpression:
return self.evaluateDotExpression(node)
case *ast.BracketExpression:
return self.evaluateBracketExpression(node)
case *ast.NewExpression:
return self.evaluateNew(node)
case *ast.ConditionalExpression:
return self.evaluateConditionalExpression(node)
case *ast.ThisExpression:
return toValue_object(self._executionContext(0).this)
case *ast.SequenceExpression:
return self.evaluateSequenceExpression(node)
case *ast.WithStatement:
return self.evaluateWithStatement(node)
case *ast.FunctionExpression:
return self.evaluateFunction(node)
}
panic(fmt.Sprintf("evaluate: Here be dragons: %T %v", node, node))
}