mirror of
https://github.com/Smaug123/WoofWare.PawPrint
synced 2025-10-05 22:28:38 +00:00
Add more test cases (#11)
This commit is contained in:
@@ -9,12 +9,24 @@ open WoofWare.PawPrint
|
||||
open WoofWare.PawPrint.Test
|
||||
|
||||
[<TestFixture>]
|
||||
module TestNoOp =
|
||||
module TestCases =
|
||||
let assy = typeof<RunResult>.Assembly
|
||||
|
||||
[<Test>]
|
||||
let ``Can run a no-op`` () : unit =
|
||||
let source = Assembly.getEmbeddedResourceAsString "NoOp.cs" assy
|
||||
let cases : TestCase list =
|
||||
[
|
||||
{
|
||||
FileName = "NoOp.cs"
|
||||
ExpectedReturnCode = 1
|
||||
}
|
||||
{
|
||||
FileName = "TriangleNumber.cs"
|
||||
ExpectedReturnCode = 10
|
||||
}
|
||||
]
|
||||
|
||||
[<TestCaseSource(nameof cases)>]
|
||||
let ``Can run a no-op`` (case : TestCase) : unit =
|
||||
let source = Assembly.getEmbeddedResourceAsString case.FileName assy
|
||||
let image = Roslyn.compile [ source ]
|
||||
let messages, loggerFactory = LoggerFactory.makeTest ()
|
||||
|
||||
@@ -28,10 +40,10 @@ module TestNoOp =
|
||||
|
||||
let exitCode =
|
||||
match terminalState.ThreadState.[terminatingThread].MethodState.EvaluationStack.Values with
|
||||
| [] -> failwith "expected program to return 1, but it returned void"
|
||||
| [] -> failwith "expected program to return a value, but it returned void"
|
||||
| head :: _ ->
|
||||
match head with
|
||||
| EvalStackValue.Int32 i -> i
|
||||
| _ -> failwith "TODO"
|
||||
| ret -> failwith "expected program to return an int, but it returned %O{ret}"
|
||||
|
||||
exitCode |> shouldEqual 1
|
||||
exitCode |> shouldEqual case.ExpectedReturnCode
|
@@ -15,3 +15,9 @@ type RunResult =
|
||||
/// Final interpreter state after we stopped executing.
|
||||
FinalState : IlMachineState
|
||||
}
|
||||
|
||||
type TestCase =
|
||||
{
|
||||
FileName : string
|
||||
ExpectedReturnCode : int
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
namespace WoofWare.Pawprint.Test
|
||||
|
||||
open System
|
||||
open System.Collections.Immutable
|
||||
open System.IO
|
||||
open FsUnitTyped
|
||||
@@ -21,17 +22,23 @@ module TestHelloWorld =
|
||||
let dotnetRuntimes =
|
||||
DotnetRuntime.SelectForDll assy.Location |> ImmutableArray.CreateRange
|
||||
|
||||
use peImage = new MemoryStream (image)
|
||||
try
|
||||
use peImage = new MemoryStream (image)
|
||||
|
||||
let terminalState, terminatingThread =
|
||||
Program.run loggerFactory peImage dotnetRuntimes []
|
||||
let terminalState, terminatingThread =
|
||||
Program.run loggerFactory peImage dotnetRuntimes []
|
||||
|
||||
let exitCode =
|
||||
match terminalState.ThreadState.[terminatingThread].MethodState.EvaluationStack.Values with
|
||||
| [] -> failwith "expected program to return 1, but it returned void"
|
||||
| head :: _ ->
|
||||
match head with
|
||||
| EvalStackValue.Int32 i -> i
|
||||
| _ -> failwith "TODO"
|
||||
let exitCode =
|
||||
match terminalState.ThreadState.[terminatingThread].MethodState.EvaluationStack.Values with
|
||||
| [] -> failwith "expected program to return 1, but it returned void"
|
||||
| head :: _ ->
|
||||
match head with
|
||||
| EvalStackValue.Int32 i -> i
|
||||
| _ -> failwith "TODO"
|
||||
|
||||
exitCode |> shouldEqual 0
|
||||
exitCode |> shouldEqual 0
|
||||
with _ ->
|
||||
for m in messages () do
|
||||
Console.Error.WriteLine $"{m}"
|
||||
|
||||
reraise ()
|
||||
|
@@ -14,12 +14,13 @@
|
||||
<Compile Include="Assembly.fs" />
|
||||
<Compile Include="Roslyn.fs" />
|
||||
<Compile Include="TestHarness.fs"/>
|
||||
<Compile Include="TestNoOp.fs" />
|
||||
<Compile Include="TestCases.fs" />
|
||||
<Compile Include="TestHelloWorld.fs" />
|
||||
<Compile Include="TestBasicLock.fs" />
|
||||
<EmbeddedResource Include="sources\BasicLock.cs" />
|
||||
<EmbeddedResource Include="sources\NoOp.cs" />
|
||||
<EmbeddedResource Include="sources\HelloWorld.cs" />
|
||||
<EmbeddedResource Include="sources\TriangleNumber.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
17
WoofWare.PawPrint.Test/sources/TriangleNumber.cs
Normal file
17
WoofWare.PawPrint.Test/sources/TriangleNumber.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
|
||||
namespace TriangleNumber
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static int Main(string[] args)
|
||||
{
|
||||
var answer = 0;
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
answer += i;
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,5 +1,7 @@
|
||||
namespace WoofWare.PawPrint
|
||||
|
||||
#nowarn "42"
|
||||
|
||||
open System.Collections.Immutable
|
||||
open System.IO
|
||||
open System.Reflection
|
||||
@@ -1096,7 +1098,44 @@ module AbstractMachine =
|
||||
| Ceq -> failwith "todo"
|
||||
| Cgt -> failwith "todo"
|
||||
| Cgt_un -> failwith "todo"
|
||||
| Clt -> failwith "todo"
|
||||
| Clt ->
|
||||
let var2, state = state |> IlMachineState.popEvalStack currentThread
|
||||
let var1, state = state |> IlMachineState.popEvalStack currentThread
|
||||
|
||||
let comparisonResult =
|
||||
match var1, var2 with
|
||||
| EvalStackValue.Int64 var1, EvalStackValue.Int64 var2 -> if var1 < var2 then 1 else 0
|
||||
| EvalStackValue.Float var1, EvalStackValue.Float var2 -> failwith "todo"
|
||||
| EvalStackValue.ObjectRef var1, EvalStackValue.ObjectRef var2 ->
|
||||
failwith $"Clt instruction invalid for comparing object refs, {var1} vs {var2}"
|
||||
| EvalStackValue.ObjectRef var1, other -> failwith $"invalid comparison, ref %O{var1} vs %O{other}"
|
||||
| other, EvalStackValue.ObjectRef var2 -> failwith $"invalid comparison, %O{other} vs ref %O{var2}"
|
||||
| EvalStackValue.Float i, other -> failwith $"invalid comparison, float %f{i} vs %O{other}"
|
||||
| other, EvalStackValue.Float i -> failwith $"invalid comparison, %O{other} vs float %f{i}"
|
||||
| EvalStackValue.Int64 i, other -> failwith $"invalid comparison, int64 %i{i} vs %O{other}"
|
||||
| other, EvalStackValue.Int64 i -> failwith $"invalid comparison, %O{other} vs int64 %i{i}"
|
||||
| EvalStackValue.Int32 var1, EvalStackValue.Int32 var2 -> if var1 < var2 then 1 else 0
|
||||
| EvalStackValue.Int32 var1, EvalStackValue.NativeInt var2 ->
|
||||
failwith "todo: this is valid but no idea how"
|
||||
| EvalStackValue.Int32 i, other -> failwith $"invalid comparison, int32 %i{i} vs %O{other}"
|
||||
| EvalStackValue.NativeInt var1, EvalStackValue.Int32 var2 ->
|
||||
failwith "todo: this is valid but no idea how"
|
||||
| other, EvalStackValue.Int32 var2 -> failwith $"invalid comparison, {other} vs int32 {var2}"
|
||||
| EvalStackValue.NativeInt var1, EvalStackValue.NativeInt var2 -> if var1 < var2 then 1 else 0
|
||||
| EvalStackValue.NativeInt var1, other ->
|
||||
failwith $"invalid comparison, nativeint %i{var1} vs %O{other}"
|
||||
| EvalStackValue.ManagedPointer managedPointerSource, NativeInt int64 -> failwith "todo"
|
||||
| EvalStackValue.ManagedPointer managedPointerSource, ManagedPointer pointerSource -> failwith "todo"
|
||||
| EvalStackValue.ManagedPointer managedPointerSource, UserDefinedValueType -> failwith "todo"
|
||||
| EvalStackValue.UserDefinedValueType, NativeInt int64 -> failwith "todo"
|
||||
| EvalStackValue.UserDefinedValueType, ManagedPointer managedPointerSource -> failwith "todo"
|
||||
| EvalStackValue.UserDefinedValueType, UserDefinedValueType -> failwith "todo"
|
||||
|
||||
state
|
||||
|> IlMachineState.pushToEvalStack' (EvalStackValue.Int32 comparisonResult) currentThread
|
||||
|> IlMachineState.advanceProgramCounter currentThread
|
||||
|> Tuple.withRight WhatWeDid.Executed
|
||||
|> ExecutionResult.Stepped
|
||||
| Clt_un -> failwith "todo"
|
||||
| Stloc_0 ->
|
||||
state
|
||||
@@ -1125,7 +1164,43 @@ module AbstractMachine =
|
||||
| Sub -> failwith "todo"
|
||||
| Sub_ovf -> failwith "todo"
|
||||
| Sub_ovf_un -> failwith "todo"
|
||||
| Add -> failwith "todo"
|
||||
| Add ->
|
||||
let val1, state = IlMachineState.popEvalStack currentThread state
|
||||
let val2, state = IlMachineState.popEvalStack currentThread state
|
||||
// see table at https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.add?view=net-9.0
|
||||
let result =
|
||||
match val1, val2 with
|
||||
| EvalStackValue.Int32 val1, EvalStackValue.Int32 val2 ->
|
||||
(# "add" val1 val2 : int32 #) |> EvalStackValue.Int32
|
||||
| EvalStackValue.Int32 val1, EvalStackValue.NativeInt val2 -> failwith "" |> EvalStackValue.NativeInt
|
||||
| EvalStackValue.Int32 val1, EvalStackValue.ManagedPointer val2 ->
|
||||
failwith "" |> EvalStackValue.ManagedPointer
|
||||
| EvalStackValue.Int32 val1, EvalStackValue.ObjectRef val2 -> failwith "" |> EvalStackValue.ObjectRef
|
||||
| EvalStackValue.Int64 val1, EvalStackValue.Int64 val2 ->
|
||||
(# "add" val1 val2 : int64 #) |> EvalStackValue.Int64
|
||||
| EvalStackValue.NativeInt val1, EvalStackValue.Int32 val2 -> failwith "" |> EvalStackValue.NativeInt
|
||||
| EvalStackValue.NativeInt val1, EvalStackValue.NativeInt val2 ->
|
||||
failwith "" |> EvalStackValue.NativeInt
|
||||
| EvalStackValue.NativeInt val1, EvalStackValue.ManagedPointer val2 ->
|
||||
failwith "" |> EvalStackValue.ManagedPointer
|
||||
| EvalStackValue.NativeInt val1, EvalStackValue.ObjectRef val2 ->
|
||||
failwith "" |> EvalStackValue.ObjectRef
|
||||
| EvalStackValue.Float val1, EvalStackValue.Float val2 ->
|
||||
(# "add" val1 val2 : float #) |> EvalStackValue.Float
|
||||
| EvalStackValue.ManagedPointer val1, EvalStackValue.NativeInt val2 ->
|
||||
failwith "" |> EvalStackValue.ManagedPointer
|
||||
| EvalStackValue.ObjectRef val1, EvalStackValue.NativeInt val2 ->
|
||||
failwith "" |> EvalStackValue.ObjectRef
|
||||
| EvalStackValue.ManagedPointer val1, EvalStackValue.Int32 val2 ->
|
||||
failwith "" |> EvalStackValue.ManagedPointer
|
||||
| EvalStackValue.ObjectRef val1, EvalStackValue.Int32 val2 -> failwith "" |> EvalStackValue.ObjectRef
|
||||
| val1, val2 -> failwith $"invalid add operation: {val1} and {val2}"
|
||||
|
||||
state
|
||||
|> IlMachineState.pushToEvalStack' result currentThread
|
||||
|> IlMachineState.advanceProgramCounter currentThread
|
||||
|> Tuple.withRight WhatWeDid.Executed
|
||||
|> ExecutionResult.Stepped
|
||||
| Add_ovf -> failwith "todo"
|
||||
| Add_ovf_un -> failwith "todo"
|
||||
| Mul -> failwith "todo"
|
||||
@@ -1600,14 +1675,26 @@ module AbstractMachine =
|
||||
|> IlMachineState.popFromStackToLocalVariable currentThread (int b)
|
||||
|> IlMachineState.advanceProgramCounter currentThread
|
||||
|> Tuple.withRight WhatWeDid.Executed
|
||||
| Ldc_I8 int64 -> failwith "todo"
|
||||
| Ldc_I8 i ->
|
||||
state
|
||||
|> IlMachineState.pushToEvalStack (CliType.Numeric (CliNumericType.Int64 i)) currentThread
|
||||
|> IlMachineState.advanceProgramCounter currentThread
|
||||
|> Tuple.withRight WhatWeDid.Executed
|
||||
| Ldc_I4 i ->
|
||||
state
|
||||
|> IlMachineState.pushToEvalStack (CliType.Numeric (CliNumericType.Int32 i)) currentThread
|
||||
|> IlMachineState.advanceProgramCounter currentThread
|
||||
|> Tuple.withRight WhatWeDid.Executed
|
||||
| Ldc_R4 f -> failwith "todo"
|
||||
| Ldc_R8 f -> failwith "todo"
|
||||
| Ldc_R4 f ->
|
||||
state
|
||||
|> IlMachineState.pushToEvalStack (CliType.Numeric (CliNumericType.Float32 f)) currentThread
|
||||
|> IlMachineState.advanceProgramCounter currentThread
|
||||
|> Tuple.withRight WhatWeDid.Executed
|
||||
| Ldc_R8 f ->
|
||||
state
|
||||
|> IlMachineState.pushToEvalStack (CliType.Numeric (CliNumericType.Float64 f)) currentThread
|
||||
|> IlMachineState.advanceProgramCounter currentThread
|
||||
|> Tuple.withRight WhatWeDid.Executed
|
||||
| Ldc_I4_s b ->
|
||||
state
|
||||
|> IlMachineState.pushToEvalStack (CliType.Numeric (CliNumericType.Int8 b)) currentThread
|
||||
@@ -1620,9 +1707,69 @@ module AbstractMachine =
|
||||
|> IlMachineState.jumpProgramCounter currentThread (int b)
|
||||
|> Tuple.withRight WhatWeDid.Executed
|
||||
| Brfalse_s b -> failwith "todo"
|
||||
| Brtrue_s b -> failwith "todo"
|
||||
| Brfalse i -> failwith "todo"
|
||||
| Brtrue i -> failwith "todo"
|
||||
| Brtrue_s b ->
|
||||
let popped, state = IlMachineState.popEvalStack currentThread state
|
||||
|
||||
let isTrue =
|
||||
match popped with
|
||||
| EvalStackValue.Int32 i -> i <> 0
|
||||
| EvalStackValue.Int64 i -> i <> 0L
|
||||
| EvalStackValue.NativeInt i -> i <> 0L
|
||||
| EvalStackValue.Float f -> failwith "semantics are undocumented"
|
||||
| EvalStackValue.ManagedPointer ManagedPointerSource.Null -> false
|
||||
| EvalStackValue.ManagedPointer _ -> true
|
||||
| EvalStackValue.ObjectRef _ -> failwith "todo"
|
||||
| EvalStackValue.UserDefinedValueType -> failwith "todo"
|
||||
|
||||
state
|
||||
|> IlMachineState.advanceProgramCounter currentThread
|
||||
|> if isTrue then
|
||||
IlMachineState.jumpProgramCounter currentThread (int b)
|
||||
else
|
||||
id
|
||||
|> Tuple.withRight WhatWeDid.Executed
|
||||
| Brfalse i ->
|
||||
let popped, state = IlMachineState.popEvalStack currentThread state
|
||||
|
||||
let isFalse =
|
||||
match popped with
|
||||
| EvalStackValue.Int32 i -> i = 0
|
||||
| EvalStackValue.Int64 i -> i = 0L
|
||||
| EvalStackValue.NativeInt i -> i = 0L
|
||||
| EvalStackValue.Float f -> failwith "semantics are undocumented"
|
||||
| EvalStackValue.ManagedPointer ManagedPointerSource.Null -> true
|
||||
| EvalStackValue.ManagedPointer _ -> false
|
||||
| EvalStackValue.ObjectRef _ -> failwith "todo"
|
||||
| EvalStackValue.UserDefinedValueType -> failwith "todo"
|
||||
|
||||
state
|
||||
|> IlMachineState.advanceProgramCounter currentThread
|
||||
|> if isFalse then
|
||||
IlMachineState.jumpProgramCounter currentThread i
|
||||
else
|
||||
id
|
||||
|> Tuple.withRight WhatWeDid.Executed
|
||||
| Brtrue i ->
|
||||
let popped, state = IlMachineState.popEvalStack currentThread state
|
||||
|
||||
let isTrue =
|
||||
match popped with
|
||||
| EvalStackValue.Int32 i -> i <> 0
|
||||
| EvalStackValue.Int64 i -> i <> 0L
|
||||
| EvalStackValue.NativeInt i -> i <> 0L
|
||||
| EvalStackValue.Float f -> failwith "semantics are undocumented"
|
||||
| EvalStackValue.ManagedPointer ManagedPointerSource.Null -> false
|
||||
| EvalStackValue.ManagedPointer _ -> true
|
||||
| EvalStackValue.ObjectRef _ -> failwith "todo"
|
||||
| EvalStackValue.UserDefinedValueType -> failwith "todo"
|
||||
|
||||
state
|
||||
|> IlMachineState.advanceProgramCounter currentThread
|
||||
|> if isTrue then
|
||||
IlMachineState.jumpProgramCounter currentThread i
|
||||
else
|
||||
id
|
||||
|> Tuple.withRight WhatWeDid.Executed
|
||||
| Beq_s b -> failwith "todo"
|
||||
| Blt_s b -> failwith "todo"
|
||||
| Ble_s b -> failwith "todo"
|
||||
|
@@ -54,7 +54,10 @@ module EvalStackValue =
|
||||
| CliNumericType.UInt8 b -> failwith "todo"
|
||||
| CliNumericType.UInt16 s -> failwith "todo"
|
||||
| CliNumericType.Float32 f -> failwith "todo"
|
||||
| CliNumericType.Float64 f -> failwith "todo"
|
||||
| CliNumericType.Float64 _ ->
|
||||
match popped with
|
||||
| EvalStackValue.Float f -> CliType.Numeric (CliNumericType.Float64 f)
|
||||
| _ -> failwith "todo"
|
||||
| CliType.ObjectRef _ ->
|
||||
match popped with
|
||||
| EvalStackValue.ManagedPointer ptrSource ->
|
||||
@@ -117,8 +120,8 @@ type EvalStack =
|
||||
| CliNumericType.Int16 s -> int32 s |> EvalStackValue.Int32
|
||||
| CliNumericType.UInt16 s -> int32 s |> EvalStackValue.Int32
|
||||
| CliNumericType.Float32 f -> failwith "todo"
|
||||
| CliNumericType.Float64 f -> failwith "todo"
|
||||
| CliNumericType.NativeFloat f -> failwith "todo"
|
||||
| CliNumericType.Float64 f -> EvalStackValue.Float f
|
||||
| CliNumericType.NativeFloat f -> EvalStackValue.Float f
|
||||
| CliType.ObjectRef i ->
|
||||
match i with
|
||||
| None -> EvalStackValue.ManagedPointer ManagedPointerSource.Null
|
||||
|
Reference in New Issue
Block a user