mirror of
https://github.com/Smaug123/WoofWare.PawPrint
synced 2025-10-11 00:38:40 +00:00
144 lines
5.7 KiB
Forth
144 lines
5.7 KiB
Forth
namespace WoofWare.PawPrint
|
|
|
|
open System
|
|
open System.Collections.Immutable
|
|
open System.Reflection.Metadata
|
|
|
|
/// Currently this is just an opaque handle; it can't be treated as a pointer.
|
|
type ManagedHeapAddress = | ManagedHeapAddress of int
|
|
|
|
/// Source:
|
|
/// Table I.6: Data Types Directly Supported by the CLI
|
|
type CliSupportedObject =
|
|
/// Can be assigned the null value 0
|
|
/// This is the 'O' type.
|
|
| ObjectReference of ManagedHeapAddress option
|
|
/// This is the '&' type. It can point to managed or unmanaged memory.
|
|
/// TODO: the contents of this are therefore wrong
|
|
| PointerType of ManagedHeapAddress option
|
|
| Int8 of int8
|
|
| UInt8 of uint8
|
|
| Int16 of int16
|
|
| UInt16 of uint16
|
|
| Int32 of int32
|
|
| UInt32 of uint32
|
|
| Int64 of int64
|
|
| UInt64 of uint64
|
|
| Float32 of float32
|
|
| Float64 of float
|
|
| NativeInt of int64
|
|
| NativeUint of uint64
|
|
|
|
/// Defined in III.1.1
|
|
type BasicCliType =
|
|
| ObjectReference of ManagedHeapAddress option
|
|
| PointerType of ManagedHeapAddress option
|
|
| Int32 of int32
|
|
| Int64 of int64
|
|
| NativeInt of int64
|
|
| NativeFloat of float
|
|
|
|
/// Defined in III.1.1.1
|
|
type CliNumericType =
|
|
| Int32 of int32
|
|
| Int64 of int64
|
|
| NativeInt of int64
|
|
| NativeFloat of float
|
|
| Int8 of int8
|
|
| Int16 of int16
|
|
| UInt8 of uint8
|
|
| UInt16 of uint16
|
|
| Float32 of float32
|
|
| Float64 of float
|
|
|
|
type CliValueType =
|
|
private
|
|
| Bool of byte
|
|
/// A UTF-16 code unit, i.e. two bytes. We store the most significant one first.
|
|
| Char of byte * byte
|
|
| UInt8 of uint8
|
|
| UInt16 of uint16
|
|
| Int8 of int8
|
|
| Int16 of int16
|
|
| Float32 of float32
|
|
| Float64 of float
|
|
|
|
[<RequireQualifiedAccess>]
|
|
type CliRuntimePointerSource = | LocalVariable of sourceThread : ThreadId * methodFrame : int * whichVar : uint16
|
|
|
|
type CliRuntimePointer =
|
|
| Unmanaged of unit
|
|
| Managed of CliRuntimePointerSource
|
|
|
|
/// This is the kind of type that can be stored in arguments, local variables, statics, array elements, fields.
|
|
type CliType =
|
|
/// III.1.1.1
|
|
| Numeric of CliNumericType
|
|
/// III.1.1.2
|
|
| Bool of byte
|
|
/// III.1.1.3
|
|
| Char of high : byte * low : byte
|
|
/// III.1.1.4 - this is a completely opaque handle to a managed object; arithmetic is forbidden
|
|
| ObjectRef of ManagedHeapAddress option
|
|
/// III.1.1.5
|
|
| RuntimePointer of CliRuntimePointer
|
|
|
|
/// In fact any non-zero value will do for True, but we'll use 1
|
|
static member OfBool (b : bool) = CliType.Bool (if b then 1uy else 0uy)
|
|
|
|
static member OfChar (c : char) =
|
|
CliType.Char (byte (int c / 256), byte (int c % 256))
|
|
|
|
static member OfManagedObject (ptr : ManagedHeapAddress) = CliType.ObjectRef (Some ptr)
|
|
|
|
[<RequireQualifiedAccess>]
|
|
module CliType =
|
|
let rec zeroOf (generics : TypeDefn ImmutableArray) (ty : TypeDefn) : CliType =
|
|
match ty with
|
|
| TypeDefn.PrimitiveType primitiveType ->
|
|
match primitiveType with
|
|
| PrimitiveType.Boolean -> CliType.Bool 0uy
|
|
| PrimitiveType.Char -> CliType.Char (0uy, 0uy)
|
|
| PrimitiveType.SByte -> CliType.Numeric (CliNumericType.Int8 0y)
|
|
| PrimitiveType.Byte -> CliType.Numeric (CliNumericType.UInt8 0uy)
|
|
| PrimitiveType.Int16 -> CliType.Numeric (CliNumericType.Int16 0s)
|
|
| PrimitiveType.UInt16 -> CliType.Numeric (CliNumericType.UInt16 0us)
|
|
| PrimitiveType.Int32 -> CliType.Numeric (CliNumericType.Int32 0)
|
|
| PrimitiveType.UInt32 -> failwith "todo"
|
|
| PrimitiveType.Int64 -> CliType.Numeric (CliNumericType.Int64 0L)
|
|
| PrimitiveType.UInt64 -> failwith "todo"
|
|
| PrimitiveType.Single -> CliType.Numeric (CliNumericType.Float32 0.0f)
|
|
| PrimitiveType.Double -> CliType.Numeric (CliNumericType.Float64 0.0)
|
|
| PrimitiveType.String -> CliType.ObjectRef None
|
|
| PrimitiveType.TypedReference -> failwith "todo"
|
|
| PrimitiveType.IntPtr -> failwith "todo"
|
|
| PrimitiveType.UIntPtr -> failwith "todo"
|
|
| PrimitiveType.Object -> CliType.ObjectRef None
|
|
| TypeDefn.Array _ -> CliType.ObjectRef None
|
|
| TypeDefn.Pinned typeDefn -> failwith "todo"
|
|
| TypeDefn.Pointer _ -> CliType.ObjectRef None
|
|
| TypeDefn.Byref _ -> CliType.ObjectRef None
|
|
| TypeDefn.OneDimensionalArrayLowerBoundZero _ -> CliType.ObjectRef None
|
|
| TypeDefn.Modified (original, afterMod, modificationRequired) -> failwith "todo"
|
|
| TypeDefn.FromReference (typeRef, signatureTypeKind) ->
|
|
match signatureTypeKind with
|
|
| SignatureTypeKind.Unknown -> failwith "todo"
|
|
| SignatureTypeKind.ValueType -> failwith "todo"
|
|
| SignatureTypeKind.Class -> CliType.ObjectRef None
|
|
| _ -> raise (ArgumentOutOfRangeException ())
|
|
| TypeDefn.FromDefinition (typeDefinitionHandle, signatureTypeKind) ->
|
|
match signatureTypeKind with
|
|
| SignatureTypeKind.Unknown -> failwith "todo"
|
|
| SignatureTypeKind.ValueType -> failwith "todo"
|
|
| SignatureTypeKind.Class -> CliType.ObjectRef None
|
|
| _ -> raise (ArgumentOutOfRangeException ())
|
|
| TypeDefn.GenericInstantiation (generic, args) ->
|
|
// TODO: this is rather concerning and probably incorrect
|
|
zeroOf args generic
|
|
| TypeDefn.FunctionPointer typeMethodSignature -> failwith "todo"
|
|
| TypeDefn.GenericTypeParameter index ->
|
|
// TODO: can generics depend on other generics? presumably, so we pass the array down again
|
|
zeroOf generics generics.[index]
|
|
| TypeDefn.GenericMethodParameter index -> zeroOf generics generics.[index]
|
|
| TypeDefn.Void -> failwith "should never construct an element of type Void"
|