aboutsummaryrefslogtreecommitdiffstats
path: root/Godeps/_workspace/src/github.com/robertkrimen/otto/runtime.go
diff options
context:
space:
mode:
Diffstat (limited to 'Godeps/_workspace/src/github.com/robertkrimen/otto/runtime.go')
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/runtime.go527
1 files changed, 0 insertions, 527 deletions
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/runtime.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/runtime.go
deleted file mode 100644
index a998f7acc..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/runtime.go
+++ /dev/null
@@ -1,527 +0,0 @@
-package otto
-
-import (
- "errors"
- "fmt"
- "math"
- "reflect"
- "sync"
-
- "github.com/robertkrimen/otto/ast"
- "github.com/robertkrimen/otto/parser"
-)
-
-type _global struct {
- Object *_object // Object( ... ), new Object( ... ) - 1 (length)
- Function *_object // Function( ... ), new Function( ... ) - 1
- Array *_object // Array( ... ), new Array( ... ) - 1
- String *_object // String( ... ), new String( ... ) - 1
- Boolean *_object // Boolean( ... ), new Boolean( ... ) - 1
- Number *_object // Number( ... ), new Number( ... ) - 1
- Math *_object
- Date *_object // Date( ... ), new Date( ... ) - 7
- RegExp *_object // RegExp( ... ), new RegExp( ... ) - 2
- Error *_object // Error( ... ), new Error( ... ) - 1
- EvalError *_object
- TypeError *_object
- RangeError *_object
- ReferenceError *_object
- SyntaxError *_object
- URIError *_object
- JSON *_object
-
- ObjectPrototype *_object // Object.prototype
- FunctionPrototype *_object // Function.prototype
- ArrayPrototype *_object // Array.prototype
- StringPrototype *_object // String.prototype
- BooleanPrototype *_object // Boolean.prototype
- NumberPrototype *_object // Number.prototype
- DatePrototype *_object // Date.prototype
- RegExpPrototype *_object // RegExp.prototype
- ErrorPrototype *_object // Error.prototype
- EvalErrorPrototype *_object
- TypeErrorPrototype *_object
- RangeErrorPrototype *_object
- ReferenceErrorPrototype *_object
- SyntaxErrorPrototype *_object
- URIErrorPrototype *_object
-}
-
-type _runtime struct {
- global _global
- globalObject *_object
- globalStash *_objectStash
- scope *_scope
- otto *Otto
- eval *_object // The builtin eval, for determine indirect versus direct invocation
- debugger func(*Otto)
- random func() float64
-
- labels []string // FIXME
- lck sync.Mutex
-}
-
-func (self *_runtime) enterScope(scope *_scope) {
- scope.outer = self.scope
- self.scope = scope
-}
-
-func (self *_runtime) leaveScope() {
- self.scope = self.scope.outer
-}
-
-// FIXME This is used in two places (cloning)
-func (self *_runtime) enterGlobalScope() {
- self.enterScope(newScope(self.globalStash, self.globalStash, self.globalObject))
-}
-
-func (self *_runtime) enterFunctionScope(outer _stash, this Value) *_fnStash {
- if outer == nil {
- outer = self.globalStash
- }
- stash := self.newFunctionStash(outer)
- var thisObject *_object
- switch this.kind {
- case valueUndefined, valueNull:
- thisObject = self.globalObject
- default:
- thisObject = self.toObject(this)
- }
- self.enterScope(newScope(stash, stash, thisObject))
- return stash
-}
-
-func (self *_runtime) putValue(reference _reference, value Value) {
- name := reference.putValue(value)
- if name != "" {
- // Why? -- If reference.base == nil
- // strict = false
- self.globalObject.defineProperty(name, value, 0111, false)
- }
-}
-
-func (self *_runtime) tryCatchEvaluate(inner func() Value) (tryValue Value, exception bool) {
- // resultValue = The value of the block (e.g. the last statement)
- // throw = Something was thrown
- // throwValue = The value of what was thrown
- // other = Something that changes flow (return, break, continue) that is not a throw
- // Otherwise, some sort of unknown panic happened, we'll just propagate it
- defer func() {
- if caught := recover(); caught != nil {
- if exception, ok := caught.(*_exception); ok {
- caught = exception.eject()
- }
- switch caught := caught.(type) {
- case _error:
- exception = true
- tryValue = toValue_object(self.newError(caught.name, caught.messageValue()))
- case Value:
- exception = true
- tryValue = caught
- default:
- panic(caught)
- }
- }
- }()
-
- tryValue = inner()
- return
-}
-
-// toObject
-
-func (self *_runtime) toObject(value Value) *_object {
- switch value.kind {
- case valueEmpty, valueUndefined, valueNull:
- panic(self.panicTypeError())
- case valueBoolean:
- return self.newBoolean(value)
- case valueString:
- return self.newString(value)
- case valueNumber:
- return self.newNumber(value)
- case valueObject:
- return value._object()
- }
- panic(self.panicTypeError())
-}
-
-func (self *_runtime) objectCoerce(value Value) (*_object, error) {
- switch value.kind {
- case valueUndefined:
- return nil, errors.New("undefined")
- case valueNull:
- return nil, errors.New("null")
- case valueBoolean:
- return self.newBoolean(value), nil
- case valueString:
- return self.newString(value), nil
- case valueNumber:
- return self.newNumber(value), nil
- case valueObject:
- return value._object(), nil
- }
- panic(self.panicTypeError())
-}
-
-func checkObjectCoercible(rt *_runtime, value Value) {
- isObject, mustCoerce := testObjectCoercible(value)
- if !isObject && !mustCoerce {
- panic(rt.panicTypeError())
- }
-}
-
-// testObjectCoercible
-
-func testObjectCoercible(value Value) (isObject bool, mustCoerce bool) {
- switch value.kind {
- case valueReference, valueEmpty, valueNull, valueUndefined:
- return false, false
- case valueNumber, valueString, valueBoolean:
- isObject = false
- mustCoerce = true
- case valueObject:
- isObject = true
- mustCoerce = false
- }
- return
-}
-
-func (self *_runtime) safeToValue(value interface{}) (Value, error) {
- result := Value{}
- err := catchPanic(func() {
- result = self.toValue(value)
- })
- return result, err
-}
-
-// convertNumeric converts numeric parameter val from js to that of type t if it is safe to do so, otherwise it panics.
-// This allows literals (int64), bitwise values (int32) and the general form (float64) of javascript numerics to be passed as parameters to go functions easily.
-func convertNumeric(val reflect.Value, t reflect.Type) reflect.Value {
- if val.Kind() == t.Kind() {
- return val
- }
-
- if val.Kind() == reflect.Interface {
- val = reflect.ValueOf(val.Interface())
- }
-
- switch val.Kind() {
- case reflect.Float32, reflect.Float64:
- f64 := val.Float()
- switch t.Kind() {
- case reflect.Float64:
- return reflect.ValueOf(f64)
- case reflect.Float32:
- if reflect.Zero(t).OverflowFloat(f64) {
- panic("converting float64 to float32 would overflow")
- }
-
- return val.Convert(t)
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- i64 := int64(f64)
- if float64(i64) != f64 {
- panic(fmt.Sprintf("converting %v to %v would cause loss of precision", val.Type(), t))
- }
-
- // The float represents an integer
- val = reflect.ValueOf(i64)
- default:
- panic(fmt.Sprintf("cannot convert %v to %v", val.Type(), t))
- }
- }
-
- switch val.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- i64 := val.Int()
- switch t.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- if reflect.Zero(t).OverflowInt(i64) {
- panic(fmt.Sprintf("converting %v to %v would overflow", val.Type(), t))
- }
- return val.Convert(t)
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- if i64 < 0 {
- panic(fmt.Sprintf("converting %v to %v would underflow", val.Type(), t))
- }
- if reflect.Zero(t).OverflowUint(uint64(i64)) {
- panic(fmt.Sprintf("converting %v to %v would overflow", val.Type(), t))
- }
- return val.Convert(t)
- }
-
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- u64 := val.Uint()
- switch t.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- if u64 > math.MaxInt64 || reflect.Zero(t).OverflowInt(int64(u64)) {
- panic(fmt.Sprintf("converting %v to %v would overflow", val.Type(), t))
- }
- return val.Convert(t)
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- if reflect.Zero(t).OverflowUint(u64) {
- panic(fmt.Sprintf("converting %v to %v would overflow", val.Type(), t))
- }
- return val.Convert(t)
- }
- }
-
- panic(fmt.Sprintf("unsupported type %v for numeric conversion", val.Type()))
-}
-
-// callParamConvert converts request val to type t if possible.
-// If the conversion fails due to overflow or type miss-match then it panics.
-// If no conversion is known then the original value is returned.
-func callParamConvert(val reflect.Value, t reflect.Type) reflect.Value {
- if val.Kind() == reflect.Interface {
- val = reflect.ValueOf(val.Interface())
- }
-
- switch t.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64:
- if val.Kind() == t.Kind() {
- // Types already match
- return val
- }
- return convertNumeric(val, t)
- case reflect.Slice:
- if val.Kind() != reflect.Slice {
- // Conversion from none slice type to slice not possible
- panic(fmt.Sprintf("cannot use %v as type %v", val, t))
- }
- default:
- // No supported conversion
- return val
- }
-
- elemType := t.Elem()
- switch elemType.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.Slice:
- // Attempt to convert to slice of the type t
- s := reflect.MakeSlice(reflect.SliceOf(elemType), val.Len(), val.Len())
- for i := 0; i < val.Len(); i++ {
- s.Index(i).Set(callParamConvert(val.Index(i), elemType))
- }
-
- return s
- }
-
- // Not a slice type we can convert
- return val
-}
-
-// callSliceRequired returns true if CallSlice is required instead of Call.
-func callSliceRequired(param reflect.Type, val reflect.Value) bool {
- vt := val.Type()
- for param.Kind() == reflect.Slice {
- if val.Kind() == reflect.Interface {
- val = reflect.ValueOf(val.Interface())
- vt = val.Type()
- }
-
- if vt.Kind() != reflect.Slice {
- return false
- }
-
- vt = vt.Elem()
- if val.Kind() != reflect.Invalid {
- if val.Len() > 0 {
- val = val.Index(0)
- } else {
- val = reflect.Value{}
- }
- }
- param = param.Elem()
- }
-
- return true
-}
-
-func (self *_runtime) toValue(value interface{}) Value {
- switch value := value.(type) {
- case Value:
- return value
- case func(FunctionCall) Value:
- return toValue_object(self.newNativeFunction("", value))
- case _nativeFunction:
- return toValue_object(self.newNativeFunction("", value))
- case Object, *Object, _object, *_object:
- // Nothing happens.
- // FIXME We should really figure out what can come here.
- // This catch-all is ugly.
- default:
- {
- value := reflect.ValueOf(value)
- switch value.Kind() {
- case reflect.Ptr:
- switch reflect.Indirect(value).Kind() {
- case reflect.Struct:
- return toValue_object(self.newGoStructObject(value))
- case reflect.Array:
- return toValue_object(self.newGoArray(value))
- }
- case reflect.Func:
- // TODO Maybe cache this?
- return toValue_object(self.newNativeFunction("", func(call FunctionCall) Value {
- argsCount := len(call.ArgumentList)
- in := make([]reflect.Value, argsCount)
- t := value.Type()
- callSlice := false
- paramsCount := t.NumIn()
- lastParam := paramsCount - 1
- lastArg := argsCount - 1
- isVariadic := t.IsVariadic()
- for i, value := range call.ArgumentList {
- var paramType reflect.Type
- if isVariadic && i == lastArg && argsCount == paramsCount {
- // Variadic functions last parameter and parameter numbers match incoming args
- paramType = t.In(lastArg)
- val := reflect.ValueOf(value.export())
- callSlice = callSliceRequired(paramType, val)
- if callSlice {
- in[i] = callParamConvert(reflect.ValueOf(value.export()), paramType)
- continue
- }
- }
-
- if i >= lastParam {
- if isVariadic {
- paramType = t.In(lastParam).Elem()
- } else {
- paramType = t.In(lastParam)
- }
- } else {
- paramType = t.In(i)
- }
- in[i] = callParamConvert(reflect.ValueOf(value.export()), paramType)
- }
-
- var out []reflect.Value
- if callSlice {
- out = value.CallSlice(in)
- } else {
- out = value.Call(in)
- }
-
- l := len(out)
- switch l {
- case 0:
- return Value{}
- case 1:
- return self.toValue(out[0].Interface())
- }
-
- // Return an array of the values to emulate multi value return.
- // In the future this can be used along side destructuring assignment.
- s := make([]interface{}, l)
- for i, v := range out {
- s[i] = self.toValue(v.Interface())
- }
- return self.toValue(s)
- }))
- case reflect.Struct:
- return toValue_object(self.newGoStructObject(value))
- case reflect.Map:
- return toValue_object(self.newGoMapObject(value))
- case reflect.Slice:
- return toValue_object(self.newGoSlice(value))
- case reflect.Array:
- return toValue_object(self.newGoArray(value))
- }
- }
- }
- return toValue(value)
-}
-
-func (runtime *_runtime) newGoSlice(value reflect.Value) *_object {
- self := runtime.newGoSliceObject(value)
- self.prototype = runtime.global.ArrayPrototype
- return self
-}
-
-func (runtime *_runtime) newGoArray(value reflect.Value) *_object {
- self := runtime.newGoArrayObject(value)
- self.prototype = runtime.global.ArrayPrototype
- return self
-}
-
-func (runtime *_runtime) parse(filename string, src interface{}) (*ast.Program, error) {
- return parser.ParseFile(nil, filename, src, 0)
-}
-
-func (runtime *_runtime) cmpl_parse(filename string, src interface{}) (*_nodeProgram, error) {
- program, err := parser.ParseFile(nil, filename, src, 0)
- if err != nil {
- return nil, err
- }
- return cmpl_parse(program), nil
-}
-
-func (self *_runtime) parseSource(src interface{}) (*_nodeProgram, *ast.Program, error) {
- switch src := src.(type) {
- case *ast.Program:
- return nil, src, nil
- case *Script:
- return src.program, nil, nil
- }
- program, err := self.parse("", src)
- return nil, program, err
-}
-
-func (self *_runtime) cmpl_runOrEval(src interface{}, eval bool) (Value, error) {
- result := Value{}
- cmpl_program, program, err := self.parseSource(src)
- if err != nil {
- return result, err
- }
- if cmpl_program == nil {
- cmpl_program = cmpl_parse(program)
- }
- err = catchPanic(func() {
- result = self.cmpl_evaluate_nodeProgram(cmpl_program, eval)
- })
- switch result.kind {
- case valueEmpty:
- result = Value{}
- case valueReference:
- result = result.resolve()
- }
- return result, err
-}
-
-func (self *_runtime) cmpl_run(src interface{}) (Value, error) {
- return self.cmpl_runOrEval(src, false)
-}
-
-func (self *_runtime) cmpl_eval(src interface{}) (Value, error) {
- return self.cmpl_runOrEval(src, true)
-}
-
-func (self *_runtime) parseThrow(err error) {
- if err == nil {
- return
- }
- switch err := err.(type) {
- case parser.ErrorList:
- {
- err := err[0]
- if err.Message == "Invalid left-hand side in assignment" {
- panic(self.panicReferenceError(err.Message))
- }
- panic(self.panicSyntaxError(err.Message))
- }
- }
- panic(self.panicSyntaxError(err.Error()))
-}
-
-func (self *_runtime) parseOrThrow(source string) *ast.Program {
- program, err := self.parse("", source)
- self.parseThrow(err) // Will panic/throw appropriately
- return program
-}
-
-func (self *_runtime) cmpl_parseOrThrow(source string) *_nodeProgram {
- program, err := self.cmpl_parse("", source)
- self.parseThrow(err) // Will panic/throw appropriately
- return program
-}