aboutsummaryrefslogblamecommitdiffstats
path: root/Godeps/_workspace/src/github.com/obscuren/otto/type_function.go
blob: 8a6fee9d7bc16fd8ed27bf81f205b2bcc0579d16 (plain) (tree)



















































































































































































































































































                                                                                                                                                         
package otto

import (
    "fmt"
)

type _functionObject struct {
    call      _callFunction
    construct _constructFunction
}

func (self _functionObject) source(object *_object) string {
    return self.call.Source(object)
}

func (self0 _functionObject) clone(clone *_clone) _functionObject {
    return _functionObject{
        clone.callFunction(self0.call),
        self0.construct,
    }
}

func (runtime *_runtime) newNativeFunctionObject(name string, native _nativeFunction, length int) *_object {
    self := runtime.newClassObject("Function")
    self.value = _functionObject{
        call:      newNativeCallFunction(native),
        construct: defaultConstructFunction,
    }
    self.defineProperty("length", toValue_int(length), 0000, false)
    return self
}

func (runtime *_runtime) newBoundFunctionObject(target *_object, this Value, argumentList []Value) *_object {
    self := runtime.newClassObject("Function")
    self.value = _functionObject{
        call:      newBoundCallFunction(target, this, argumentList),
        construct: newBoundConstructFunction(target),
    }
    length := int(toInt32(target.get("length")))
    length -= len(argumentList)
    if length < 0 {
        length = 0
    }
    self.defineProperty("length", toValue_int(length), 0000, false)
    self.defineProperty("caller", UndefinedValue(), 0000, false)    // TODO Should throw a TypeError
    self.defineProperty("arguments", UndefinedValue(), 0000, false) // TODO Should throw a TypeError
    return self
}

func (runtime *_runtime) newBoundFunction(target *_object, this Value, argumentList []Value) *_object {
    self := runtime.newBoundFunctionObject(target, this, argumentList)
    self.prototype = runtime.Global.FunctionPrototype
    prototype := runtime.newObject()
    self.defineProperty("prototype", toValue_object(prototype), 0100, false)
    prototype.defineProperty("constructor", toValue_object(self), 0100, false)
    return self
}

func (self *_object) functionValue() _functionObject {
    value, _ := self.value.(_functionObject)
    return value
}

func (self *_object) Call(this Value, argumentList ...interface{}) Value {
    if self.functionValue().call == nil {
        panic(newTypeError("%v is not a function", toValue_object(self)))
    }
    return self.runtime.Call(self, this, self.runtime.toValueArray(argumentList...), false)
    // ... -> runtime -> self.Function.Call.Dispatch -> ...
}

func (self *_object) Construct(this Value, argumentList ...interface{}) Value {
    function := self.functionValue()
    if function.call == nil {
        panic(newTypeError("%v is not a function", toValue_object(self)))
    }
    if function.construct == nil {
        panic(newTypeError("%v is not a constructor", toValue_object(self)))
    }
    return function.construct(self, this, self.runtime.toValueArray(argumentList...))
}

func defaultConstructFunction(self *_object, this Value, argumentList []Value) Value {
    newObject := self.runtime.newObject()
    newObject.class = "Object"
    prototypeValue := self.get("prototype")
    if !prototypeValue.IsObject() {
        prototypeValue = toValue_object(self.runtime.Global.ObjectPrototype)
    }
    newObject.prototype = prototypeValue._object()
    newObjectValue := toValue_object(newObject)
    result := self.Call(newObjectValue, argumentList)
    if result.IsObject() {
        return result
    }
    return newObjectValue
}

func (self *_object) callGet(this Value) Value {
    return self.runtime.Call(self, this, []Value(nil), false)
}

func (self *_object) callSet(this Value, value Value) {
    self.runtime.Call(self, this, []Value{value}, false)
}

// 15.3.5.3
func (self *_object) HasInstance(of Value) bool {
    if self.functionValue().call == nil {
        // We should not have a HasInstance method
        panic(newTypeError())
    }
    if !of.IsObject() {
        return false
    }
    prototype := self.get("prototype")
    if !prototype.IsObject() {
        panic(newTypeError())
    }
    prototypeObject := prototype._object()

    value := of._object().prototype
    for value != nil {
        if value == prototypeObject {
            return true
        }
        value = value.prototype
    }
    return false
}

