Skip to content

Commit 1596243

Browse files
committed
perf: internalize stdlib builtins and remove stdlib source LSP plumbing
1 parent 4d44e35 commit 1596243

16 files changed

Lines changed: 883 additions & 548 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ All notable changes to FScript are documented in this file.
88
- Optimized runtime invocation paths by reducing argument list churn and improving closure application in `Eval.invokeValue`.
99
- Cached stdlib loading and reserved-name computation to avoid repeated parse/inference work.
1010
- Optimized `ScriptHost` exported symbol access by caching function/value sets and maps for faster `invoke` and `getValue`.
11+
- Moved stdlib `List.*`, `Option.*`, `Map.*`, `Environment`, and `FsKind` definitions to native language/runtime built-ins to remove stdlib source parsing/inference at load time.
12+
- Removed virtual stdlib source navigation plumbing from LSP (`fscript/stdlibSource`) and updated injected symbol/type resolution to rely on native built-in metadata.
1113

1214
## [0.57.0]
1315

src/FScript.CSharpInterop/InteropServices.fs

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -39,37 +39,3 @@ let Env = asEnvironment { ScriptName = None; Arguments = [] }
3939

4040
let inferProgramWithExternsAndLocalVariableTypes (externs: ExternalFunction list) (program: Program) : TypeInfer.TypedProgram * TypeInfer.LocalVariableTypeInfo list =
4141
TypeInfer.inferProgramWithExternsAndLocalVariableTypes externs (withLspEnvironmentPrelude program)
42-
43-
let inferStdlibWithExternsRaw (externs: ExternalFunction list) : TypeInfer.TypedProgram =
44-
TypeInfer.inferProgramWithExternsRaw externs (Stdlib.loadProgram())
45-
46-
let stdlibProgram () : Program =
47-
Stdlib.loadProgram()
48-
49-
let tryLoadStdlibSourceText (uri: string) : string option =
50-
try
51-
let parsed = Uri(uri)
52-
if not (String.Equals(parsed.Scheme, "fscript-stdlib", StringComparison.OrdinalIgnoreCase)) then
53-
None
54-
else
55-
let fileName = parsed.AbsolutePath.TrimStart('/')
56-
let resourceName =
57-
match fileName with
58-
| "Option.fss" -> Some "FScript.Language.Stdlib.Option.fss"
59-
| "List.fss" -> Some "FScript.Language.Stdlib.List.fss"
60-
| "Map.fss" -> Some "FScript.Language.Stdlib.Map.fss"
61-
| "Environment.fss" -> Some "FScript.Language.Stdlib.Environment.fss"
62-
| _ -> None
63-
64-
match resourceName with
65-
| None -> None
66-
| Some name ->
67-
let assembly = typeof<Span>.Assembly
68-
match assembly.GetManifestResourceStream(name) with
69-
| null -> None
70-
| stream ->
71-
use stream = stream
72-
use reader = new StreamReader(stream)
73-
Some(reader.ReadToEnd())
74-
with _ ->
75-
None

src/FScript.CSharpInterop/LanguageServer/LspHandlers.fs

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1703,24 +1703,6 @@ module LspHandlers =
17031703
| _ ->
17041704
LspProtocol.sendResponse idNode None
17051705

1706-
let handleStdlibSource (idNode: JsonNode) (paramsObj: JsonObject) =
1707-
match tryGetString paramsObj "uri" with
1708-
| None ->
1709-
sendCommandError idNode "internal" "Missing stdlib URI."
1710-
| Some uri ->
1711-
match InteropServices.tryLoadStdlibSourceText uri with
1712-
| Some sourceText ->
1713-
let response = JsonObject()
1714-
response["ok"] <- JsonValue.Create(true)
1715-
let data = JsonObject()
1716-
data["uri"] <- JsonValue.Create(uri)
1717-
data["text"] <- JsonValue.Create(sourceText)
1718-
data["languageId"] <- JsonValue.Create("fscript")
1719-
response["data"] <- data
1720-
LspProtocol.sendResponse idNode (Some response)
1721-
| None ->
1722-
sendCommandError idNode "internal" $"Unable to load stdlib source for '{uri}'."
1723-
17241706
let handleRename (idNode: JsonNode) (paramsObj: JsonObject) =
17251707
match tryGetUriFromTextDocument paramsObj, tryGetPosition paramsObj, tryGetString paramsObj "newName" with
17261708
| Some _, Some _, Some newName when not (isValidIdentifierName newName) ->

