package goja

import (
	
	

	
)

type resultType uint8

const (
	resultNormal resultType = iota
	resultYield
	resultYieldRes      // a yield that expects a value in return
	resultYieldDelegate // yield*
	resultYieldDelegateRes
	resultAwait
)

// used both as an instruction and as a Value
type yieldMarker struct {
	valueNull
	resultType resultType
}

var (
	await = &yieldMarker{resultType: resultAwait}

	yield            = &yieldMarker{resultType: resultYield}
	yieldRes         = &yieldMarker{resultType: resultYieldRes}
	yieldDelegate    = &yieldMarker{resultType: resultYieldDelegate}
	yieldDelegateRes = &yieldMarker{resultType: resultYieldDelegateRes}
	yieldEmpty       = &yieldMarker{resultType: resultYield}
)

// AsyncContextTracker is a handler that allows to track an async execution context to ensure it remains
// consistent across all callback invocations.
// Whenever a Promise reaction job is scheduled the Grab method is called. It is supposed to return the
// current context. The same context will be supplied to the Resumed method before the reaction job is
// executed. The Exited method is called after the reaction job is finished.
// This means that for each invocation of the Grab method there will be exactly one subsequent invocation
// of Resumed and then Exited methods (assuming the Promise is fulfilled or rejected). Also, the Resumed/Exited
// calls cannot be nested, so Exited can simply clear the current context instead of popping from a stack.
// Note, this works for both async functions and regular Promise.then()/Promise.catch() callbacks.
// See TestAsyncContextTracker for more insight.
//
// To register it call Runtime.SetAsyncContextTracker().
type AsyncContextTracker interface {
	Grab() (trackingObject interface{})
	Resumed(trackingObject interface{})
	Exited()
}

type funcObjectImpl interface {
	source() String
}

type baseFuncObject struct {
	baseObject

	lenProp valueProperty
}

type baseJsFuncObject struct {
	baseFuncObject

	stash   *stash
	privEnv *privateEnv

	prg    *Program
	src    string
	strict bool
}

type funcObject struct {
	baseJsFuncObject
}

type generatorFuncObject struct {
	baseJsFuncObject
}

type asyncFuncObject struct {
	baseJsFuncObject
}

type classFuncObject struct {
	baseJsFuncObject
	initFields   *Program
	computedKeys []Value

	privateEnvType *privateEnvType
	privateMethods []Value

	derived bool
}

type methodFuncObject struct {
	baseJsFuncObject
	homeObject *Object
}

type generatorMethodFuncObject struct {
	methodFuncObject
}

type asyncMethodFuncObject struct {
	methodFuncObject
}

type arrowFuncObject struct {
	baseJsFuncObject
	funcObj   *Object
	newTarget Value
}

type asyncArrowFuncObject struct {
	arrowFuncObject
}

type nativeFuncObject struct {
	baseFuncObject

	f         func(FunctionCall) Value
	construct func(args []Value, newTarget *Object) *Object
}

type wrappedFuncObject struct {
	nativeFuncObject
	wrapped reflect.Value
}

type boundFuncObject struct {
	nativeFuncObject
	wrapped *Object
}

type generatorState uint8

const (
	genStateUndefined generatorState = iota
	genStateSuspendedStart
	genStateExecuting
	genStateSuspendedYield
	genStateSuspendedYieldRes
	genStateCompleted
)

type generatorObject struct {
	baseObject
	gen       generator
	delegated *iteratorRecord
	state     generatorState
}

func ( *nativeFuncObject) () String {
	return newStringValue(fmt.Sprintf("function %s() { [native code] }", nilSafe(.getStr("name", nil)).toString()))
}

func ( *nativeFuncObject) (*objectExportCtx) interface{} {
	return .f
}

func ( *wrappedFuncObject) () reflect.Type {
	return .wrapped.Type()
}

func ( *wrappedFuncObject) (*objectExportCtx) interface{} {
	return .wrapped.Interface()
}

