Skip to content

Commit ad65d0a

Browse files
committed
Expose exported function signatures for host-side invocation
1 parent c0b90df commit ad65d0a

1 file changed

Lines changed: 53 additions & 0 deletions

File tree

src/FScript.Runtime/ScriptHost.fs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,17 @@ open System.IO
44
open FScript.Language
55

66
module 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

Comments
 (0)