94 lines
2.0 KiB
Go
94 lines
2.0 KiB
Go
package builtin
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"strings"
|
|
"sync"
|
|
|
|
"modernc.org/quickjs"
|
|
)
|
|
|
|
var (
|
|
builtinRegistry = make(map[string]Builtin)
|
|
registryMutex sync.RWMutex
|
|
collector *typeCollector
|
|
)
|
|
|
|
func registerBuiltin[T Args, R any](name string, isAsync bool, fn Func[T, R]) {
|
|
if collector == nil {
|
|
collector = newTypeCollector()
|
|
}
|
|
|
|
var zeroT T
|
|
tType := reflect.TypeOf(zeroT)
|
|
|
|
if tType.Kind() != reflect.Struct {
|
|
panic(fmt.Sprintf("builtin %s: argument must be a struct type, got %v", name, tType))
|
|
}
|
|
|
|
fnType := reflect.TypeOf(fn)
|
|
|
|
wrapper := createWrapper(fn, isAsync)
|
|
types := collector.collectTypes(tType, fnType)
|
|
paramTypes := collector.getParamTypes()
|
|
|
|
registryMutex.Lock()
|
|
b := Builtin{
|
|
Name: name,
|
|
Function: wrapper,
|
|
Definition: generateTypeScriptDefinition(name, tType, fnType, isAsync, paramTypes),
|
|
Types: types,
|
|
ParamTypes: paramTypes,
|
|
}
|
|
builtinRegistry[name] = b
|
|
registryMutex.Unlock()
|
|
}
|
|
|
|
func GetBuiltinsDeclarations() string {
|
|
registryMutex.RLock()
|
|
defer registryMutex.RUnlock()
|
|
|
|
typeDefinitions := make(map[string]bool)
|
|
var typeDefs []string
|
|
var functionDecls []string
|
|
|
|
for _, builtin := range builtinRegistry {
|
|
for _, t := range builtin.Types {
|
|
if !typeDefinitions[t] {
|
|
typeDefinitions[t] = true
|
|
typeDefs = append(typeDefs, t)
|
|
}
|
|
}
|
|
functionDecls = append(functionDecls, builtin.Definition)
|
|
}
|
|
|
|
result := strings.Join(typeDefs, "\n\n")
|
|
if len(result) > 0 && len(functionDecls) > 0 {
|
|
result += "\n\n"
|
|
}
|
|
result += strings.Join(functionDecls, "\n")
|
|
|
|
return result
|
|
}
|
|
|
|
func RegisterBuiltin[T Args, R any](name string, fn Func[T, R]) {
|
|
registerBuiltin(name, false, fn)
|
|
}
|
|
|
|
func RegisterAsyncBuiltin[T Args, R any](name string, fn Func[T, R]) {
|
|
registerBuiltin(name, true, fn)
|
|
}
|
|
|
|
func RegisterBuiltins(vm *quickjs.VM) {
|
|
registryMutex.RLock()
|
|
defer registryMutex.RUnlock()
|
|
|
|
for name, builtin := range builtinRegistry {
|
|
err := vm.RegisterFunc(name, builtin.Function, false)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("failed to register builtin %s: %v", name, err))
|
|
}
|
|
}
|
|
}
|