func ( *funcObject) ( unistring.String) Value {
	if  == "prototype" {
		if ,  := .values[]; ! {
			return .addPrototype()
		}
	}
	return nil
}

func ( *funcObject) ( unistring.String,  Value) Value {
	return .getStrWithOwnProp(.getOwnPropStr(), , )
}

func ( *funcObject) ( unistring.String) Value {
	if  := ._addProto();  != nil {
		return 
	}

	return .baseObject.getOwnPropStr()
}

func ( *funcObject) ( unistring.String,  Value,  bool) bool {
	._addProto()
	return .baseObject.setOwnStr(, , )
}

func ( *funcObject) ( unistring.String, ,  Value,  bool) (bool, bool) {
	return ._setForeignStr(, .getOwnPropStr(), , , )
}

func ( *funcObject) ( unistring.String,  PropertyDescriptor,  bool) bool {
	._addProto()
	return .baseObject.defineOwnPropertyStr(, , )
}

func ( *funcObject) ( unistring.String,  bool) bool {
	._addProto()
	return .baseObject.deleteStr(, )
}

func ( *funcObject) () Value {
	 := .val.runtime.NewObject()
	.self._putProp("constructor", .val, true, false, true)
	return ._putProp("prototype", , true, false, false)
}

func ( *funcObject) ( unistring.String) bool {
	if .baseObject.hasOwnPropertyStr() {
		return true
	}

	if  == "prototype" {
		return true
	}
	return false
}

func ( *funcObject) ( bool,  []Value) []Value {
	if  {
		if ,  := .values["prototype"]; ! {
			 = append(, asciiString("prototype"))
		}
	}
	return .baseFuncObject.stringKeys(, )
}

func ( *funcObject) () iterNextFunc {
	if ,  := .values["prototype"]; ! {
		.addPrototype()
	}
	return .baseFuncObject.iterateStringKeys()
}

func ( *baseFuncObject) ( *Object) *Object {
	 := .val.runtime
	if  == nil {
		 = .val
	}
	 := .getPrototypeFromCtor(, nil, .global.ObjectPrototype)

	return .val.runtime.newBaseObject(, classObject).val
}

func ( *baseJsFuncObject) () String {
	return newStringValue(.src)
}

func ( *baseJsFuncObject) ( []Value,  *Object) *Object {
	if  == nil {
		 = .val
	}
	 := .self.getStr("prototype", nil)
	var  *Object
	if ,  := .(*Object);  {
		 = 
	} else {
		 = .val.runtime.global.ObjectPrototype
	}

	 := .val.runtime.newBaseObject(, classObject).val
	 := .call(FunctionCall{
		This:      ,
		Arguments: ,
	}, )

	if ,  := .(*Object);  {
		return 
	}
	return 
}

func ( *classFuncObject) (FunctionCall) Value {
	panic(.val.runtime.NewTypeError("Class constructor cannot be invoked without 'new'"))
}

func ( *classFuncObject) () (func(FunctionCall) Value, bool) {
	return .Call, true
}

func ( *classFuncObject) ( *vm,  int) {
	.Call(FunctionCall{})
}

func ( *classFuncObject) (*objectExportCtx) interface{} {
	return .Call
}

func ( *classFuncObject) ( []Value,  *Object) ( *Object) {
	if .derived {
		if  := .prototype.self.assertConstructor();  != nil {
			 = (, )
		} else {
			panic(.val.runtime.NewTypeError("Super constructor is not a constructor"))
		}
	} else {
		 = .baseFuncObject.createInstance()
	}
	return
}

func ( *classFuncObject) ( *Object) {
	if .privateEnvType != nil {
		 := .self.getPrivateEnv(.privateEnvType, true)
		.methods = .privateMethods
	}
	if .initFields != nil {
		 := .val.runtime.vm
		.pushCtx()
		.prg = .initFields
		.stash = .stash
		.privEnv = .privEnv
		.newTarget = nil

		// so that 'super' base could be correctly resolved (including from direct eval())
		.push(.val)

		.sb = .sp
		.push()
		.pc = 0
		 := .runTry()
		.popCtx()
		if  != nil {
			panic()
		}
		.sp -= 2
	}
}