src/FScript.CSharpInterop/LanguageServer/LspModel.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ module LspModel =
1111
let mutable debugLoggingEnabled = false
1212
let mutable lastDefinitionRequest: (string * int * int * DateTime) option = None
1313

14-
let stdlibNames = Stdlib.reservedNames() |> Set.toList
14+
let stdlibNames = BuiltinSignatures.builtinReservedNames |> Set.toList
1515
let builtinNames = [ "ignore"; "nameof"; "typeof" ]
1616

1717
let reservedKeywords =

src/FScript.CSharpInterop/LanguageServer/LspSymbols.fs

Lines changed: 63 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -45,79 +45,71 @@ module LspSymbols =
4545
match scheme with
4646
| Forall (_, t) -> Types.typeToString t
4747

48-
let private stdlibFunctionSignatures : Lazy<Map<string, string>> =
48+
let private builtinSignatures : Lazy<Map<string, string>> =
4949
lazy
50-
let typedStdlib = InteropServices.inferStdlibWithExternsRaw []
51-
typedStdlib
52-
|> List.collect (function
53-
| TypeInfer.TSLet(name, _, t, _, _, _) ->
54-
match t with
55-
| TFun _ -> [ name, Types.typeToString t ]
56-
| _ -> []
57-
| TypeInfer.TSLetRecGroup(bindings, _, _) ->
58-
bindings
59-
|> List.choose (fun (name, _, t, _) ->
60-
match t with
61-
| TFun _ -> Some (name, Types.typeToString t)
62-
| _ -> None)
63-
| _ -> [])
64-
|> Map.ofList
65-
66-
let private tryStdlibVirtualUriFromSource (sourceFile: string option) =
67-
match sourceFile with
68-
| Some file when file.EndsWith("Stdlib.Option.fss", StringComparison.Ordinal) || file.EndsWith("Option.fss", StringComparison.Ordinal) -> Some "fscript-stdlib:///Option.fss"
69-
| Some file when file.EndsWith("Stdlib.List.fss", StringComparison.Ordinal) || file.EndsWith("List.fss", StringComparison.Ordinal) -> Some "fscript-stdlib:///List.fss"
70-
| Some file when file.EndsWith("Stdlib.Map.fss", StringComparison.Ordinal) || file.EndsWith("Map.fss", StringComparison.Ordinal) -> Some "fscript-stdlib:///Map.fss"
71-
| Some file when file.EndsWith("Stdlib.Environment.fss", StringComparison.Ordinal) || file.EndsWith("Environment.fss", StringComparison.Ordinal) -> Some "fscript-stdlib:///Environment.fss"
72-
| _ -> None
73-
74-
let private stdlibFunctionParameterNames : Lazy<Map<string, string list>> =
75-
lazy
76-
InteropServices.stdlibProgram()
77-
|> List.collect (function
78-
| SLet(name, args, _, _, _, _, _) ->
79-
[ name, (args |> List.map (fun p -> p.Name)) ]
80-
| SLetRecGroup(bindings, _, _) ->
81-
bindings
82-
|> List.map (fun (name, args, _, _, _) -> name, (args |> List.map (fun p -> p.Name)))
83-
| _ -> [])
84-
|> Map.ofList
85-
86-
let private stdlibFunctionDefinitions : Lazy<Map<string, (string * Span)>> =
87-
lazy
88-
InteropServices.stdlibProgram()
89-
|> List.collect (function
90-
| SLet(name, _, _, _, _, _, span) ->
91-
match tryStdlibVirtualUriFromSource span.Start.File with
92-
| Some uri -> [ name, (uri, span) ]
93-
| None -> []
94-
| SLetRecGroup(bindings, _, _) ->
95-
bindings
96-
|> List.collect (fun (name, _, _, _, span) ->
97-
match tryStdlibVirtualUriFromSource span.Start.File with
98-
| Some uri -> [ name, (uri, span) ]
99-
| None -> [])
100-
| _ -> [])
101-
|> Map.ofList
102-
103-
let private stdlibTypeDefinitions : Lazy<Map<string, (string * Span)>> =
104-
lazy
105-
InteropServices.stdlibProgram()
106-
|> List.collect (function
107-
| SType typeDef ->
108-
match tryStdlibVirtualUriFromSource typeDef.Span.Start.File with
109-
| Some uri -> [ typeDef.Name, (uri, typeDef.Span) ]
110-
| None -> []
111-
| _ -> [])
112-
|> Map.ofList
50+
BuiltinSignatures.builtinSchemes
51+
|> Map.map (fun _ signature -> schemeTypeToString signature)
52+
53+
let private builtinParameterNames : Map<string, string list> =
54+
[ "ignore", [ "value" ]
55+
"print", [ "message" ]
56+
"Int.tryParse", [ "value" ]
57+
"Float.tryParse", [ "value" ]
58+
"Bool.tryParse", [ "value" ]
59+
"Int.toString", [ "value" ]
60+
"Float.toString", [ "value" ]
61+
"Bool.toString", [ "value" ]
62+
"String.replace", [ "oldValue"; "newValue"; "source" ]
63+
"String.indexOf", [ "value"; "source" ]
64+
"String.toLower", [ "source" ]
65+
"String.toUpper", [ "source" ]
66+
"String.substring", [ "start"; "length"; "source" ]
67+
"String.concat", [ "separator"; "values" ]
68+
"String.split", [ "separator"; "source" ]
69+
"String.endsWith", [ "suffix"; "source" ]
70+
"List.empty", []
71+
"List.map", [ "mapper"; "values" ]
72+
"List.iter", [ "iterator"; "values" ]
73+
"List.choose", [ "chooser"; "values" ]
74+
"List.collect", [ "collector"; "values" ]
75+
"List.exists", [ "predicate"; "values" ]
76+
"List.contains", [ "needle"; "values" ]
77+
"List.rev", [ "values" ]
78+
"List.distinct", [ "values" ]
79+
"List.fold", [ "folder"; "state"; "values" ]
80+
"List.filter", [ "predicate"; "values" ]
81+
"List.length", [ "values" ]
82+
"List.tryFind", [ "predicate"; "values" ]
83+
"List.tryGet", [ "predicate"; "values" ]
84+
"List.tryHead", [ "values" ]
85+
"List.tail", [ "values" ]
86+
"List.append", [ "left"; "right" ]
87+
"Option.defaultValue", [ "fallback"; "value" ]
88+
"Option.defaultWith", [ "fallback"; "value" ]
89+
"Option.isNone", [ "value" ]
90+
"Option.isSome", [ "value" ]
91+
"Option.map", [ "mapper"; "value" ]
92+
"Map.empty", []
93+
"Map.tryGet", [ "key"; "values" ]
94+
"Map.containsKey", [ "key"; "values" ]
95+
"Map.add", [ "key"; "value"; "values" ]
96+
"Map.ofList", [ "pairs" ]
97+
"Map.fold", [ "folder"; "state"; "values" ]
98+
"Map.count", [ "values" ]
99+
"Map.filter", [ "predicate"; "values" ]
100+
"Map.choose", [ "chooser"; "values" ]
101+
"Map.map", [ "mapper"; "values" ]
102+
"Map.iter", [ "iterator"; "values" ]
103+
"Map.remove", [ "key"; "values" ] ]
104+
|> Map.ofList
113105

