aboutsummaryrefslogtreecommitdiffstats
path: root/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_function.go
blob: 3d07566c6bbf4ec811158508423a712a182829db (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package otto

import (
    "fmt"
    "regexp"
    "strings"
    "unicode"

    "github.com/robertkrimen/otto/parser"
)

// Function

func builtinFunction(call FunctionCall) Value {
    return toValue_object(builtinNewFunctionNative(call.runtime, call.ArgumentList))
}

func builtinNewFunction(self *_object, argumentList []Value) Value {
    return toValue_object(builtinNewFunctionNative(self.runtime, argumentList))
}

func argumentList2parameterList(argumentList []Value) []string {
    parameterList := make([]string, 0, len(argumentList))
    for _, value := range argumentList {
        tmp := strings.FieldsFunc(value.string(), func(chr rune) bool {
            return chr == ',' || unicode.IsSpace(chr)
        })
        parameterList = append(parameterList, tmp...)
    }
    return parameterList
}

var matchIdentifier = regexp.MustCompile(`^[$_\p{L}][$_\p{L}\d}]*$`)

func builtinNewFunctionNative(runtime *_runtime, argumentList []Value) *_object {
    var parameterList, body string
    count := len(argumentList)
    if count > 0 {
        tmp := make([]string, 0, count-1)
        for _, value := range argumentList[0 : count-1] {
            tmp = append(tmp, value.string())
        }
        parameterList = strings.Join(tmp, ",")
        body = argumentList[count-1].string()
    }

    // FIXME
    function, err := parser.ParseFunction(parameterList, body)
    runtime.parseThrow(err) // Will panic/throw appropriately
    cmpl := _compiler{}
    cmpl_function := cmpl.parseExpression(function)

    return runtime.newNodeFunction(cmpl_function.(*_nodeFunctionLiteral), runtime.globalStash)
}

func builtinFunction_toString(call FunctionCall) Value {
    object := call.thisClassObject("Function") // Should throw a TypeError unless Function
    switch fn := object.value.(type) {
    case _nativeFunctionObject:
        return toValue_string(fmt.Sprintf("function %s() { [native code] }", fn.name))
    case _nodeFunctionObject:
        return toValue_string(fn.node.source)
    case _bindFunctionObject:
        return toValue_string("function () { [native code] }")
    }

    panic(call.runtime.panicTypeError("Function.toString()"))
}

func builtinFunction_apply(call FunctionCall) Value {
    if !call.This.isCallable() {
        panic(call.runtime.panicTypeError())
    }
    this := call.Argument(0)
    if this.IsUndefined() {
        // FIXME Not ECMA5
        this = toValue_object(call.runtime.globalObject)
    }
    argumentList := call.Argument(1)
    switch argumentList.kind {
    case valueUndefined, valueNull:
        return call.thisObject().call(this, nil, false, nativeFrame)
    case valueObject:
    default:
        panic(call.runtime.panicTypeError())
    }

    arrayObject := argumentList._object()
    thisObject := call.thisObject()
    length := int64(toUint32(arrayObject.get("length")))
    valueArray := make([]Value, length)
    for index := int64(0); index < length; index++ {
        valueArray[index] = arrayObject.get(arrayIndexToString(index))
    }
    return thisObject.call(this, valueArray, false, nativeFrame)
}

func builtinFunction_call(call FunctionCall) Value {
    if !call.This.isCallable() {
        panic(call.runtime.panicTypeError())
    }
    thisObject := call.thisObject()
    this := call.Argument(0)
    if this.IsUndefined() {
        // FIXME Not ECMA5
        this = toValue_object(call.runtime.globalObject)
    }
    if len(call.ArgumentList) >= 1 {
        return thisObject.call(this, call.ArgumentList[1:], false, nativeFrame)
    }
    return thisObject.call(this, nil, false, nativeFrame)
}

func builtinFunction_bind(call FunctionCall) Value {
    target := call.This
    if !target.isCallable() {
        panic(call.runtime.panicTypeError())
    }
    targetObject := target._object()

    this := call.Argument(0)
    argumentList := call.slice(1)
    if this.IsUndefined() {
        // FIXME Do this elsewhere?
        this = toValue_object(call.runtime.globalObject)
    }

    return toValue_object(call.runtime.newBoundFunction(targetObject, this, argumentList))
}