func ( *classFuncObject) ( []Value,  *Object) *Object {
	if  == nil {
		 = .val
	}
	if .prg == nil {
		 := .createInstance(, )
		._initFields()
		return 
	} else {
		var  *Object
		var  Value
		if !.derived {
			 = .createInstance(, )
			._initFields()
			 = 
		}
		 := ._call(, , )

		if ,  := .(*Object);  {
			return 
		}
		if .derived {
			 := .val.runtime
			if  != _undefined {
				panic(.NewTypeError("Derived constructors may only return object or undefined"))
			}
			if  := .vm.stack[.vm.sp+1];  != nil { // using residual 'this' value (a bit hacky)
				 = .toObject()
			} else {
				panic(.newError(.getReferenceError(), "Must call super constructor in derived class before returning from derived constructor"))
			}
		}
		return 
	}
}

func ( *classFuncObject) () func( []Value,  *Object) *Object {
	return .construct
}

func ( *baseJsFuncObject) ( FunctionCall) Value {
	return .call(, nil)
}

func ( *arrowFuncObject) ( FunctionCall) Value {
	return ._call(.Arguments, .newTarget, nil)
}

func ( *baseJsFuncObject) ( []Value, ,  Value) (Value, *Exception) {
	 := .val.runtime.vm

	.stack.expand(.sp + len() + 1)
	.stack[.sp] = .val
	.sp++
	.stack[.sp] = 
	.sp++
	for ,  := range  {
		if  != nil {
			.stack[.sp] = 
		} else {
			.stack[.sp] = _undefined
		}
		.sp++
	}

	.pushTryFrame(tryPanicMarker, -1)
	defer .popTryFrame()

	var  bool
	if .prg != nil {
		.pushCtx()
		.callStack = append(.callStack, context{pc: -2}) // extra frame so that run() halts after ret
		 = true
	} else {
		.pc = -2
		.pushCtx()
	}

	.args = len()
	.prg = .prg
	.stash = .stash
	.privEnv = .privEnv
	.newTarget = 
	.pc = 0
	for {
		 := .runTryInner()
		if  != nil {
			return nil, 
		}
		if .halted() {
			break
		}
	}
	if  {
		.popCtx()
	}

	return .pop(), nil
}

func ( *baseJsFuncObject) ( []Value, ,  Value) Value {
	,  := .__call(, , )
	if  != nil {
		panic()
	}
	return 
}

func ( *baseJsFuncObject) ( FunctionCall,  Value) Value {
	return ._call(.Arguments, , nilSafe(.This))
}

func ( *baseJsFuncObject) (*objectExportCtx) interface{} {
	return .Call
}

func ( *baseFuncObject) () reflect.Type {
	return reflectTypeFunc
}

func ( *baseFuncObject) () String {
	return stringFunction
}

func ( *baseJsFuncObject) () (func(FunctionCall) Value, bool) {
	return .Call, true
}

func ( *funcObject) () func( []Value,  *Object) *Object {
	return .construct
}

func ( *baseJsFuncObject) ( *vm,  int) {
	.pushCtx()
	.args = 
	.prg = .prg
	.stash = .stash
	.privEnv = .privEnv
	.pc = 0
	.stack[.sp--1], .stack[.sp--2] = .stack[.sp--2], .stack[.sp--1]
}

func ( *arrowFuncObject) () (func(FunctionCall) Value, bool) {
	return .Call, true
}

func ( *arrowFuncObject) ( *vm,  int) {
	.pushCtx()
	.args = 
	.prg = .prg
	.stash = .stash
	.privEnv = .privEnv
	.pc = 0
	.stack[.sp--1], .stack[.sp--2] = nil, .stack[.sp--1]
	.newTarget = .newTarget
}

