289b30715d
This commit converts the dependency management from Godeps to the vendor folder, also switching the tool from godep to trash. Since the upstream tool lacks a few features proposed via a few PRs, until those PRs are merged in (if), use github.com/karalabe/trash. You can update dependencies via trash --update. All dependencies have been updated to their latest version. Parts of the build system are reworked to drop old notions of Godeps and invocation of the go vet command so that it doesn't run against the vendor folder, as that will just blow up during vetting. The conversion drops OpenCL (and hence GPU mining support) from ethash and our codebase. The short reasoning is that there's noone to maintain and having opencl libs in our deps messes up builds as go install ./... tries to build them, failing with unsatisfied link errors for the C OpenCL deps. golang.org/x/net/context is not vendored in. We expect it to be fetched by the user (i.e. using go get). To keep ci.go builds reproducible the package is "vendored" in build/_vendor.
425 lines
10 KiB
Go
425 lines
10 KiB
Go
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:
|
|
if self.debugger != nil {
|
|
self.debugger(self.otto)
|
|
}
|
|
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)
|
|
}
|