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)) } } }