114106
let private buildInjectedFunctionData (externs: ExternalFunction list) =
115107
let fromExterns =
116108
externs
117109
|> List.map (fun ext -> ext.Name, schemeTypeToString ext.Scheme)
118110
|> Map.ofList
119111

120-
let builtinSignatures =
112+
let builtinCoreSignatures =
121113
[ "ignore", "'a -> unit"
122114
"print", "string -> unit"
123115
"Int.tryParse", "string -> int option"
@@ -144,19 +136,18 @@ module LspSymbols =
144136
|> Map.ofList
145137

146138
let signatures =
147-
stdlibFunctionSignatures.Value
139+
builtinSignatures.Value
148140
|> Map.fold (fun acc name signature -> acc |> Map.add name signature) fromExterns
149-
|> Map.fold (fun acc name signature -> acc |> Map.add name signature) builtinSignatures
141+
|> Map.fold (fun acc name signature -> acc |> Map.add name signature) builtinCoreSignatures
150142

151143
let paramNames =
152-
stdlibFunctionParameterNames.Value
144+
builtinParameterNames
153145
|> Map.fold (fun acc name names -> acc |> Map.add name names) builtinParamNames
154146

155-
signatures, paramNames, stdlibFunctionDefinitions.Value
147+
signatures, paramNames, Map.empty
156148

157-
let tryFindInjectedTypeDefinition (typeName: string) =
158-
stdlibTypeDefinitions.Value
159-
|> Map.tryFind typeName
149+
let tryFindInjectedTypeDefinition (_typeName: string) : (string * Span) option =
150+
None
160151

161152
let rec private typeRefToString (typeRef: TypeRef) =
162153
match typeRef with

0 commit comments

Comments
 (0)