package wasm

import (
	
	

	
	
)

// LookupFunction looks up the table by the given index, and returns the api.Function implementation if found,
// otherwise this panics according to the same semantics as call_indirect instruction.
// Currently, this is only used by emscripten which needs to do call_indirect-like operation in the host function.
func ( *ModuleInstance) ( *TableInstance,  FunctionTypeID,  Index) api.Function {
	,  := .Engine.LookupFunction(, , )
	if  := .Source; .IsHostModule {
		// This case, the found function is a host function stored in the table. Generally, Engine.NewFunction are only
		// responsible for calling Wasm-defined functions (not designed for calling Go functions!). Hence we need to wrap
		// the host function as a special case.
		 := &.FunctionDefinitionSection[]
		 := .CodeSection[].GoFunc
		switch typed := .(type) {
		case api.GoFunction:
			// GoFunction doesn't need looked up module.
			return &lookedUpGoFunction{def: , g: goFunctionAsGoModuleFunction()}
		case api.GoModuleFunction:
			return &lookedUpGoFunction{def: , lookedUpModule: , g: }
		default:
			panic(fmt.Sprintf("unexpected GoFunc type: %T", ))
		}
	} else {
		return .Engine.NewFunction()
	}
}

// lookedUpGoFunction implements lookedUpGoModuleFunction.
type lookedUpGoFunction struct {
	internalapi.WazeroOnly
	def *FunctionDefinition
	// lookedUpModule is the *ModuleInstance from which this Go function is looked up, i.e. owner of the table.
	lookedUpModule *ModuleInstance
	g              api.GoModuleFunction
}

// goFunctionAsGoModuleFunction converts api.GoFunction to api.GoModuleFunction which ignores the api.Module argument.
func goFunctionAsGoModuleFunction( api.GoFunction) api.GoModuleFunction {
	return api.GoModuleFunc(func( context.Context,  api.Module,  []uint64) {
		.Call(, )
	})
}

// Definition implements api.Function.
func ( *lookedUpGoFunction) () api.FunctionDefinition { return .def }

// Call implements api.Function.
func ( *lookedUpGoFunction) ( context.Context,  ...uint64) ([]uint64, error) {
	 := .def.Functype
	 := .ParamNumInUint64
	 := .ResultNumInUint64
	if  >  {
		 = 
	}
	 := make([]uint64, )
	copy(, )
	return [:], .CallWithStack(, )
}

// CallWithStack implements api.Function.
func ( *lookedUpGoFunction) ( context.Context,  []uint64) error {
	// The Go host function always needs to access caller's module, in this case the one holding the table.
	.g.Call(, .lookedUpModule, )
	return nil
}