aboutsummaryrefslogtreecommitdiffstats
path: root/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_evaluate_statement.go
diff options
context:
space:
mode:
Diffstat (limited to 'Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_evaluate_statement.go')
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_evaluate_statement.go421
1 files changed, 421 insertions, 0 deletions
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_evaluate_statement.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_evaluate_statement.go
new file mode 100644
index 000000000..7be158487
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_evaluate_statement.go
@@ -0,0 +1,421 @@
+package otto
+
+import (
+ "fmt"
+ "runtime"
+
+ "github.com/robertkrimen/otto/token"
+)
+
+func (self *_runtime) cmpl_evaluate_nodeStatement(node _nodeStatement) 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 *_nodeBlockStatement:
+ labels := self.labels
+ self.labels = nil
+
+ value := self.cmpl_evaluate_nodeStatementList(node.list)
+ switch value.kind {
+ case valueResult:
+ switch value.evaluateBreak(labels) {
+ case resultBreak:
+ return emptyValue
+ }
+ }
+ return value
+
+ case *_nodeBranchStatement:
+ target := node.label
+ switch node.branch { // FIXME Maybe node.kind? node.operator?
+ case token.BREAK:
+ return toValue(newBreakResult(target))
+ case token.CONTINUE:
+ return toValue(newContinueResult(target))
+ }
+
+ case *_nodeDebuggerStatement:
+ return emptyValue // Nothing happens.
+
+ case *_nodeDoWhileStatement:
+ return self.cmpl_evaluate_nodeDoWhileStatement(node)
+
+ case *_nodeEmptyStatement:
+ return emptyValue
+
+ case *_nodeExpressionStatement:
+ return self.cmpl_evaluate_nodeExpression(node.expression)
+
+ case *_nodeForInStatement:
+ return self.cmpl_evaluate_nodeForInStatement(node)
+
+ case *_nodeForStatement:
+ return self.cmpl_evaluate_nodeForStatement(node)
+
+ case *_nodeIfStatement:
+ return self.cmpl_evaluate_nodeIfStatement(node)
+
+ case *_nodeLabelledStatement:
+ self.labels = append(self.labels, node.label)
+ defer func() {
+ if len(self.labels) > 0 {
+ self.labels = self.labels[:len(self.labels)-1] // Pop the label
+ } else {
+ self.labels = nil
+ }
+ }()
+ return self.cmpl_evaluate_nodeStatement(node.statement)
+
+ case *_nodeReturnStatement:
+ if node.argument != nil {
+ return toValue(newReturnResult(self.cmpl_evaluate_nodeExpression(node.argument).resolve()))
+ }
+ return toValue(newReturnResult(Value{}))
+
+ case *_nodeSwitchStatement:
+ return self.cmpl_evaluate_nodeSwitchStatement(node)
+
+ case *_nodeThrowStatement:
+ value := self.cmpl_evaluate_nodeExpression(node.argument).resolve()
+ panic(newException(value))
+
+ case *_nodeTryStatement:
+ return self.cmpl_evaluate_nodeTryStatement(node)
+
+ case *_nodeVariableStatement:
+ // Variables are already defined, this is initialization only
+ for _, variable := range node.list {
+ self.cmpl_evaluate_nodeVariableExpression(variable.(*_nodeVariableExpression))
+ }
+ return emptyValue
+
+ case *_nodeWhileStatement:
+ return self.cmpl_evaluate_nodeWhileStatement(node)
+
+ case *_nodeWithStatement:
+ return self.cmpl_evaluate_nodeWithStatement(node)
+
+ }
+
+ panic(fmt.Errorf("Here be dragons: evaluate_nodeStatement(%T)", node))
+}
+
+func (self *_runtime) cmpl_evaluate_nodeStatementList(list []_nodeStatement) Value {
+ var result Value
+ for _, node := range list {
+ value := self.cmpl_evaluate_nodeStatement(node)
+ switch value.kind {
+ case valueResult:
+ return value
+ case valueEmpty:
+ default:
+ // 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
+ // TODO Do we still need this?
+ result = value.resolve()
+ }
+ }
+ return result
+}
+
+func (self *_runtime) cmpl_evaluate_nodeDoWhileStatement(node *_nodeDoWhileStatement) Value {
+
+ labels := append(self.labels, "")
+ self.labels = nil
+
+ test := node.test
+
+ result := emptyValue
+resultBreak:
+ for {
+ for _, node := range node.body {
+ value := self.cmpl_evaluate_nodeStatement(node)
+ switch value.kind {
+ case valueResult:
+ switch value.evaluateBreakContinue(labels) {
+ case resultReturn:
+ return value
+ case resultBreak:
+ break resultBreak
+ case resultContinue:
+ goto resultContinue
+ }
+ case valueEmpty:
+ default:
+ result = value
+ }
+ }
+ resultContinue:
+ if !self.cmpl_evaluate_nodeExpression(test).resolve().bool() {
+ // Stahp: do ... while (false)
+ break
+ }
+ }
+ return result
+}
+
+func (self *_runtime) cmpl_evaluate_nodeForInStatement(node *_nodeForInStatement) Value {
+
+ labels := append(self.labels, "")
+ self.labels = nil
+
+ source := self.cmpl_evaluate_nodeExpression(node.source)
+ sourceValue := source.resolve()
+
+ switch sourceValue.kind {
+ case valueUndefined, valueNull:
+ return emptyValue
+ }
+
+ sourceObject := self.toObject(sourceValue)
+
+ into := node.into
+ body := node.body
+
+ result := emptyValue
+ object := sourceObject
+ for object != nil {
+ enumerateValue := emptyValue
+ object.enumerate(false, func(name string) bool {
+ into := self.cmpl_evaluate_nodeExpression(into)
+ // In the case of: for (var abc in def) ...
+ if into.reference() == nil {
+ identifier := into.string()
+ // TODO Should be true or false (strictness) depending on context
+ into = toValue(getIdentifierReference(self, self.scope.lexical, identifier, false, -1))
+ }
+ self.putValue(into.reference(), toValue_string(name))
+ for _, node := range body {
+ value := self.cmpl_evaluate_nodeStatement(node)
+ switch value.kind {
+ case valueResult:
+ switch value.evaluateBreakContinue(labels) {
+ case resultReturn:
+ enumerateValue = value
+ return false
+ case resultBreak:
+ object = nil
+ return false
+ case resultContinue:
+ return true
+ }
+ case valueEmpty:
+ default:
+ enumerateValue = value
+ }
+ }
+ return true
+ })
+ if object == nil {
+ break
+ }
+ object = object.prototype
+ if !enumerateValue.isEmpty() {
+ result = enumerateValue
+ }
+ }
+ return result
+}
+
+func (self *_runtime) cmpl_evaluate_nodeForStatement(node *_nodeForStatement) Value {
+
+ labels := append(self.labels, "")
+ self.labels = nil
+
+ initializer := node.initializer
+ test := node.test
+ update := node.update
+ body := node.body
+
+ if initializer != nil {
+ initialResult := self.cmpl_evaluate_nodeExpression(initializer)
+ initialResult.resolve() // Side-effect trigger
+ }
+
+ result := emptyValue
+resultBreak:
+ for {
+ if test != nil {
+ testResult := self.cmpl_evaluate_nodeExpression(test)
+ testResultValue := testResult.resolve()
+ if testResultValue.bool() == false {
+ break
+ }
+ }
+ for _, node := range body {
+ value := self.cmpl_evaluate_nodeStatement(node)
+ switch value.kind {
+ case valueResult:
+ switch value.evaluateBreakContinue(labels) {
+ case resultReturn:
+ return value
+ case resultBreak:
+ break resultBreak
+ case resultContinue:
+ goto resultContinue
+ }
+ case valueEmpty:
+ default:
+ result = value
+ }
+ }
+ resultContinue:
+ if update != nil {
+ updateResult := self.cmpl_evaluate_nodeExpression(update)
+ updateResult.resolve() // Side-effect trigger
+ }
+ }
+ return result
+}
+
+func (self *_runtime) cmpl_evaluate_nodeIfStatement(node *_nodeIfStatement) Value {
+ test := self.cmpl_evaluate_nodeExpression(node.test)
+ testValue := test.resolve()
+ if testValue.bool() {
+ return self.cmpl_evaluate_nodeStatement(node.consequent)
+ } else if node.alternate != nil {
+ return self.cmpl_evaluate_nodeStatement(node.alternate)
+ }
+
+ return emptyValue
+}
+
+func (self *_runtime) cmpl_evaluate_nodeSwitchStatement(node *_nodeSwitchStatement) Value {
+
+ labels := append(self.labels, "")
+ self.labels = nil
+
+ discriminantResult := self.cmpl_evaluate_nodeExpression(node.discriminant)
+ target := node.default_
+
+ for index, clause := range node.body {
+ test := clause.test
+ if test != nil {
+ if self.calculateComparison(token.STRICT_EQUAL, discriminantResult, self.cmpl_evaluate_nodeExpression(test)) {
+ target = index
+ break
+ }
+ }
+ }
+
+ result := emptyValue
+ if target != -1 {
+ for _, clause := range node.body[target:] {
+ for _, statement := range clause.consequent {
+ value := self.cmpl_evaluate_nodeStatement(statement)
+ switch value.kind {
+ case valueResult:
+ switch value.evaluateBreak(labels) {
+ case resultReturn:
+ return value
+ case resultBreak:
+ return emptyValue
+ }
+ case valueEmpty:
+ default:
+ result = value
+ }
+ }
+ }
+ }
+
+ return result
+}
+
+func (self *_runtime) cmpl_evaluate_nodeTryStatement(node *_nodeTryStatement) Value {
+ tryCatchValue, exception := self.tryCatchEvaluate(func() Value {
+ return self.cmpl_evaluate_nodeStatement(node.body)
+ })
+
+ if exception && node.catch != nil {
+ outer := self.scope.lexical
+ self.scope.lexical = self.newDeclarationStash(outer)
+ defer func() {
+ self.scope.lexical = outer
+ }()
+ // TODO If necessary, convert TypeError<runtime> => TypeError
+ // That, is, such errors can be thrown despite not being JavaScript "native"
+ // strict = false
+ self.scope.lexical.setValue(node.catch.parameter, tryCatchValue, false)
+
+ // FIXME node.CatchParameter
+ // FIXME node.Catch
+ tryCatchValue, exception = self.tryCatchEvaluate(func() Value {
+ return self.cmpl_evaluate_nodeStatement(node.catch.body)
+ })
+ }
+
+ if node.finally != nil {
+ finallyValue := self.cmpl_evaluate_nodeStatement(node.finally)
+ if finallyValue.kind == valueResult {
+ return finallyValue
+ }
+ }
+
+ if exception {
+ panic(newException(tryCatchValue))
+ }
+
+ return tryCatchValue
+}
+
+func (self *_runtime) cmpl_evaluate_nodeWhileStatement(node *_nodeWhileStatement) Value {
+
+ test := node.test
+ body := node.body
+ labels := append(self.labels, "")
+ self.labels = nil
+
+ result := emptyValue
+resultBreakContinue:
+ for {
+ if !self.cmpl_evaluate_nodeExpression(test).resolve().bool() {
+ // Stahp: while (false) ...
+ break
+ }
+ for _, node := range body {
+ value := self.cmpl_evaluate_nodeStatement(node)
+ switch value.kind {
+ case valueResult:
+ switch value.evaluateBreakContinue(labels) {
+ case resultReturn:
+ return value
+ case resultBreak:
+ break resultBreakContinue
+ case resultContinue:
+ continue resultBreakContinue
+ }
+ case valueEmpty:
+ default:
+ result = value
+ }
+ }
+ }
+ return result
+}
+
+func (self *_runtime) cmpl_evaluate_nodeWithStatement(node *_nodeWithStatement) Value {
+ object := self.cmpl_evaluate_nodeExpression(node.object)
+ outer := self.scope.lexical
+ lexical := self.newObjectStash(self.toObject(object.resolve()), outer)
+ self.scope.lexical = lexical
+ defer func() {
+ self.scope.lexical = outer
+ }()
+
+ return self.cmpl_evaluate_nodeStatement(node.body)
+}