diff options
Diffstat (limited to 'src/Language/Fiddle/Internal')
-rw-r--r-- | src/Language/Fiddle/Internal/UnitInterface.hs | 11 | ||||
-rw-r--r-- | src/Language/Fiddle/Internal/UnitNumbers.hs | 74 |
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) + |