package wasm

import (
	
	

	
	
)

type HostFuncExporter interface {
	ExportHostFunc(*HostFunc)
}

// HostFunc is a function with an inlined type, used for NewHostModule.
// Any corresponding FunctionType will be reused or added to the Module.
type HostFunc struct {
	// ExportName is the only value returned by api.FunctionDefinition.
	ExportName string

	// Name is equivalent to the same method on api.FunctionDefinition.
	Name string

	// ParamTypes is equivalent to the same method on api.FunctionDefinition.
	ParamTypes []ValueType

	// ParamNames is equivalent to the same method on api.FunctionDefinition.
	ParamNames []string

	// ResultTypes is equivalent to the same method on api.FunctionDefinition.
	ResultTypes []ValueType

	// ResultNames is equivalent to the same method on api.FunctionDefinition.
	ResultNames []string

	// Code is the equivalent function in the SectionIDCode.
	Code Code
}

// WithGoModuleFunc returns a copy of the function, replacing its Code.GoFunc.
func ( *HostFunc) ( api.GoModuleFunc) *HostFunc {
	 := *
	.Code.GoFunc = 
	return &
}

// NewHostModule is defined internally for use in WASI tests and to keep the code size in the root directory small.
func (
	 string,
	 []string,
	 map[string]*HostFunc,
	 api.CoreFeatures,
) ( *Module,  error) {
	if  != "" {
		 = &Module{NameSection: &NameSection{ModuleName: }}
	} else {
		return nil, errors.New("a module name must not be empty")
	}

	if  := uint32(len());  > 0 {
		.ExportSection = make([]Export, 0, )
		.Exports = make(map[string]*Export, )
		if  = addFuncs(, , , );  != nil {
			return
		}
	}

	.IsHostModule = true
	// Uses the address of *wasm.Module as the module ID so that host functions can have each state per compilation.
	// Downside of this is that compilation cache on host functions (trampoline codes for Go functions and
	// Wasm codes for Wasm-implemented host functions) are not available and compiles each time. On the other hand,
	// compilation of host modules is not costly as it's merely small trampolines vs the real-world native Wasm binary.
	// TODO: refactor engines so that we can properly cache compiled machine codes for host modules.
	.AssignModuleID([]byte(fmt.Sprintf("@@@@@@@@%p", )), // @@@@@@@@ = any 8 bytes different from Wasm header.
		nil, false)
	return
}

func addFuncs(
	 *Module,
	 []string,
	 map[string]*HostFunc,
	 api.CoreFeatures,
) ( error) {
	if .NameSection == nil {
		.NameSection = &NameSection{}
	}
	 := .NameSection.ModuleName

	for ,  := range  {
		 := []
		if .Name == "" {
			.Name =  // default name to export name
		}
		switch .Code.GoFunc.(type) {
		case api.GoModuleFunction, api.GoFunction:
			continue // already parsed
		}

		// Resolve the code using reflection
		.ParamTypes, .ResultTypes, .Code,  = parseGoReflectFunc(.Code.GoFunc)
		if  != nil {
			return fmt.Errorf("func[%s.%s] %w", , , )
		}

		// Assign names to the function, if they exist.
		 := .ParamTypes
		if  := .ParamNames;  != nil {
			if  := len();  != len() {
				return fmt.Errorf("func[%s.%s] has %d params, but %d params names", , , , len())
			}
		}

		 := .ResultTypes
		if  := .ResultNames;  != nil {
			if  := len();  != len() {
				return fmt.Errorf("func[%s.%s] has %d results, but %d results names", , , , len())
			}
		}
	}

	 := uint32(len())
	.NameSection.FunctionNames = make([]NameAssoc, 0, )
	.FunctionSection = make([]Index, 0, )
	.CodeSection = make([]Code, 0, )

	 := Index(0)
	for ,  := range  {
		 := []
		 := wasmdebug.FuncName(, , )
		,  := .maybeAddType(.ParamTypes, .ResultTypes, )
		if  != nil {
			return fmt.Errorf("func[%s] %v", , )
		}
		.FunctionSection = append(.FunctionSection, )
		.CodeSection = append(.CodeSection, .Code)

		 := .ExportName
		.ExportSection = append(.ExportSection, Export{Type: ExternTypeFunc, Name: , Index: })
		.Exports[] = &.ExportSection[len(.ExportSection)-1]
		.NameSection.FunctionNames = append(.NameSection.FunctionNames, NameAssoc{Index: , Name: .Name})

		if len(.ParamNames) > 0 {
			 := NameMapAssoc{Index: }
			for ,  := range .ParamNames {
				.NameMap = append(.NameMap, NameAssoc{Index: Index(), Name: })
			}
			.NameSection.LocalNames = append(.NameSection.LocalNames, )
		}
		if len(.ResultNames) > 0 {
			 := NameMapAssoc{Index: }
			for ,  := range .ResultNames {
				.NameMap = append(.NameMap, NameAssoc{Index: Index(), Name: })
			}
			.NameSection.ResultNames = append(.NameSection.ResultNames, )
		}
		++
	}
	return nil
}

func ( *Module) (,  []ValueType,  api.CoreFeatures) (Index, error) {
	if len() > 1 {
		// Guard >1.0 feature multi-value
		if  := .RequireEnabled(api.CoreFeatureMultiValue);  != nil {
			return 0, fmt.Errorf("multiple result types invalid as %v", )
		}
	}
	for  := range .TypeSection {
		 := &.TypeSection[]
		if .EqualsSignature(, ) {
			return Index(), nil
		}
	}

	 := .SectionElementCount(SectionIDType)
	.TypeSection = append(.TypeSection, FunctionType{Params: , Results: })
	return , nil
}