func ( *arrowFuncObject) (*objectExportCtx) interface{} {
	return .Call
}

func ( *baseFuncObject) ( unistring.String,  Value) {
	.baseObject.init()

	.lenProp.configurable = true
	.lenProp.value = 
	._put("length", &.lenProp)

	._putProp("name", stringValueFromRaw(), false, false, true)
}

func hasInstance( *Object,  Value) bool {
	if ,  := .(*Object);  {
		 := .self.getStr("prototype", nil)
		if ,  := .(*Object);  {
			for {
				 = .self.proto()
				if  == nil {
					return false
				}
				if  ==  {
					return true
				}
			}
		} else {
			panic(.runtime.NewTypeError("prototype is not an object"))
		}
	}

	return false
}

func ( *baseFuncObject) ( Value) bool {
	return hasInstance(.val, )
}

func ( *nativeFuncObject) ( func(ConstructorCall) *Object,  []Value,  *Object) *Object {
	 := .createInstance()
	 := (ConstructorCall{
		This:      ,
		Arguments: ,
		NewTarget: ,
	})

	if  != nil {
		return 
	}
	return 
}

func ( *nativeFuncObject) () (func(FunctionCall) Value, bool) {
	if .f != nil {
		return .f, true
	}
	return nil, false
}

func ( *nativeFuncObject) ( *vm,  int) {
	if .f != nil {
		.pushCtx()
		.prg = nil
		.sb = .sp -  // so that [sb-1] points to the callee
		 := .f(FunctionCall{
			Arguments: .stack[.sp- : .sp],
			This:      .stack[.sp--2],
		})
		if  == nil {
			 = _undefined
		}
		.stack[.sp--2] = 
		.popCtx()
	} else {
		.stack[.sp--2] = _undefined
	}
	.sp -=  + 1
	.pc++
}

func ( *nativeFuncObject) () func( []Value,  *Object) *Object {
	return .construct
}

func ( *boundFuncObject) ( Value) bool {
	return instanceOfOperator(, .wrapped)
}

func ( *baseJsFuncObject) ( FunctionCall) {
	 := .val.runtime.vm
	 := .Arguments
	.stack.expand(.sp + len() + 1)
	.stack[.sp] = .This
	.sp++
	.stack[.sp] = .val
	.sp++
	for ,  := range  {
		if  != nil {
			.stack[.sp] = 
		} else {
			.stack[.sp] = _undefined
		}
		.sp++
	}
}

func ( *baseJsFuncObject) ( FunctionCall,  func(*vm, int)) Value {
	.prepareForVmCall()
	 := &asyncRunner{
		f:      .val,
		vmCall: ,
	}
	.start(len(.Arguments))
	return .promiseCap.promise
}

func ( *asyncFuncObject) ( FunctionCall) Value {
	return .asyncCall(, .baseJsFuncObject.vmCall)
}

func ( *asyncFuncObject) () (func(FunctionCall) Value, bool) {
	return .Call, true
}

func ( *asyncFuncObject) (*objectExportCtx) interface{} {
	return .Call
}

func ( *asyncArrowFuncObject) ( FunctionCall) Value {
	return .asyncCall(, .arrowFuncObject.vmCall)
}

func ( *asyncArrowFuncObject) () (func(FunctionCall) Value, bool) {
	return .Call, true
}

func ( *asyncArrowFuncObject) (*objectExportCtx) interface{} {
	return .Call
}

func ( *asyncArrowFuncObject) ( *vm,  int) {
	.asyncVmCall(, , .arrowFuncObject.vmCall)
}

func ( *asyncMethodFuncObject) ( FunctionCall) Value {
	return .asyncCall(, .methodFuncObject.vmCall)
}

func ( *asyncMethodFuncObject) () (func(FunctionCall) Value, bool) {
	return .Call, true
}

func ( *asyncMethodFuncObject) ( *objectExportCtx) interface{} {
	return .Call
}

