aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/robertkrimen/otto/cmpl_evaluate_expression.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/robertkrimen/otto/cmpl_evaluate_expression.go')
-rw-r--r--vendor/github.com/robertkrimen/otto/cmpl_evaluate_expression.go460
1 files changed, 460 insertions, 0 deletions
diff --git a/vendor/github.com/robertkrimen/otto/cmpl_evaluate_expression.go b/vendor/github.com/robertkrimen/otto/cmpl_evaluate_expression.go
new file mode 100644
index 000000000..8586a484f
--- /dev/null
+++ b/vendor/github.com/robertkrimen/otto/cmpl_evaluate_expression.go
@@ -0,0 +1,460 @@
+package otto
+
+import (
+ "fmt"
+ "math"
+ "runtime"
+
+ "github.com/robertkrimen/otto/token"
+)
+
+func (self *_runtime) cmpl_evaluate_nodeExpression(node _nodeExpression) Value {
+ // Allow interpreter interruption
+ // If the Interrupt channel is nil, then
+ // we avoid runtime.Gosched() overhead (if any)
+ // FIXME: Test this
+ if self.otto.Interrupt != nil {
+ runtime.Gosched()
+ select {
+ case value := <-self.otto.Interrupt:
+ value()
+ default:
+ }
+ }
+
+ switch node := node.(type) {
+
+ case *_nodeArrayLiteral:
+ return self.cmpl_evaluate_nodeArrayLiteral(node)
+
+ case *_nodeAssignExpression:
+ return self.cmpl_evaluate_nodeAssignExpression(node)
+
+ case *_nodeBinaryExpression:
+ if node.comparison {
+ return self.cmpl_evaluate_nodeBinaryExpression_comparison(node)
+ } else {
+ return self.cmpl_evaluate_nodeBinaryExpression(node)
+ }
+
+ case *_nodeBracketExpression:
+ return self.cmpl_evaluate_nodeBracketExpression(node)
+
+ case *_nodeCallExpression:
+ return self.cmpl_evaluate_nodeCallExpression(node, nil)
+
+ case *_nodeConditionalExpression:
+ return self.cmpl_evaluate_nodeConditionalExpression(node)
+
+ case *_nodeDotExpression:
+ return self.cmpl_evaluate_nodeDotExpression(node)
+
+ case *_nodeFunctionLiteral:
+ var local = self.scope.lexical
+ if node.name != "" {
+ local = self.newDeclarationStash(local)
+ }
+
+ value := toValue_object(self.newNodeFunction(node, local))
+ if node.name != "" {
+ local.createBinding(node.name, false, value)
+ }
+ return value
+
+ case *_nodeIdentifier:
+ name := node.name
+ // TODO Should be true or false (strictness) depending on context
+ // getIdentifierReference should not return nil, but we check anyway and panic
+ // so as not to propagate the nil into something else
+ reference := getIdentifierReference(self, self.scope.lexical, name, false, _at(node.idx))
+ if reference == nil {
+ // Should never get here!
+ panic(hereBeDragons("referenceError == nil: " + name))
+ }
+ return toValue(reference)
+
+ case *_nodeLiteral:
+ return node.value
+
+ case *_nodeNewExpression:
+ return self.cmpl_evaluate_nodeNewExpression(node)
+
+ case *_nodeObjectLiteral:
+ return self.cmpl_evaluate_nodeObjectLiteral(node)
+
+ case *_nodeRegExpLiteral:
+ return toValue_object(self._newRegExp(node.pattern, node.flags))
+
+ case *_nodeSequenceExpression:
+ return self.cmpl_evaluate_nodeSequenceExpression(node)
+
+ case *_nodeThisExpression:
+ return toValue_object(self.scope.this)
+
+ case *_nodeUnaryExpression:
+ return self.cmpl_evaluate_nodeUnaryExpression(node)
+
+ case *_nodeVariableExpression:
+ return self.cmpl_evaluate_nodeVariableExpression(node)
+ }
+
+ panic(fmt.Errorf("Here be dragons: evaluate_nodeExpression(%T)", node))
+}
+
+func (self *_runtime) cmpl_evaluate_nodeArrayLiteral(node *_nodeArrayLiteral) Value {
+
+ valueArray := []Value{}
+
+ for _, node := range node.value {
+ if node == nil {
+ valueArray = append(valueArray, emptyValue)
+ } else {
+ valueArray = append(valueArray, self.cmpl_evaluate_nodeExpression(node).resolve())
+ }
+ }
+
+ result := self.newArrayOf(valueArray)
+
+ return toValue_object(result)
+}
+
+func (self *_runtime) cmpl_evaluate_nodeAssignExpression(node *_nodeAssignExpression) Value {
+
+ left := self.cmpl_evaluate_nodeExpression(node.left)
+ right := self.cmpl_evaluate_nodeExpression(node.right)
+ rightValue := right.resolve()
+
+ result := rightValue
+ if node.operator != token.ASSIGN {
+ result = self.calculateBinaryExpression(node.operator, left, rightValue)
+ }
+
+ self.putValue(left.reference(), result)
+
+ return result
+}
+
+func (self *_runtime) cmpl_evaluate_nodeBinaryExpression(node *_nodeBinaryExpression) Value {
+
+ left := self.cmpl_evaluate_nodeExpression(node.left)
+ leftValue := left.resolve()
+
+ switch node.operator {
+ // Logical
+ case token.LOGICAL_AND:
+ if !leftValue.bool() {
+ return leftValue
+ }
+ right := self.cmpl_evaluate_nodeExpression(node.right)
+ return right.resolve()
+ case token.LOGICAL_OR:
+ if leftValue.bool() {
+ return leftValue
+ }
+ right := self.cmpl_evaluate_nodeExpression(node.right)
+ return right.resolve()
+ }
+
+ return self.calculateBinaryExpression(node.operator, leftValue, self.cmpl_evaluate_nodeExpression(node.right))
+}
+
+func (self *_runtime) cmpl_evaluate_nodeBinaryExpression_comparison(node *_nodeBinaryExpression) Value {
+
+ left := self.cmpl_evaluate_nodeExpression(node.left).resolve()
+ right := self.cmpl_evaluate_nodeExpression(node.right).resolve()
+
+ return toValue_bool(self.calculateComparison(node.operator, left, right))
+}
+
+func (self *_runtime) cmpl_evaluate_nodeBracketExpression(node *_nodeBracketExpression) Value {
+ target := self.cmpl_evaluate_nodeExpression(node.left)
+ targetValue := target.resolve()
+ member := self.cmpl_evaluate_nodeExpression(node.member)
+ memberValue := member.resolve()
+
+ // TODO Pass in base value as-is, and defer toObject till later?
+ object, err := self.objectCoerce(targetValue)
+ if err != nil {
+ panic(self.panicTypeError("Cannot access member '%s' of %s", memberValue.string(), err.Error(), _at(node.idx)))
+ }
+ return toValue(newPropertyReference(self, object, memberValue.string(), false, _at(node.idx)))
+}
+
+func (self *_runtime) cmpl_evaluate_nodeCallExpression(node *_nodeCallExpression, withArgumentList []interface{}) Value {
+ rt := self
+ this := Value{}
+ callee := self.cmpl_evaluate_nodeExpression(node.callee)
+
+ argumentList := []Value{}
+ if withArgumentList != nil {
+ argumentList = self.toValueArray(withArgumentList...)
+ } else {
+ for _, argumentNode := range node.argumentList {
+ argumentList = append(argumentList, self.cmpl_evaluate_nodeExpression(argumentNode).resolve())
+ }
+ }
+
+ rf := callee.reference()
+ vl := callee.resolve()
+
+ eval := false // Whether this call is a (candidate for) direct call to eval
+ name := ""
+ if rf != nil {
+ switch rf := rf.(type) {
+ case *_propertyReference:
+ name = rf.name
+ object := rf.base
+ this = toValue_object(object)
+ eval = rf.name == "eval" // Possible direct eval
+ case *_stashReference:
+ // TODO ImplicitThisValue
+ name = rf.name
+ eval = rf.name == "eval" // Possible direct eval
+ default:
+ // FIXME?
+ panic(rt.panicTypeError("Here be dragons"))
+ }
+ }
+
+ at := _at(-1)
+ switch callee := node.callee.(type) {
+ case *_nodeIdentifier:
+ at = _at(callee.idx)
+ case *_nodeDotExpression:
+ at = _at(callee.idx)
+ case *_nodeBracketExpression:
+ at = _at(callee.idx)
+ }
+
+ frame := _frame{
+ callee: name,
+ file: self.scope.frame.file,
+ }
+
+ if !vl.IsFunction() {
+ if name == "" {
+ // FIXME Maybe typeof?
+ panic(rt.panicTypeError("%v is not a function", vl, at))
+ }
+ panic(rt.panicTypeError("'%s' is not a function", name, at))
+ }
+
+ self.scope.frame.offset = int(at)
+
+ return vl._object().call(this, argumentList, eval, frame)
+}
+
+func (self *_runtime) cmpl_evaluate_nodeConditionalExpression(node *_nodeConditionalExpression) Value {
+ test := self.cmpl_evaluate_nodeExpression(node.test)
+ testValue := test.resolve()
+ if testValue.bool() {
+ return self.cmpl_evaluate_nodeExpression(node.consequent)
+ }
+ return self.cmpl_evaluate_nodeExpression(node.alternate)
+}
+
+func (self *_runtime) cmpl_evaluate_nodeDotExpression(node *_nodeDotExpression) Value {
+ target := self.cmpl_evaluate_nodeExpression(node.left)
+ targetValue := target.resolve()
+ // TODO Pass in base value as-is, and defer toObject till later?
+ object, err := self.objectCoerce(targetValue)
+ if err != nil {
+ panic(self.panicTypeError("Cannot access member '%s' of %s", node.identifier, err.Error(), _at(node.idx)))
+ }
+ return toValue(newPropertyReference(self, object, node.identifier, false, _at(node.idx)))
+}
+
+func (self *_runtime) cmpl_evaluate_nodeNewExpression(node *_nodeNewExpression) Value {
+ rt := self
+ callee := self.cmpl_evaluate_nodeExpression(node.callee)
+
+ argumentList := []Value{}
+ for _, argumentNode := range node.argumentList {
+ argumentList = append(argumentList, self.cmpl_evaluate_nodeExpression(argumentNode).resolve())
+ }
+
+ rf := callee.reference()
+ vl := callee.resolve()
+
+ name := ""
+ if rf != nil {
+ switch rf := rf.(type) {
+ case *_propertyReference:
+ name = rf.name
+ case *_stashReference:
+ name = rf.name
+ default:
+ panic(rt.panicTypeError("Here be dragons"))
+ }
+ }
+
+ at := _at(-1)
+ switch callee := node.callee.(type) {
+ case *_nodeIdentifier:
+ at = _at(callee.idx)
+ case *_nodeDotExpression:
+ at = _at(callee.idx)
+ case *_nodeBracketExpression:
+ at = _at(callee.idx)
+ }
+
+ if !vl.IsFunction() {
+ if name == "" {
+ // FIXME Maybe typeof?
+ panic(rt.panicTypeError("%v is not a function", vl, at))
+ }
+ panic(rt.panicTypeError("'%s' is not a function", name, at))
+ }
+
+ self.scope.frame.offset = int(at)
+
+ return vl._object().construct(argumentList)
+}
+
+func (self *_runtime) cmpl_evaluate_nodeObjectLiteral(node *_nodeObjectLiteral) Value {
+
+ result := self.newObject()
+
+ for _, property := range node.value {
+ switch property.kind {
+ case "value":
+ result.defineProperty(property.key, self.cmpl_evaluate_nodeExpression(property.value).resolve(), 0111, false)
+ case "get":
+ getter := self.newNodeFunction(property.value.(*_nodeFunctionLiteral), self.scope.lexical)
+ descriptor := _property{}
+ descriptor.mode = 0211
+ descriptor.value = _propertyGetSet{getter, nil}
+ result.defineOwnProperty(property.key, descriptor, false)
+ case "set":
+ setter := self.newNodeFunction(property.value.(*_nodeFunctionLiteral), self.scope.lexical)
+ descriptor := _property{}
+ descriptor.mode = 0211
+ descriptor.value = _propertyGetSet{nil, setter}
+ result.defineOwnProperty(property.key, descriptor, false)
+ default:
+ panic(fmt.Errorf("Here be dragons: evaluate_nodeObjectLiteral: invalid property.Kind: %v", property.kind))
+ }
+ }
+
+ return toValue_object(result)
+}
+
+func (self *_runtime) cmpl_evaluate_nodeSequenceExpression(node *_nodeSequenceExpression) Value {
+ var result Value
+ for _, node := range node.sequence {
+ result = self.cmpl_evaluate_nodeExpression(node)
+ result = result.resolve()
+ }
+ return result
+}
+
+func (self *_runtime) cmpl_evaluate_nodeUnaryExpression(node *_nodeUnaryExpression) Value {
+
+ target := self.cmpl_evaluate_nodeExpression(node.operand)
+ switch node.operator {
+ case token.TYPEOF, token.DELETE:
+ if target.kind == valueReference && target.reference().invalid() {
+ if node.operator == token.TYPEOF {
+ return toValue_string("undefined")
+ }
+ return trueValue
+ }
+ }
+
+ switch node.operator {
+ case token.NOT:
+ targetValue := target.resolve()
+ if targetValue.bool() {
+ return falseValue
+ }
+ return trueValue
+ case token.BITWISE_NOT:
+ targetValue := target.resolve()
+ integerValue := toInt32(targetValue)
+ return toValue_int32(^integerValue)
+ case token.PLUS:
+ targetValue := target.resolve()
+ return toValue_float64(targetValue.float64())
+ case token.MINUS:
+ targetValue := target.resolve()
+ value := targetValue.float64()
+ // TODO Test this
+ sign := float64(-1)
+ if math.Signbit(value) {
+ sign = 1
+ }
+ return toValue_float64(math.Copysign(value, sign))
+ case token.INCREMENT:
+ targetValue := target.resolve()
+ if node.postfix {
+ // Postfix++
+ oldValue := targetValue.float64()
+ newValue := toValue_float64(+1 + oldValue)
+ self.putValue(target.reference(), newValue)
+ return toValue_float64(oldValue)
+ } else {
+ // ++Prefix
+ newValue := toValue_float64(+1 + targetValue.float64())
+ self.putValue(target.reference(), newValue)
+ return newValue
+ }
+ case token.DECREMENT:
+ targetValue := target.resolve()
+ if node.postfix {
+ // Postfix--
+ oldValue := targetValue.float64()
+ newValue := toValue_float64(-1 + oldValue)
+ self.putValue(target.reference(), newValue)
+ return toValue_float64(oldValue)
+ } else {
+ // --Prefix
+ newValue := toValue_float64(-1 + targetValue.float64())
+ self.putValue(target.reference(), newValue)
+ return newValue
+ }
+ case token.VOID:
+ target.resolve() // FIXME Side effect?
+ return Value{}
+ case token.DELETE:
+ reference := target.reference()
+ if reference == nil {
+ return trueValue
+ }
+ return toValue_bool(target.reference().delete())
+ case token.TYPEOF:
+ targetValue := target.resolve()
+ switch targetValue.kind {
+ case valueUndefined:
+ return toValue_string("undefined")
+ case valueNull:
+ return toValue_string("object")
+ case valueBoolean:
+ return toValue_string("boolean")
+ case valueNumber:
+ return toValue_string("number")
+ case valueString:
+ return toValue_string("string")
+ case valueObject:
+ if targetValue._object().isCall() {
+ return toValue_string("function")
+ }
+ return toValue_string("object")
+ default:
+ // FIXME ?
+ }
+ }
+
+ panic(hereBeDragons())
+}
+
+func (self *_runtime) cmpl_evaluate_nodeVariableExpression(node *_nodeVariableExpression) Value {
+ if node.initializer != nil {
+ // FIXME If reference is nil
+ left := getIdentifierReference(self, self.scope.lexical, node.name, false, _at(node.idx))
+ right := self.cmpl_evaluate_nodeExpression(node.initializer)
+ rightValue := right.resolve()
+
+ self.putValue(left, rightValue)
+ }
+ return toValue_string(node.name)
+}