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  }