func ( *asyncMethodFuncObject) ( *vm,  int) {
	.asyncVmCall(, , .methodFuncObject.vmCall)
}

func ( *baseJsFuncObject) ( *vm,  int,  func(*vm, int)) {
	 := &asyncRunner{
		f:      .val,
		vmCall: ,
	}
	.start()
	.push(.promiseCap.promise)
	.pc++
}

func ( *asyncFuncObject) ( *vm,  int) {
	.asyncVmCall(, , .baseJsFuncObject.vmCall)
}

type asyncRunner struct {
	gen        generator
	promiseCap *promiseCapability
	f          *Object
	vmCall     func(*vm, int)
}

func ( *asyncRunner) ( FunctionCall) Value {
	.gen.vm.curAsyncRunner = 
	defer func() {
		.gen.vm.curAsyncRunner = nil
	}()
	 := .Argument(0)
	, ,  := .gen.next()
	.step(,  == resultNormal, )
	return _undefined
}

func ( *asyncRunner) ( FunctionCall) Value {
	.gen.vm.curAsyncRunner = 
	defer func() {
		.gen.vm.curAsyncRunner = nil
	}()
	 := .Argument(0)
	, ,  := .gen.nextThrow()
	.step(,  == resultNormal, )
	return _undefined
}

func ( *asyncRunner) ( Value,  bool,  *Exception) {
	 := .f.runtime
	if  ||  != nil {
		if  == nil {
			.promiseCap.resolve()
		} else {
			.promiseCap.reject(.val)
		}
		return
	}

	// await
	 := .promiseResolve(.getPromise(), )
	.self.(*Promise).addReactions(&promiseReaction{
		typ:         promiseReactionFulfill,
		handler:     &jobCallback{callback: .onFulfilled},
		asyncRunner: ,
	}, &promiseReaction{
		typ:         promiseReactionReject,
		handler:     &jobCallback{callback: .onRejected},
		asyncRunner: ,
	})
}

func ( *asyncRunner) ( int) {
	 := .f.runtime
	.gen.vm = .vm
	.promiseCap = .newPromiseCapability(.getPromise())
	 := .vm.sp
	.gen.enter()
	.vmCall(.vm, )
	, ,  := .gen.step()
	.step(,  == resultNormal, )
	if  != nil {
		.vm.sp =  -  - 2
	}
	.vm.popTryFrame()
	.vm.popCtx()
}

type generator struct {
	ctx execCtx
	vm  *vm

	tryStackLen, iterStackLen, refStackLen uint32
}

func ( *generator) () {
	.tryStackLen, .iterStackLen, .refStackLen = uint32(len(.vm.tryStack)), uint32(len(.vm.iterStack)), uint32(len(.vm.refStack))
}

func ( *generator) () {
	.vm.pushCtx()
	.vm.pushTryFrame(tryPanicMarker, -1)
	.vm.prg, .vm.sb, .vm.pc = nil, -1, -2 // so that vm.run() halts after ret
	.storeLengths()
}

func ( *generator) () ( Value,  resultType,  *Exception) {
	for {
		 = .vm.runTryInner()
		if  != nil {
			return
		}
		if .vm.halted() {
			break
		}
	}
	 = .vm.pop()
	if ,  := .(*yieldMarker);  {
		 = .resultType
		.ctx = execCtx{}
		.vm.pc = -.vm.pc + 1
		if  != yieldEmpty {
			 = .vm.pop()
		} else {
			 = nil
		}
		.vm.suspend(&.ctx, .tryStackLen, .iterStackLen, .refStackLen)
		.vm.sp = .vm.sb - 1
		.vm.callStack = .vm.callStack[:len(.vm.callStack)-1] // remove the frame with pc == -2, as ret would do
	}
	return
}

func ( *generator) () {
	.vm.pushCtx()
	.vm.pushTryFrame(tryPanicMarker, -1)
	.vm.callStack = append(.vm.callStack, context{pc: -2}) // extra frame so that vm.run() halts after ret
	.storeLengths()
	.vm.resume(&.ctx)
}