type _nativeFunction func(FunctionCall) Value

// _constructFunction
type _constructFunction func(*_object, Value, []Value) Value

// _callFunction
type _callFunction interface {
    Dispatch(*_object, *_functionEnvironment, *_runtime, Value, []Value, bool) Value
    Source(*_object) string
    ScopeEnvironment() _environment
    clone(clone *_clone) _callFunction
}

// _nativeCallFunction
type _nativeCallFunction struct {
    name     string
    function _nativeFunction
}

func newNativeCallFunction(native _nativeFunction) _nativeCallFunction {
    return _nativeCallFunction{"", native}
}

func (self _nativeCallFunction) Dispatch(_ *_object, _ *_functionEnvironment, runtime *_runtime, this Value, argumentList []Value, evalHint bool) Value {
    return self.function(FunctionCall{
        runtime:  runtime,
        evalHint: evalHint,

        This:         this,
        ArgumentList: argumentList,
        Otto:         runtime.Otto,
    })
}

func (self _nativeCallFunction) ScopeEnvironment() _environment {
    return nil
}

func (self _nativeCallFunction) Source(*_object) string {
    return fmt.Sprintf("function %s() { [native code] }", self.name)
}

func (self0 _nativeCallFunction) clone(clone *_clone) _callFunction {
    return self0
}

// _boundCallFunction
type _boundCallFunction struct {
    target       *_object
    this         Value
    argumentList []Value
}

func newBoundCallFunction(target *_object, this Value, argumentList []Value) *_boundCallFunction {
    self := &_boundCallFunction{
        target:       target,
        this:         this,
        argumentList: argumentList,
    }
    return self
}

func (self _boundCallFunction) Dispatch(_ *_object, _ *_functionEnvironment, runtime *_runtime, this Value, argumentList []Value, _ bool) Value {
    argumentList = append(self.argumentList, argumentList...)
    return runtime.Call(self.target, self.this, argumentList, false)
}

func (self _boundCallFunction) ScopeEnvironment() _environment {
    return nil
}

func (self _boundCallFunction) Source(*_object) string {
    return ""
}

func (self0 _boundCallFunction) clone(clone *_clone) _callFunction {
    return _boundCallFunction{
        target:       clone.object(self0.target),
        this:         clone.value(self0.this),
        argumentList: clone.valueArray(self0.argumentList),
    }
}

func newBoundConstructFunction(target *_object) _constructFunction {
    // This is not exactly as described in 15.3.4.5.2, we let [[Call]] supply the
    // bound arguments, etc.
    return func(self *_object, this Value, argumentList []Value) Value {
        switch value := target.value.(type) {
        case _functionObject:
            return value.construct(self, this, argumentList)
        }
        panic(newTypeError())
    }
}

// FunctionCall{}

// FunctionCall is an encapsulation of a JavaScript function call.
type FunctionCall struct {
    runtime     *_runtime
    _thisObject *_object
    evalHint    bool

    This         Value
    ArgumentList []Value
    Otto         *Otto
}

// Argument will return the value of the argument at the given index.
//
// If no such argument exists, undefined is returned.
func (self FunctionCall) Argument(index int) Value {
    return valueOfArrayIndex(self.ArgumentList, index)
}

func (self FunctionCall) getArgument(index int) (Value, bool) {
    return getValueOfArrayIndex(self.ArgumentList, index)
}

func (self FunctionCall) slice(index int) []Value {
    if index < len(self.ArgumentList) {
        return self.ArgumentList[index:]
    }
    return []Value{}
}

func (self *FunctionCall) thisObject() *_object {
    if self._thisObject == nil {
        this := self.runtime.GetValue(self.This) // FIXME Is this right?
        self._thisObject = self.runtime.toObject(this)
    }
    return self._thisObject
}

func (self *FunctionCall) thisClassObject(class string) *_object {
    thisObject := self.thisObject()
    if thisObject.class != class {
        panic(newTypeError())
    }
    return self._thisObject
}

func (self FunctionCall) toObject(value Value) *_object {
    return self.runtime.toObject(value)
}