diff options
Diffstat (limited to 'Godeps/_workspace/src/github.com/robertkrimen/otto/runtime.go')
-rw-r--r-- | Godeps/_workspace/src/github.com/robertkrimen/otto/runtime.go | 527 |
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 -} |