func ( *generator) ( Value) (Value, resultType, *Exception) {
	.enterNext()
	if  != nil {
		.vm.push()
	}
	, ,  := .step()
	.vm.popTryFrame()
	.vm.popCtx()
	return , , 
}

func ( *generator) ( interface{}) (Value, resultType, *Exception) {
	.enterNext()
	 := .vm.handleThrow()
	if  != nil {
		.vm.popTryFrame()
		.vm.popCtx()
		return nil, resultNormal, 
	}

	, ,  := .step()
	.vm.popTryFrame()
	.vm.popCtx()
	return , , 
}

func ( *generatorObject) ( func(*vm, int),  int) {
	.baseObject.init()
	 := .val.runtime.vm
	.gen.vm = 

	.gen.enter()
	(, )

	, ,  := .gen.step()

	.popTryFrame()
	if  != nil {
		panic()
	}

	.state = genStateSuspendedStart
	.popCtx()
}

func ( *generatorObject) () {
	if .state == genStateExecuting {
		panic(.val.runtime.NewTypeError("Illegal generator state"))
	}
}

func ( *generatorObject) ( Value,  resultType,  *Exception) Value {
	if  != nil {
		.delegated = nil
		.state = genStateCompleted
		panic()
	}
	switch  {
	case resultYield:
		.state = genStateSuspendedYield
		return .val.runtime.createIterResultObject(, false)
	case resultYieldDelegate:
		.state = genStateSuspendedYield
		return .delegate()
	case resultYieldRes:
		.state = genStateSuspendedYieldRes
		return .val.runtime.createIterResultObject(, false)
	case resultYieldDelegateRes:
		.state = genStateSuspendedYieldRes
		return .delegate()
	case resultNormal:
		.state = genStateCompleted
		return .val.runtime.createIterResultObject(, true)
	default:
		panic(.val.runtime.NewTypeError("Runtime bug: unexpected result type: %v", ))
	}
}

func ( *generatorObject) ( Value) Value {
	 := .val.runtime.try(func() {
		.delegated = .val.runtime.getIterator(, nil)
	})
	if  != nil {
		.delegated = nil
		.state = genStateCompleted
		return .step(.gen.nextThrow())
	}
	return .next(_undefined)
}

func ( *generatorObject) ( func() (Value, bool)) ( Value,  bool) {
	 := .val.runtime.try(func() {
		,  = ()
	})
	if  != nil {
		.delegated = nil
		.state = genStateExecuting
		return .step(.gen.nextThrow()), false
	}
	return
}

func ( *generatorObject) ( func(FunctionCall) Value,  Value) (Value, bool) {
	 := .val.runtime.toObject((FunctionCall{This: .delegated.iterator, Arguments: []Value{}}))
	if iteratorComplete() {
		.delegated = nil
		return iteratorValue(), true
	}
	return , false
}

func ( *generatorObject) ( Value) Value {
	.validate()
	if .state == genStateCompleted {
		return .val.runtime.createIterResultObject(_undefined, true)
	}
	if .delegated != nil {
		,  := .tryCallDelegated(func() (Value, bool) {
			return .callDelegated(.delegated.next, )
		})
		if ! {
			return 
		} else {
			 = 
		}
	}
	if .state != genStateSuspendedYieldRes {
		 = nil
	}
	.state = genStateExecuting
	return .step(.gen.next())
}

func ( *generatorObject) ( Value) Value {
	.validate()
	if .state == genStateSuspendedStart {
		.state = genStateCompleted
	}
	if .state == genStateCompleted {
		panic()
	}
	if  := .delegated;  != nil {
		,  := .tryCallDelegated(func() (Value, bool) {
			 := toMethod(.delegated.iterator.self.getStr("throw", nil))
			if  != nil {
				return .callDelegated(, )
			}
			.delegated = nil
			.returnIter()
			panic(.val.runtime.NewTypeError("The iterator does not provide a 'throw' method"))
		})
		if ! {
			return 
		}
		if .state != genStateSuspendedYieldRes {
			 = nil
		}
		.state = genStateExecuting
		return .step(.gen.next())
	}
	.state = genStateExecuting
	return .step(.gen.nextThrow())
}

