File: builtin_function.go

package info (click to toggle)
golang-github-robertkrimen-otto 0.0~git20200922.ef014fd-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, sid
  • size: 1,796 kB
  • sloc: perl: 1,227; makefile: 79
file content (129 lines) | stat: -rw-r--r-- 3,711 bytes parent folder | download | duplicates (2)
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))
}