Skip to content

Commit d474efb

Browse files
committed
Simplify External Type Resolution
Remove some of the indirection from external type resolution now that we don't pre-walk the externs.
1 parent 8f79426 commit d474efb

File tree

2 files changed

+129
-136
lines changed

2 files changed

+129
-136
lines changed

src/Feersum/Builtins.fs

+103-135
Original file line numberDiff line numberDiff line change
@@ -74,75 +74,43 @@ let private addEnvDecls (assm: AssemblyDefinition) =
7474

7575
envTy
7676

77-
/// Map the exports of a given type using `onGlobal` for `LispExport`s and
78-
/// `onBuiltin` for `LispBuiltin`s.
79-
let private cataExports onGlobal onBuiltin (ty: TypeDefinition) =
80-
81-
let unpackStringArg (attr: CustomAttribute) =
82-
attr.ConstructorArguments.[0].Value.ToString()
83-
84-
let chooseMatching name onMatching (things: seq<'a> when 'a:> ICustomAttributeProvider) =
85-
things
86-
|> Seq.choose (fun thing ->
87-
thing.CustomAttributes
88-
|> Seq.tryPick (fun attr ->
89-
if attr.AttributeType.Name = name then
90-
Some(onMatching (unpackStringArg attr) thing)
91-
else
92-
None))
93-
94-
let exports =
95-
ty.Fields |> chooseMatching "LispExportAttribute" (onGlobal ty.FullName)
96-
let builtins =
97-
ty.Methods |> chooseMatching "LispBuiltinAttribute" (onBuiltin ty.FullName)
98-
99-
Seq.append exports builtins
100-
101-
/// Get Exported items from a given Mono type definition.
102-
let private getExports =
103-
cataExports (fun ty name field -> (name, Global(ty, Field field.Name))) (fun ty name meth -> (name, Global(ty, Method meth.Name)))
104-
>> List.ofSeq
105-
106-
/// Maybe map a given type if it has a `LispLibrary` name.
107-
let private tryCataType onLib (ty: TypeDefinition) =
108-
ty.CustomAttributes
109-
|> Seq.tryPick (fun attr ->
110-
if attr.AttributeType.Name = "LispLibraryAttribute" then
111-
Some(attr.ConstructorArguments.[0].Value :?> CustomAttributeArgument[])
112-
else
113-
None)
114-
|> Option.map (onLib ty)
115-
116-
/// Try to convert a given type definition into a library signature.
117-
let private tryGetSignatureFromType =
118-
tryCataType (fun ty name ->
119-
(ty, { LibraryName = name |> Seq.map (fun a -> a.Value.ToString()) |> List.ofSeq
120-
; Exports = getExports ty }))
121-
122-
/// Convert a method reference on a generic type to a method reference on a bound
123-
/// generic instance type.
124-
///
125-
/// https://stackoverflow.com/a/16433452/1353098 - CC BY-SA 4.0
126-
let private makeHostInstanceGeneric args (method: MethodReference) =
127-
let reference =
128-
MethodReference(
129-
method.Name,
130-
method.ReturnType,
131-
method.DeclaringType.MakeGenericInstanceType(args)
132-
)
133-
reference.HasThis <- method.HasThis
134-
reference.ExplicitThis <- method.ExplicitThis
135-
reference.CallingConvention <- method.CallingConvention
136-
137-
method.Parameters
138-
|> Seq.iter (fun parameter ->
139-
reference.Parameters.Add(ParameterDefinition(parameter.ParameterType)))
140-
141-
method.GenericParameters
142-
|> Seq.iter (fun genericParam ->
143-
reference.GenericParameters.Add(GenericParameter(genericParam.Name, reference)))
144-
145-
reference
77+
// -------------------- External Reference Utils -----------------------------
78+
79+
[<AutoOpen>]
80+
module private ExternUtils =
81+
82+
/// Get Exported items from a given Mono type definition.
83+
let private getExports (ty: TypeDefinition) =
84+
85+
let unpackStringArg (attr: CustomAttribute) =
86+
attr.ConstructorArguments.[0].Value.ToString()
87+
88+
let chooseMatching name onMatching (things: seq<'a> when 'a:> ICustomAttributeProvider) =
89+
things
90+
|> Seq.choose (fun thing ->
91+
thing.CustomAttributes
92+
|> Seq.tryPick (fun attr ->
93+
if attr.AttributeType.Name = name then
94+
Some(((unpackStringArg attr), Global(ty.FullName, (onMatching thing))))
95+
else
96+
None))
97+
98+
let exports = ty.Fields |> chooseMatching "LispExportAttribute" (fun x -> Field(x.Name))
99+
let builtins = ty.Methods |> chooseMatching "LispBuiltinAttribute" (fun x -> Method(x.Name))
100+
101+
Seq.append exports builtins |> List.ofSeq
102+
103+
/// Try to convert a given type definition into a library signature.
104+
let tryGetSignatureFromType (ty: TypeDefinition) =
105+
ty.CustomAttributes
106+
|> Seq.tryPick (fun attr ->
107+
if attr.AttributeType.Name = "LispLibraryAttribute" then
108+
Some(attr.ConstructorArguments.[0].Value :?> CustomAttributeArgument[])
109+
else
110+
None)
111+
|> Option.map (fun name ->
112+
(ty, { LibraryName = name |> Seq.map (fun a -> a.Value.ToString()) |> List.ofSeq
113+
; Exports = getExports ty }))
146114

