1package otto 2 3import ( 4 "fmt" 5 "regexp" 6 "strings" 7 "unicode" 8 9 "github.com/robertkrimen/otto/parser" 10) 11 12// Function 13 14func builtinFunction(call FunctionCall) Value { 15 return toValue_object(builtinNewFunctionNative(call.runtime, call.ArgumentList)) 16} 17 18func builtinNewFunction(self *_object, argumentList []Value) Value { 19 return toValue_object(builtinNewFunctionNative(self.runtime, argumentList)) 20} 21 22func argumentList2parameterList(argumentList []Value) []string { 23 parameterList := make([]string, 0, len(argumentList)) 24 for _, value := range argumentList { 25 tmp := strings.FieldsFunc(value.string(), func(chr rune) bool { 26 return chr == ',' || unicode.IsSpace(chr) 27 }) 28 parameterList = append(parameterList, tmp...) 29 } 30 return parameterList 31} 32 33var matchIdentifier = regexp.MustCompile(`^[$_\p{L}][$_\p{L}\d}]*$`) 34 35func builtinNewFunctionNative(runtime *_runtime, argumentList []Value) *_object { 36 var parameterList, body string 37 count := len(argumentList) 38 if count > 0 { 39 tmp := make([]string, 0, count-1) 40 for _, value := range argumentList[0 : count-1] { 41 tmp = append(tmp, value.string()) 42 } 43 parameterList = strings.Join(tmp, ",") 44 body = argumentList[count-1].string() 45 } 46 47 // FIXME 48 function, err := parser.ParseFunction(parameterList, body) 49 runtime.parseThrow(err) // Will panic/throw appropriately 50 cmpl := _compiler{} 51 cmpl_function := cmpl.parseExpression(function) 52 53 return runtime.newNodeFunction(cmpl_function.(*_nodeFunctionLiteral), runtime.globalStash) 54} 55 56func builtinFunction_toString(call FunctionCall) Value { 57 object := call.thisClassObject("Function") // Should throw a TypeError unless Function 58 switch fn := object.value.(type) { 59 case _nativeFunctionObject: 60 return toValue_string(fmt.Sprintf("function %s() { [native code] }", fn.name)) 61 case _nodeFunctionObject: 62 return toValue_string(fn.node.source) 63 case _bindFunctionObject: 64 return toValue_string("function () { [native code] }") 65 } 66 67 panic(call.runtime.panicTypeError("Function.toString()")) 68} 69 70func builtinFunction_apply(call FunctionCall) Value { 71 if !call.This.isCallable() { 72 panic(call.runtime.panicTypeError()) 73 } 74 this := call.Argument(0) 75 if this.IsUndefined() { 76 // FIXME Not ECMA5 77 this = toValue_object(call.runtime.globalObject) 78 } 79 argumentList := call.Argument(1) 80 switch argumentList.kind { 81 case valueUndefined, valueNull: 82 return call.thisObject().call(this, nil, false, nativeFrame) 83 case valueObject: 84 default: 85 panic(call.runtime.panicTypeError()) 86 } 87 88 arrayObject := argumentList._object() 89 thisObject := call.thisObject() 90 length := int64(toUint32(arrayObject.get("length"))) 91 valueArray := make([]Value, length) 92 for index := int64(0); index < length; index++ { 93 valueArray[index] = arrayObject.get(arrayIndexToString(index)) 94 } 95 return thisObject.call(this, valueArray, false, nativeFrame) 96} 97 98func builtinFunction_call(call FunctionCall) Value { 99 if !call.This.isCallable() { 100 panic(call.runtime.panicTypeError()) 101 } 102 thisObject := call.thisObject() 103 this := call.Argument(0) 104 if this.IsUndefined() { 105 // FIXME Not ECMA5 106 this = toValue_object(call.runtime.globalObject) 107 } 108 if len(call.ArgumentList) >= 1 { 109 return thisObject.call(this, call.ArgumentList[1:], false, nativeFrame) 110 } 111 return thisObject.call(this, nil, false, nativeFrame) 112} 113 114func builtinFunction_bind(call FunctionCall) Value { 115 target := call.This 116 if !target.isCallable() { 117 panic(call.runtime.panicTypeError()) 118 } 119 targetObject := target._object() 120 121 this := call.Argument(0) 122 argumentList := call.slice(1) 123 if this.IsUndefined() { 124 // FIXME Do this elsewhere? 125 this = toValue_object(call.runtime.globalObject) 126 } 127 128 return toValue_object(call.runtime.newBoundFunction(targetObject, this, argumentList)) 129} 130