func ( *generatorObject) ( Value) Value {
	.validate()
	if .state == genStateSuspendedStart {
		.state = genStateCompleted
	}

	if .state == genStateCompleted {
		return .val.runtime.createIterResultObject(, true)
	}

	if  := .delegated;  != nil {
		,  := .tryCallDelegated(func() (Value, bool) {
			 := toMethod(.delegated.iterator.self.getStr("return", nil))
			if  != nil {
				return .callDelegated(, )
			}
			.delegated = nil
			return , true
		})
		if ! {
			return 
		} else {
			 = 
		}
	}

	.state = genStateExecuting

	.gen.enterNext()

	 := .gen.vm
	var  *Exception
	for len(.tryStack) > 0 {
		 := &.tryStack[len(.tryStack)-1]
		if int(.callStackLen) != len(.callStack) {
			break
		}

		if .finallyPos >= 0 {
			.sp = int(.sp)
			.stash = .stash
			.privEnv = .privEnv
			 := .restoreStacks(.iterLen, .refLen)
			if  != nil {
				 = 
				.popTryFrame()
				continue
			}

			.pc = int(.finallyPos)
			.catchPos = tryPanicMarker
			.finallyPos = -1
			.finallyRet = -2 // -1 would cause it to continue after leaveFinally
			for {
				 := .runTryInner()
				if  != nil {
					 = 
					.popTryFrame()
					break
				}
				if .halted() {
					break
				}
			}
		} else {
			.popTryFrame()
		}
	}

	.state = genStateCompleted

	.popTryFrame()

	if  == nil {
		 = .restoreStacks(.gen.iterStackLen, .gen.refStackLen)
	}

	if  != nil {
		panic()
	}

	.callStack = .callStack[:len(.callStack)-1]
	.sp = .sb - 1
	.popCtx()

	return .val.runtime.createIterResultObject(, true)
}

func ( *baseJsFuncObject) ( func(*vm, int),  int) Value {
	 := &Object{runtime: .val.runtime}

	 := &generatorObject{
		baseObject: baseObject{
			class:      classObject,
			val:        ,
			extensible: true,
		},
	}
	.self = 
	.init(, )
	.prototype = .runtime.getPrototypeFromCtor(.val, nil, .runtime.getGeneratorPrototype())
	return 
}

func ( *baseJsFuncObject) ( func(*vm, int),  int) {
	 := .val.runtime.vm
	.push(.generatorCall(, ))
	.pc++
}

func ( *generatorFuncObject) ( *vm,  int) {
	.generatorVmCall(.baseJsFuncObject.vmCall, )
}

func ( *generatorFuncObject) ( FunctionCall) Value {
	.prepareForVmCall()
	return .generatorCall(.baseJsFuncObject.vmCall, len(.Arguments))
}

func ( *generatorFuncObject) () (func(FunctionCall) Value, bool) {
	return .Call, true
}

func ( *generatorFuncObject) (*objectExportCtx) interface{} {
	return .Call
}

func ( *generatorFuncObject) () func( []Value,  *Object) *Object {
	return nil
}

func ( *generatorMethodFuncObject) ( *vm,  int) {
	.generatorVmCall(.methodFuncObject.vmCall, )
}

func ( *generatorMethodFuncObject) ( FunctionCall) Value {
	.prepareForVmCall()
	return .generatorCall(.methodFuncObject.vmCall, len(.Arguments))
}

func ( *generatorMethodFuncObject) () (func(FunctionCall) Value, bool) {
	return .Call, true
}

func ( *generatorMethodFuncObject) (*objectExportCtx) interface{} {
	return .Call
}