summaryrefslogtreecommitdiff
path: root/src/Language/Fiddle/Internal
diff options
context:
space:
mode:
Diffstat (limited to 'src/Language/Fiddle/Internal')
-rw-r--r--src/Language/Fiddle/Internal/UnitInterface.hs11
-rw-r--r--src/Language/Fiddle/Internal/UnitNumbers.hs74
2 files changed, 80 insertions, 5 deletions
diff --git a/src/Language/Fiddle/Internal/UnitInterface.hs b/src/Language/Fiddle/Internal/UnitInterface.hs
index c5cbc2c..2a538eb 100644
--- a/src/Language/Fiddle/Internal/UnitInterface.hs
+++ b/src/Language/Fiddle/Internal/UnitInterface.hs
@@ -8,6 +8,7 @@ import GHC.Generics
import Language.Fiddle.Internal.Scopes (Scope)
import qualified Language.Fiddle.Internal.Scopes as Scopes
import Language.Fiddle.Types (SourceSpan)
+import Language.Fiddle.Internal.UnitNumbers
data InternalDirectiveExpression
= InternalDirectiveExpressionNumber String
@@ -93,7 +94,7 @@ data ExportedLocationDecl where
{ -- | Metadata associated with the location.
exportedLocationMetadata :: Metadata,
-- | The value of the location as an integer.
- exportedLocationValue :: Integer
+ exportedLocationValue :: N Address
} ->
ExportedLocationDecl
deriving (Show, Eq, Ord, Generic, FromJSON, ToJSON)
@@ -105,7 +106,7 @@ data ExportedBitsDecl where
{ -- | Metadata associated with the bits declaration.
exportedBitsDeclMetadata :: Metadata,
-- | The size of the bits in this declaration.
- exportedBitsDeclSizeBits :: Word32
+ exportedBitsDeclSizeBits :: N Bits
} ->
ExportedBitsDecl
deriving (Show, Eq, Ord, Generic, FromJSON, ToJSON)
@@ -117,7 +118,7 @@ data ExportedTypeDecl where
{ -- | Metadata associated with the type declaration.
exportedTypeDeclMetadata :: Metadata,
-- | The size of the type in bytes.
- exportedTypeDeclSizeBytes :: Word32
+ exportedTypeDeclSizeBytes :: N Bytes
} ->
ExportedTypeDecl
deriving (Show, Eq, Ord, Generic, FromJSON, ToJSON)
@@ -127,7 +128,7 @@ data ReferencedObjectType where
{objectTypeReference :: String} -> ReferencedObjectType
ArrayObjectType ::
{ arrayObjectTypeType :: ReferencedObjectType,
- arryObjecttTypeNumber :: Word32
+ arryObjecttTypeNumber :: N Unitless
} ->
ReferencedObjectType
deriving (Show, Eq, Ord, Generic, FromJSON, ToJSON)
@@ -139,7 +140,7 @@ data ExportedObjectDecl where
{ -- | Metadata associated with the object declaration.
exportedObjectDeclMetadata :: Metadata,
-- | The memory location of the object.
- exportedObjectDeclLocation :: Integer,
+ exportedObjectDeclLocation :: N Address,
-- | The type of the object as a string.
exportedObjectDeclType :: ReferencedObjectType
} ->
diff --git a/src/Language/Fiddle/Internal/UnitNumbers.hs b/src/Language/Fiddle/Internal/UnitNumbers.hs
new file mode 100644
index 0000000..7bdc539
--- /dev/null
+++ b/src/Language/Fiddle/Internal/UnitNumbers.hs
@@ -0,0 +1,74 @@
+{-# LANGUAGE DerivingStrategies #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+
+module Language.Fiddle.Internal.UnitNumbers where
+
+import Data.Aeson (FromJSON (..), ToJSON (..))
+import Text.Printf
+
+-- | 'NumberWithUnit' represents a numeric value associated with a unit type.
+-- The unit type 'u' is a phantom type, meaning it carries no runtime data
+-- but provides compile-time type safety for the units.
+-- The actual value is of type 'i', such as 'Int' or 'Integer'.
+newtype NumberWithUnit u i = NumberWithUnit i
+ deriving newtype (Real, Enum, Num, Eq, Ord, Integral, PrintfArg)
+
+-- | Custom 'Show' instance for 'NumberWithUnit' to display the numeric value.
+instance (Show i) => Show (NumberWithUnit u i) where
+ show (NumberWithUnit b) = show b
+
+-- | JSON serialization for 'NumberWithUnit', converting to and from JSON using
+-- the underlying numeric type.
+instance (ToJSON i) => ToJSON (NumberWithUnit u i) where
+ toJSON (NumberWithUnit b) = toJSON b
+
+instance (FromJSON i) => FromJSON (NumberWithUnit u i) where
+ parseJSON v = NumberWithUnit <$> parseJSON v
+
+-- | Type alias for 'NumberWithUnit' where the underlying numeric type is 'Int'.
+-- This is a shorthand for convenience when working with integers.
+type N u = NumberWithUnit u Int
+
+-- | Phantom types representing different units that can be used with
+-- 'NumberWithUnit'. These types carry no data but serve as compile-time
+-- markers for the units.
+data Bits
+data Bytes
+data Address
+data Unitless
+
+-- | 'NamedUnit' is a typeclass for units that can be represented as strings.
+-- It provides a 'unitName' method for displaying a formatted representation
+-- of the unit.
+class NamedUnit u where
+ unitName :: N u -> String
+
+-- | 'NamedUnit' instance for 'Bits'. It displays the value followed by "bit"
+-- or "bits", depending on whether the value is 1 or not.
+instance NamedUnit Bits where
+ unitName 1 = "1 bit"
+ unitName n = show n ++ " bits"
+
+-- | 'NamedUnit' instance for 'Bytes'. It displays the value followed by "byte"
+-- or "bytes", depending on whether the value is 1 or not.
+instance NamedUnit Bytes where
+ unitName 1 = "1 byte"
+ unitName n = show n ++ " bytes"
+
+-- | Convert a value from 'Bits' to 'Bytes'. This returns a tuple containing the
+-- number of complete bytes and the remaining bits.
+bitsToBytes :: N Bits -> (N Bytes, N Bits)
+bitsToBytes (NumberWithUnit a) =
+ let (y, i) = divMod a 8 in (NumberWithUnit y, NumberWithUnit i)
+
+-- | Convert a value from 'Bytes' to 'Bits'. This multiplies the byte value by
+-- 8 to get the corresponding number of bits.
+bytesToBits :: N Bytes -> N Bits
+bytesToBits (NumberWithUnit a) = NumberWithUnit (a * 8)
+
+-- | Multiplication operator for 'NumberWithUnit' values. The result retains
+-- the original unit 'u', while the right operand is of the 'Unitless' type.
+-- This operator is useful for scaling values by a unitless factor.
+(.*.) :: N u -> N Unitless -> N u
+(.*.) (NumberWithUnit a) (NumberWithUnit b) = NumberWithUnit (a * b)
+