147115
/// Scan the `externAssms` and retrieve the core types that are required to
148116
/// compile a scheme progrma. These `CoreTypes` represent the types and methods
@@ -213,75 +181,75 @@ let private loadCoreTypes (lispAssm: AssemblyDefinition) (externAssms: seq<Assem
213181

214182
// -------------------- Builtin Macro Definitions -----------------------------
215183

216-
217-
/// Parse a builtin macro from syntax rules
218-
let private parseBuiltinMacro id rules =
219-
let (node, errs) =
220-
Syntax.readExpr1 (sprintf "builtin-%s" id) rules
221-
if Diagnostics.hasErrors errs then
222-
icef "Error in builtin macro: %A" errs
223-
match node with
224-
| { Kind = AstNodeKind.Seq([n])} -> n
225-
| n -> n
226-
|> Macros.parseSyntaxRules id
227-
|> ResultEx.unwrap
228-
229-
230-
/// Builtin `and` Macro
231-
let private macroAnd =
232-
"(syntax-rules ::: ()
233-
((_ a) a)
234-
((_ a b :::) (if a (and b :::) #f))
235-
((_) #t))"
236-
|> parseBuiltinMacro "and"
237-
238-
/// Builtin `or` Macro
239-
let private macroOr =
240-
"(syntax-rules ()
241-
((or) #f)
242-
((or test) test)
243-
((or test1 test2 ...)
244-
(let ((|90a3b246-0d7b-4f47-8e1e-0a9f0e7e3288| test1))
245-
(if |90a3b246-0d7b-4f47-8e1e-0a9f0e7e3288| |90a3b246-0d7b-4f47-8e1e-0a9f0e7e3288| (or test2 ...)))))"
246-
|> parseBuiltinMacro "or"
247-
248-
/// Builtin `when` Macro
249-
let private macroWhen =
250-
"(syntax-rules ()
251-
((_ cond expr expr1 ...)
252-
(if cond
253-
(begin
254-
expr
255-
expr1 ...))))"
256-
|> parseBuiltinMacro "when"
257-
258-
/// Builtin `unless` Macro
259-
let private macroUnless =
260-
"(syntax-rules ()
261-
((_ cond expr expr1 ...)
262-
(if (not cond)
263-
(begin
264-
expr
265-
expr1 ...))))"
266-
|> parseBuiltinMacro "unless"
267-
268-
269-
/// Folds a sequence of references into a single pair of lists
270-
let private combineSignatures sigs =
271-
sigs
272-
|> Seq.fold (fun (tys, sigs) (t, s) -> (t :: tys, s :: sigs)) ([], [])
273-
274-
/// The list of builtin macros
275-
let private coreMacros =
276-
{ LibraryName = ["scheme";"base"]
277-
; Exports =
278-
[ macroAnd ; macroOr; macroWhen; macroUnless ]
279-
|> List.map (fun m -> (m.Name, StorageRef.Macro(m))) }
184+
module private BuiltinMacros =
185+
186+
/// Parse a builtin macro from syntax rules
187+
let private parseBuiltinMacro id rules =
188+
let (node, errs) =
189+
Syntax.readExpr1 (sprintf "builtin-%s" id) rules
190+
if Diagnostics.hasErrors errs then
191+
icef "Error in builtin macro: %A" errs
192+
match node with
193+
| { Kind = AstNodeKind.Seq([n])} -> n
194+
| n -> n
195+
|> Macros.parseSyntaxRules id
196+
|> ResultEx.unwrap
197+
198+
199+
/// Builtin `and` Macro
200+
let private macroAnd =
201+
"(syntax-rules ::: ()
202+
((_ a) a)
203+
((_ a b :::) (if a (and b :::) #f))
204+
((_) #t))"
205+
|> parseBuiltinMacro "and"
206+
207+
/// Builtin `or` Macro
208+
let private macroOr =
209+
"(syntax-rules ()
210+
((or) #f)
211+
((or test) test)
212+
((or test1 test2 ...)
213+
(let ((|90a3b246-0d7b-4f47-8e1e-0a9f0e7e3288| test1))
214+
(if |90a3b246-0d7b-4f47-8e1e-0a9f0e7e3288| |90a3b246-0d7b-4f47-8e1e-0a9f0e7e3288| (or test2 ...)))))"
215+
|> parseBuiltinMacro "or"
216+
217+
/// Builtin `when` Macro
218+
let private macroWhen =
219+
"(syntax-rules ()
220+
((_ cond expr expr1 ...)
221+
(if cond
222+
(begin
223+
expr
224+
expr1 ...))))"
225+
|> parseBuiltinMacro "when"
226+
227+
/// Builtin `unless` Macro
228+
let private macroUnless =
229+
"(syntax-rules ()
230+
((_ cond expr expr1 ...)
231+
(if (not cond)
232+
(begin
233+
expr
234+
expr1 ...))))"
235+
|> parseBuiltinMacro "unless"
236+
237+
/// The list of builtin macros
238+
let coreMacros =
239+
{ LibraryName = ["scheme";"base"]
240+
; Exports =
241+
[ macroAnd ; macroOr; macroWhen; macroUnless ]
242+
|> List.map (fun m -> (m.Name, StorageRef.Macro(m))) }
280243

281244
// ------------------------ Public Builtins API --------------------------------
282245

283246
/// Load the signature from a given libary name
284247
let public loadReferencedSignatures (name: string) =
248+
/// Folds a sequence of references into a single pair of lists
249+
let combineSignatures sigs =
250+
sigs
251+
|> Seq.fold (fun (tys, sigs) (t, s) -> (t :: tys, s :: sigs)) ([], [])
252+
285253
use assm =
286254
Mono.Cecil.AssemblyDefinition.ReadAssembly(name, assmReadParams)
287255
assm.MainModule.Types
@@ -292,7 +260,7 @@ let public loadReferencedSignatures (name: string) =
292260
let public loadCoreSignatures target =
293261
let (tys, sigs) = loadReferencedSignatures target.LispCoreLocation
294262
let sigs =
295-
coreMacros :: sigs
263+
BuiltinMacros.coreMacros :: sigs
296264
|> Seq.groupBy (fun l -> l.LibraryName)
297265
|> Seq.map (fun (n, sigs) ->
298266
{ LibraryName = n
@@ -301,7 +269,7 @@ let public loadCoreSignatures target =
301269
(tys, sigs |> List.ofSeq)
302270

303271
/// Load the core types into the given assembly
304-
let importCore (targetAssm: AssemblyDefinition) target =
272+
let public importCore (targetAssm: AssemblyDefinition) target =
305273
use sehrefaAssm =
306274
AssemblyDefinition.ReadAssembly(target.LispCoreLocation, assmReadParams)
307275
use mscorelibAssm =

src/Feersum/IlHelpers.fs

+26-1
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,29 @@ let createEmptyCtor (assm: AssemblyDefinition) =
5151
let namedParam name ty =
5252
ParameterDefinition(name,
5353
ParameterAttributes.None,
54-
ty)
54+
ty)
55+
56+
/// Convert a method reference on a generic type to a method reference on a bound
57+
/// generic instance type.
58+
///
59+
/// https://stackoverflow.com/a/16433452/1353098 - CC BY-SA 4.0
60+
let makeHostInstanceGeneric args (method: MethodReference) =
61+
let reference =
62+
MethodReference(
63+
method.Name,
64+
method.ReturnType,
65+
method.DeclaringType.MakeGenericInstanceType(args)
66+
)
67+
reference.HasThis <- method.HasThis
68+
reference.ExplicitThis <- method.ExplicitThis
69+
reference.CallingConvention <- method.CallingConvention
70+
71+
method.Parameters
72+
|> Seq.iter (fun parameter ->
73+
reference.Parameters.Add(ParameterDefinition(parameter.ParameterType)))
74+
75+
method.GenericParameters
76+
|> Seq.iter (fun genericParam ->
77+
reference.GenericParameters.Add(GenericParameter(genericParam.Name, reference)))
78+
79+
reference

0 commit comments

Comments
 (0)