Skip to content

Commit 33966ab

Browse files
committed
Assembler: add simple implementation.
1 parent 0ab6b11 commit 33966ab

File tree

4 files changed

+83
-4
lines changed

4 files changed

+83
-4
lines changed

Naggum.Assembler/Assembler.fs

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,62 @@
11
module Naggum.Assembler.Assembler
22

3+
open System
4+
open System.Reflection
35
open System.Reflection.Emit
46

57
open Naggum.Assembler.Representation
68

7-
/// Assembles the intermediate program representation. Returns a list of assemblies ready for saving.
9+
let private getMethodAttributes (m : MethodDefinition) =
10+
let empty = enum 0
11+
let conditions =
12+
[ (m.Visibility = Public, MethodAttributes.Public)
13+
(true, MethodAttributes.Static) ] // TODO: Proper static method detection
14+
15+
conditions
16+
|> List.map (fun (c, r) -> if c then r else empty)
17+
|> List.fold (|||) empty
18+
19+
let private findMethod (signature : MethodSignature) =
20+
// TODO: Add method overload resolution etc. (see ClrGenerator module)
21+
let ``type`` = signature.ContainingType.Value
22+
``type``.GetMethod (signature.Name, Array.ofList signature.ArgumentTypes)
23+
24+
let private buildMethodBody (m : MethodDefinition) (builder : MethodBuilder) =
25+
let generator = builder.GetILGenerator ()
26+
27+
m.Body
28+
|> List.iter (function
29+
| Call signature ->
30+
let methodInfo = findMethod signature
31+
generator.Emit (OpCodes.Call, methodInfo)
32+
| Ldstr string -> generator.Emit (OpCodes.Ldstr, string)
33+
| Ret -> generator.Emit (OpCodes.Ret))
34+
35+
let private assembleUnit (builder : ModuleBuilder) = function
36+
| Method m ->
37+
let name = m.Name
38+
let attributes = getMethodAttributes m
39+
let returnType = m.ReturnType
40+
let argumentTypes = Array.ofList m.ArgumentTypes
41+
let methodBuilder = builder.DefineGlobalMethod (name,
42+
attributes,
43+
returnType,
44+
argumentTypes)
45+
buildMethodBody m methodBuilder
46+
47+
48+
let private assembleAssembly (assembly : Assembly) =
49+
let name = AssemblyName assembly.Name
50+
let domain = AppDomain.CurrentDomain
51+
let builder = domain.DefineDynamicAssembly (name,
52+
AssemblyBuilderAccess.Save)
53+
let fileName = assembly.Name + ".dll" // TODO: Proper file naming
54+
let moduleBuilder = builder.DefineDynamicModule (assembly.Name, fileName)
55+
assembly.Units |> List.iter (assembleUnit moduleBuilder)
56+
builder
57+
58+
/// Assembles the intermediate program representation. Returns a list of
59+
/// assemblies ready for saving.
860
let assemble (assemblies : Assembly seq) : AssemblyBuilder seq =
9-
Seq.empty
61+
assemblies
62+
|> Seq.map assembleAssembly

Naggum.Assembler/Representation.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ type MethodSignature =
1818
ReturnType : Type }
1919

2020
type Instruction =
21-
| Ldstr of string
2221
| Call of MethodSignature
22+
| Ldstr of string
2323
| Ret
2424

2525
type MethodDefinition =

Naggum.Test/AssemblerTests.fs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
module Naggum.Test.AssemblerTests
2+
3+
open System
4+
open System.IO
5+
open System.Reflection
6+
open System.Text
7+
8+
open Xunit
9+
10+
open Naggum.Assembler
11+
open Naggum.Assembler.Representation
12+
13+
let assemble (source : string) =
14+
use stream = new MemoryStream(Encoding.UTF8.GetBytes source)
15+
let repr = Processor.prepare "file.ngi" stream
16+
let assemblies = Assembler.assemble repr
17+
Array.ofSeq assemblies
18+
19+
[<Fact>]
20+
let ``Empty assembly should be assembled`` () =
21+
let source = "(.assembly Empty)"
22+
let result = assemble source
23+
Assert.Equal (1, result.Length)
24+
25+
// TODO: Additional integration tests

Naggum.Test/Naggum.Test.fsproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,9 @@
5252
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
5353
</Content>
5454
<Content Include="packages.config" />
55-
<Compile Include="ProcessorTests.fs" />
5655
<Compile Include="CompilerTest.fs" />
56+
<Compile Include="AssemblerTests.fs" />
57+
<Compile Include="ProcessorTests.fs" />
5758
</ItemGroup>
5859
<ItemGroup>
5960
<Reference Include="FSharp.Core, Version=$(TargetFSharpCoreVersion), Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">

0 commit comments

Comments
 (0)