@@ -4,10 +4,17 @@ open System.IO
44open FScript.Language
55
66module ScriptHost =
7+ type FunctionSignature =
8+ { Name: string
9+ ParameterNames: string list
10+ ParameterTypes: Type list
11+ ReturnType: Type }
12+
713 type LoadedScript =
814 { TypeDefs: Map < string , Type >
915 Env: Env
1016 ExportedFunctionNames: string list
17+ ExportedFunctionSignatures: Map < string , FunctionSignature >
1118 ExportedValueNames: string list
1219 LastValue: Value }
1320
@@ -25,6 +32,47 @@ module ScriptHost =
2532 | TypeInfer.TSLetRecGroup( bindings, isExported, _) when isExported -> bindings |> List.map ( fun ( name , _ , _ , _ ) -> name)
2633 | _ -> [])
2734
35+ let private flattenFunctionType ( t : Type ) : Type list * Type =
36+ let rec loop ( acc : Type list ) ( current : Type ) =
37+ match current with
38+ | TFun ( arg, ret) -> loop ( arg :: acc) ret
39+ | _ -> List.rev acc, current
40+ loop [] t
41+
42+ let private flattenParameterNames ( expr : Expr ) : string list =
43+ let rec loop ( acc : string list ) ( current : Expr ) =
44+ match current with
45+ | ELambda ( param, body, _) -> loop ( param.Name :: acc) body
46+ | _ -> List.rev acc
47+ loop [] expr
48+
49+ let private collectFunctionSignatures ( program : TypeInfer.TypedProgram ) : Map < string , FunctionSignature > =
50+ let fromLet name expr exprType =
51+ let paramNames = flattenParameterNames expr
52+ let parameterTypes , returnType = flattenFunctionType exprType
53+ if paramNames.IsEmpty || parameterTypes.IsEmpty then
54+ None
55+ elif paramNames.Length <> parameterTypes.Length then
56+ raise ( HostCommon.evalError $" Signature mismatch for function '{name}'" )
57+ else
58+ Some ( name,
59+ { Name = name
60+ ParameterNames = paramNames
61+ ParameterTypes = parameterTypes
62+ ReturnType = returnType })
63+
64+ program
65+ |> List.collect ( function
66+ | TypeInfer.TSLet( name, expr, exprType, _, isExported, _) when isExported ->
67+ match fromLet name expr exprType with
68+ | Some signature -> [ signature ]
69+ | None -> []
70+ | TypeInfer.TSLetRecGroup( bindings, isExported, _) when isExported ->
71+ bindings
72+ |> List.choose ( fun ( name , expr , exprType , _ ) -> fromLet name expr exprType)
73+ | _ -> [])
74+ |> Map.ofList
75+
2876 let loadSource ( externs : ExternalFunction list ) ( source : string ) : LoadedScript =
2977 let program = FScript.parse source
3078 let typed = FScript.inferWithExterns externs program
@@ -41,6 +89,10 @@ module ScriptHost =
4189 | Some value -> isCallable value
4290 | None -> false )
4391
92+ let functionSignatures =
93+ collectFunctionSignatures typed
94+ |> Map.filter ( fun name _ -> functionNames |> List.contains name)
95+
4496 let valueNames =
4597 exportedNames
4698 |> List.filter ( fun name ->
@@ -51,6 +103,7 @@ module ScriptHost =
51103 { TypeDefs = state.TypeDefs
52104 Env = state.Env
53105 ExportedFunctionNames = functionNames
106+ ExportedFunctionSignatures = functionSignatures
54107 ExportedValueNames = valueNames
55108 LastValue = state.LastValue }
56109
0 commit comments