go.ketch.com/lib/goja@v0.0.1/func.go (about) 1 package goja 2 3 import ( 4 "reflect" 5 6 "go.ketch.com/lib/goja/unistring" 7 ) 8 9 type baseFuncObject struct { 10 baseObject 11 12 lenProp valueProperty 13 } 14 15 type baseJsFuncObject struct { 16 baseFuncObject 17 18 stash *stash 19 privEnv *privateEnv 20 21 prg *Program 22 src string 23 strict bool 24 } 25 26 type funcObject struct { 27 baseJsFuncObject 28 } 29 30 type classFuncObject struct { 31 baseJsFuncObject 32 initFields *Program 33 computedKeys []Value 34 35 privateEnvType *privateEnvType 36 privateMethods []Value 37 38 derived bool 39 } 40 41 type methodFuncObject struct { 42 baseJsFuncObject 43 homeObject *Object 44 } 45 46 type arrowFuncObject struct { 47 baseJsFuncObject 48 funcObj *Object 49 newTarget Value 50 } 51 52 type nativeFuncObject struct { 53 baseFuncObject 54 55 f func(FunctionCall) Value 56 construct func(args []Value, newTarget *Object) *Object 57 } 58 59 type boundFuncObject struct { 60 nativeFuncObject 61 wrapped *Object 62 } 63 64 func (f *nativeFuncObject) export(*objectExportCtx) interface{} { 65 return f.f 66 } 67 68 func (f *funcObject) _addProto(n unistring.String) Value { 69 if n == "prototype" { 70 if _, exists := f.values[n]; !exists { 71 return f.addPrototype() 72 } 73 } 74 return nil 75 } 76 77 func (f *funcObject) getStr(p unistring.String, receiver Value) Value { 78 return f.getStrWithOwnProp(f.getOwnPropStr(p), p, receiver) 79 } 80 81 func (f *funcObject) getOwnPropStr(name unistring.String) Value { 82 if v := f._addProto(name); v != nil { 83 return v 84 } 85 86 return f.baseObject.getOwnPropStr(name) 87 } 88 89 func (f *funcObject) setOwnStr(name unistring.String, val Value, throw bool) bool { 90 f._addProto(name) 91 return f.baseObject.setOwnStr(name, val, throw) 92 } 93 94 func (f *funcObject) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) { 95 return f._setForeignStr(name, f.getOwnPropStr(name), val, receiver, throw) 96 } 97 98 func (f *funcObject) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool { 99 f._addProto(name) 100 return f.baseObject.defineOwnPropertyStr(name, descr, throw) 101 } 102 103 func (f *funcObject) deleteStr(name unistring.String, throw bool) bool { 104 f._addProto(name) 105 return f.baseObject.deleteStr(name, throw) 106 } 107 108 func (f *funcObject) addPrototype() Value { 109 proto := f.val.runtime.NewObject() 110 proto.self._putProp("constructor", f.val, true, false, true) 111 return f._putProp("prototype", proto, true, false, false) 112 } 113 114 func (f *funcObject) hasOwnPropertyStr(name unistring.String) bool { 115 if f.baseObject.hasOwnPropertyStr(name) { 116 return true 117 } 118 119 if name == "prototype" { 120 return true 121 } 122 return false 123 } 124 125 func (f *funcObject) stringKeys(all bool, accum []Value) []Value { 126 if all { 127 if _, exists := f.values["prototype"]; !exists { 128 accum = append(accum, asciiString("prototype")) 129 } 130 } 131 return f.baseFuncObject.stringKeys(all, accum) 132 } 133 134 func (f *funcObject) iterateStringKeys() iterNextFunc { 135 if _, exists := f.values["prototype"]; !exists { 136 f.addPrototype() 137 } 138 return f.baseFuncObject.iterateStringKeys() 139 } 140 141 func (f *baseFuncObject) createInstance(newTarget *Object) *Object { 142 r := f.val.runtime 143 if newTarget == nil { 144 newTarget = f.val 145 } 146 proto := r.getPrototypeFromCtor(newTarget, nil, r.global.ObjectPrototype) 147 148 return f.val.runtime.newBaseObject(proto, classObject).val 149 } 150 151 func (f *baseJsFuncObject) construct(args []Value, newTarget *Object) *Object { 152 if newTarget == nil { 153 newTarget = f.val 154 } 155 proto := newTarget.self.getStr("prototype", nil) 156 var protoObj *Object 157 if p, ok := proto.(*Object); ok { 158 protoObj = p 159 } else { 160 protoObj = f.val.runtime.global.ObjectPrototype 161 } 162 163 obj := f.val.runtime.newBaseObject(protoObj, classObject).val 164 ret := f.call(FunctionCall{ 165 This: obj, 166 Arguments: args, 167 }, newTarget) 168 169 if ret, ok := ret.(*Object); ok { 170 return ret 171 } 172 return obj 173 } 174 175 func (f *classFuncObject) Call(FunctionCall) Value { 176 panic(f.val.runtime.NewTypeError("Class constructor cannot be invoked without 'new'")) 177 } 178 179 func (f *classFuncObject) assertCallable() (func(FunctionCall) Value, bool) { 180 return f.Call, true 181 } 182 183 func (f *classFuncObject) export(*objectExportCtx) interface{} { 184 return f.Call 185 } 186 187 func (f *classFuncObject) createInstance(args []Value, newTarget *Object) (instance *Object) { 188 if f.derived { 189 if ctor := f.prototype.self.assertConstructor(); ctor != nil { 190 instance = ctor(args, newTarget) 191 } else { 192 panic(f.val.runtime.NewTypeError("Super constructor is not a constructor")) 193 } 194 } else { 195 instance = f.baseFuncObject.createInstance(newTarget) 196 } 197 return 198 } 199 200 func (f *classFuncObject) _initFields(instance *Object) { 201 if f.privateEnvType != nil { 202 penv := instance.self.getPrivateEnv(f.privateEnvType, true) 203 penv.methods = f.privateMethods 204 } 205 if f.initFields != nil { 206 vm := f.val.runtime.vm 207 vm.pushCtx() 208 vm.prg = f.initFields 209 vm.stash = f.stash 210 vm.privEnv = f.privEnv 211 vm.newTarget = nil 212 213 // so that 'super' base could be correctly resolved (including from direct eval()) 214 vm.push(f.val) 215 216 vm.sb = vm.sp 217 vm.push(instance) 218 vm.pc = 0 219 vm.run() 220 vm.popCtx() 221 vm.sp -= 2 222 vm.halt = false 223 } 224 } 225 226 func (f *classFuncObject) construct(args []Value, newTarget *Object) *Object { 227 if newTarget == nil { 228 newTarget = f.val 229 } 230 if f.prg == nil { 231 instance := f.createInstance(args, newTarget) 232 f._initFields(instance) 233 return instance 234 } else { 235 var instance *Object 236 var thisVal Value 237 if !f.derived { 238 instance = f.createInstance(args, newTarget) 239 f._initFields(instance) 240 thisVal = instance 241 } 242 ret := f._call(args, newTarget, thisVal) 243 244 if ret, ok := ret.(*Object); ok { 245 return ret 246 } 247 if f.derived { 248 r := f.val.runtime 249 if ret != _undefined { 250 panic(r.NewTypeError("Derived constructors may only return object or undefined")) 251 } 252 if v := r.vm.stack[r.vm.sp+1]; v != nil { // using residual 'this' value (a bit hacky) 253 instance = r.toObject(v) 254 } else { 255 panic(r.newError(r.global.ReferenceError, "Must call super constructor in derived class before returning from derived constructor")) 256 } 257 } 258 return instance 259 } 260 } 261 262 func (f *classFuncObject) assertConstructor() func(args []Value, newTarget *Object) *Object { 263 return f.construct 264 } 265 266 func (f *baseJsFuncObject) Call(call FunctionCall) Value { 267 return f.call(call, nil) 268 } 269 270 func (f *arrowFuncObject) Call(call FunctionCall) Value { 271 return f._call(call.Arguments, f.newTarget, nil) 272 } 273 274 func (f *baseJsFuncObject) _call(args []Value, newTarget, this Value) Value { 275 vm := f.val.runtime.vm 276 277 vm.stack.expand(vm.sp + len(args) + 1) 278 vm.stack[vm.sp] = f.val 279 vm.sp++ 280 vm.stack[vm.sp] = this 281 vm.sp++ 282 for _, arg := range args { 283 if arg != nil { 284 vm.stack[vm.sp] = arg 285 } else { 286 vm.stack[vm.sp] = _undefined 287 } 288 vm.sp++ 289 } 290 291 pc := vm.pc 292 if pc != -1 { 293 vm.pc++ // fake "return address" so that captureStack() records the correct call location 294 vm.pushCtx() 295 vm.callStack = append(vm.callStack, context{pc: -1}) // extra frame so that run() halts after ret 296 } else { 297 vm.pushCtx() 298 } 299 vm.args = len(args) 300 vm.prg = f.prg 301 vm.stash = f.stash 302 vm.privEnv = f.privEnv 303 vm.newTarget = newTarget 304 vm.pc = 0 305 vm.run() 306 if pc != -1 { 307 vm.popCtx() 308 } 309 vm.pc = pc 310 vm.halt = false 311 return vm.pop() 312 } 313 314 func (f *baseJsFuncObject) call(call FunctionCall, newTarget Value) Value { 315 return f._call(call.Arguments, newTarget, nilSafe(call.This)) 316 } 317 318 func (f *baseJsFuncObject) export(*objectExportCtx) interface{} { 319 return f.Call 320 } 321 322 func (f *baseFuncObject) exportType() reflect.Type { 323 return reflectTypeFunc 324 } 325 326 func (f *baseJsFuncObject) assertCallable() (func(FunctionCall) Value, bool) { 327 return f.Call, true 328 } 329 330 func (f *funcObject) assertConstructor() func(args []Value, newTarget *Object) *Object { 331 return f.construct 332 } 333 334 func (f *arrowFuncObject) assertCallable() (func(FunctionCall) Value, bool) { 335 return f.Call, true 336 } 337 338 func (f *arrowFuncObject) export(*objectExportCtx) interface{} { 339 return f.Call 340 } 341 342 func (f *baseFuncObject) init(name unistring.String, length Value) { 343 f.baseObject.init() 344 345 f.lenProp.configurable = true 346 f.lenProp.value = length 347 f._put("length", &f.lenProp) 348 349 f._putProp("name", stringValueFromRaw(name), false, false, true) 350 } 351 352 func (f *baseFuncObject) hasInstance(v Value) bool { 353 if v, ok := v.(*Object); ok { 354 o := f.val.self.getStr("prototype", nil) 355 if o1, ok := o.(*Object); ok { 356 for { 357 v = v.self.proto() 358 if v == nil { 359 return false 360 } 361 if o1 == v { 362 return true 363 } 364 } 365 } else { 366 f.val.runtime.typeErrorResult(true, "prototype is not an object") 367 } 368 } 369 370 return false 371 } 372 373 func (f *nativeFuncObject) defaultConstruct(ccall func(ConstructorCall) *Object, args []Value, newTarget *Object) *Object { 374 obj := f.createInstance(newTarget) 375 ret := ccall(ConstructorCall{ 376 This: obj, 377 Arguments: args, 378 NewTarget: newTarget, 379 }) 380 381 if ret != nil { 382 return ret 383 } 384 return obj 385 } 386 387 func (f *nativeFuncObject) assertCallable() (func(FunctionCall) Value, bool) { 388 if f.f != nil { 389 return f.f, true 390 } 391 return nil, false 392 } 393 394 func (f *nativeFuncObject) assertConstructor() func(args []Value, newTarget *Object) *Object { 395 return f.construct 396 } 397 398 /*func (f *boundFuncObject) getStr(p unistring.String, receiver Value) Value { 399 return f.getStrWithOwnProp(f.getOwnPropStr(p), p, receiver) 400 } 401 402 func (f *boundFuncObject) getOwnPropStr(name unistring.String) Value { 403 if name == "caller" || name == "arguments" { 404 return f.val.runtime.global.throwerProperty 405 } 406 407 return f.nativeFuncObject.getOwnPropStr(name) 408 } 409 410 func (f *boundFuncObject) deleteStr(name unistring.String, throw bool) bool { 411 if name == "caller" || name == "arguments" { 412 return true 413 } 414 return f.nativeFuncObject.deleteStr(name, throw) 415 } 416 417 func (f *boundFuncObject) setOwnStr(name unistring.String, val Value, throw bool) bool { 418 if name == "caller" || name == "arguments" { 419 panic(f.val.runtime.NewTypeError("'caller' and 'arguments' are restricted function properties and cannot be accessed in this context.")) 420 } 421 return f.nativeFuncObject.setOwnStr(name, val, throw) 422 } 423 424 func (f *boundFuncObject) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) { 425 return f._setForeignStr(name, f.getOwnPropStr(name), val, receiver, throw) 426 } 427 */ 428 429 func (f *boundFuncObject) hasInstance(v Value) bool { 430 return instanceOfOperator(v, f.wrapped) 431 }