go.ketch.com/lib/goja@v0.0.1/builtin_function.go (about) 1 package goja 2 3 import ( 4 "fmt" 5 "math" 6 ) 7 8 func (r *Runtime) builtin_Function(args []Value, proto *Object) *Object { 9 var sb valueStringBuilder 10 sb.WriteString(asciiString("(function anonymous(")) 11 if len(args) > 1 { 12 ar := args[:len(args)-1] 13 for i, arg := range ar { 14 sb.WriteString(arg.toString()) 15 if i < len(ar)-1 { 16 sb.WriteRune(',') 17 } 18 } 19 } 20 sb.WriteString(asciiString("\n) {\n")) 21 if len(args) > 0 { 22 sb.WriteString(args[len(args)-1].toString()) 23 } 24 sb.WriteString(asciiString("\n})")) 25 26 ret := r.toObject(r.eval(sb.String(), false, false)) 27 ret.self.setProto(proto, true) 28 return ret 29 } 30 31 func (r *Runtime) functionproto_toString(call FunctionCall) Value { 32 obj := r.toObject(call.This) 33 repeat: 34 switch f := obj.self.(type) { 35 case *funcObject: 36 return newStringValue(f.src) 37 case *classFuncObject: 38 return newStringValue(f.src) 39 case *methodFuncObject: 40 return newStringValue(f.src) 41 case *arrowFuncObject: 42 return newStringValue(f.src) 43 case *nativeFuncObject: 44 return newStringValue(fmt.Sprintf("function %s() { [native code] }", nilSafe(f.getStr("name", nil)).toString())) 45 case *boundFuncObject: 46 return newStringValue(fmt.Sprintf("function %s() { [native code] }", nilSafe(f.getStr("name", nil)).toString())) 47 case *lazyObject: 48 obj.self = f.create(obj) 49 goto repeat 50 case *proxyObject: 51 repeat2: 52 switch c := f.target.self.(type) { 53 case *classFuncObject, *methodFuncObject, *funcObject, *arrowFuncObject, *nativeFuncObject, *boundFuncObject: 54 return asciiString("function () { [native code] }") 55 case *lazyObject: 56 f.target.self = c.create(obj) 57 goto repeat2 58 } 59 } 60 panic(r.NewTypeError("Function.prototype.toString requires that 'this' be a Function")) 61 } 62 63 func (r *Runtime) functionproto_hasInstance(call FunctionCall) Value { 64 if o, ok := call.This.(*Object); ok { 65 if _, ok = o.self.assertCallable(); ok { 66 return r.toBoolean(o.self.hasInstance(call.Argument(0))) 67 } 68 } 69 70 return valueFalse 71 } 72 73 func (r *Runtime) createListFromArrayLike(a Value) []Value { 74 o := r.toObject(a) 75 if arr := r.checkStdArrayObj(o); arr != nil { 76 return arr.values 77 } 78 l := toLength(o.self.getStr("length", nil)) 79 res := make([]Value, 0, l) 80 for k := int64(0); k < l; k++ { 81 res = append(res, nilSafe(o.self.getIdx(valueInt(k), nil))) 82 } 83 return res 84 } 85 86 func (r *Runtime) functionproto_apply(call FunctionCall) Value { 87 var args []Value 88 if len(call.Arguments) >= 2 { 89 args = r.createListFromArrayLike(call.Arguments[1]) 90 } 91 92 f := r.toCallable(call.This) 93 return f(FunctionCall{ 94 This: call.Argument(0), 95 Arguments: args, 96 }) 97 } 98 99 func (r *Runtime) functionproto_call(call FunctionCall) Value { 100 var args []Value 101 if len(call.Arguments) > 0 { 102 args = call.Arguments[1:] 103 } 104 105 f := r.toCallable(call.This) 106 return f(FunctionCall{ 107 This: call.Argument(0), 108 Arguments: args, 109 }) 110 } 111 112 func (r *Runtime) boundCallable(target func(FunctionCall) Value, boundArgs []Value) func(FunctionCall) Value { 113 var this Value 114 var args []Value 115 if len(boundArgs) > 0 { 116 this = boundArgs[0] 117 args = make([]Value, len(boundArgs)-1) 118 copy(args, boundArgs[1:]) 119 } else { 120 this = _undefined 121 } 122 return func(call FunctionCall) Value { 123 a := append(args, call.Arguments...) 124 return target(FunctionCall{ 125 This: this, 126 Arguments: a, 127 }) 128 } 129 } 130 131 func (r *Runtime) boundConstruct(f *Object, target func([]Value, *Object) *Object, boundArgs []Value) func([]Value, *Object) *Object { 132 if target == nil { 133 return nil 134 } 135 var args []Value 136 if len(boundArgs) > 1 { 137 args = make([]Value, len(boundArgs)-1) 138 copy(args, boundArgs[1:]) 139 } 140 return func(fargs []Value, newTarget *Object) *Object { 141 a := append(args, fargs...) 142 if newTarget == f { 143 newTarget = nil 144 } 145 return target(a, newTarget) 146 } 147 } 148 149 func (r *Runtime) functionproto_bind(call FunctionCall) Value { 150 obj := r.toObject(call.This) 151 152 fcall := r.toCallable(call.This) 153 construct := obj.self.assertConstructor() 154 155 var l = _positiveZero 156 if obj.self.hasOwnPropertyStr("length") { 157 var li int64 158 switch lenProp := nilSafe(obj.self.getStr("length", nil)).(type) { 159 case valueInt: 160 li = lenProp.ToInteger() 161 case valueFloat: 162 switch lenProp { 163 case _positiveInf: 164 l = lenProp 165 goto lenNotInt 166 case _negativeInf: 167 goto lenNotInt 168 case _negativeZero: 169 // no-op, li == 0 170 default: 171 if !math.IsNaN(float64(lenProp)) { 172 li = int64(math.Abs(float64(lenProp))) 173 } // else li = 0 174 } 175 } 176 if len(call.Arguments) > 1 { 177 li -= int64(len(call.Arguments)) - 1 178 } 179 if li < 0 { 180 li = 0 181 } 182 l = intToValue(li) 183 } 184 lenNotInt: 185 name := obj.self.getStr("name", nil) 186 nameStr := stringBound_ 187 if s, ok := name.(valueString); ok { 188 nameStr = nameStr.concat(s) 189 } 190 191 v := &Object{runtime: r} 192 ff := r.newNativeFuncAndConstruct(v, r.boundCallable(fcall, call.Arguments), r.boundConstruct(v, construct, call.Arguments), nil, nameStr.string(), l) 193 bf := &boundFuncObject{ 194 nativeFuncObject: *ff, 195 wrapped: obj, 196 } 197 bf.prototype = obj.self.proto() 198 v.self = bf 199 200 return v 201 } 202 203 func (r *Runtime) initFunction() { 204 o := r.global.FunctionPrototype.self.(*nativeFuncObject) 205 o.prototype = r.global.ObjectPrototype 206 o._putProp("name", stringEmpty, false, false, true) 207 o._putProp("apply", r.newNativeFunc(r.functionproto_apply, nil, "apply", nil, 2), true, false, true) 208 o._putProp("bind", r.newNativeFunc(r.functionproto_bind, nil, "bind", nil, 1), true, false, true) 209 o._putProp("call", r.newNativeFunc(r.functionproto_call, nil, "call", nil, 1), true, false, true) 210 o._putProp("toString", r.newNativeFunc(r.functionproto_toString, nil, "toString", nil, 0), true, false, true) 211 o._putSym(SymHasInstance, valueProp(r.newNativeFunc(r.functionproto_hasInstance, nil, "[Symbol.hasInstance]", nil, 1), false, false, false)) 212 213 r.global.Function = r.newNativeFuncConstruct(r.builtin_Function, "Function", r.global.FunctionPrototype, 1) 214 r.addToGlobal("Function", r.global.Function) 215 }