Added a signed 8-bit type and unsigned 16-,32- and 64-bit types to the AST, adjusting all other code accordingly
The types have been added to the AST. Beyond the obvious trivial changes (extra cases in functions, etc), the only significant change was that isSafeConversion needed to be changed. I took the opportunity to totally rewrite the function into a graph-like mechanism rather than just using a list. To demonstrate its correctness I also wrote an exhaustive test for it.
This commit is contained in:
parent
3b14eec036
commit
96f6bc39fd
29
AST.hs
29
AST.hs
|
@ -90,8 +90,26 @@ data ChanAttributes = ChanAttributes {
|
|||
-- have.
|
||||
data Type =
|
||||
Bool
|
||||
-- | 8-bit unsigned integer.
|
||||
| Byte
|
||||
| Int | Int16 | Int32 | Int64
|
||||
|
||||
-- | 16-bit unsigned integer. Only exists in Rain.
|
||||
| UInt16
|
||||
-- | 32-bit unsigned integer. Only exists in Rain.
|
||||
| UInt32
|
||||
-- | 64-bit unsigned integer. Only exists in Rain.
|
||||
| UInt64
|
||||
-- | 8-bit signed integer. Only exists in Rain.
|
||||
| Int8
|
||||
|
||||
-- | In occam: a signed integer that uses the most efficient word-size in the target. In Rain: transformed to an Int64.
|
||||
| Int
|
||||
-- | 16-bit signed integer.
|
||||
| Int16
|
||||
-- | 32-bit signed integer.
|
||||
| Int32
|
||||
-- | 64-bit signed integer.
|
||||
| Int64
|
||||
| Real32 | Real64
|
||||
-- | An array.
|
||||
-- For N-dimensional arrays, the [Dimension] list will be of length N.
|
||||
|
@ -113,7 +131,14 @@ data Type =
|
|||
|
||||
instance Show Type where
|
||||
show Bool = "BOOL"
|
||||
show Byte = "BYTE"
|
||||
show Byte = "BYTE"
|
||||
--Not sure how to show the non-occam types -- just use their AST names:
|
||||
show UInt16 = "UInt16"
|
||||
show UInt32 = "UInt32"
|
||||
show UInt64 = "UInt64"
|
||||
show Int8 = "Int8"
|
||||
|
||||
|
||||
show Int = "INT"
|
||||
show Int16 = "INT16"
|
||||
show Int32 = "INT32"
|
||||
|
|
|
@ -122,6 +122,14 @@ evalExpression (A.Dyadic _ op e1 e2)
|
|||
evalDyadic op v1 v2
|
||||
evalExpression (A.MostPos _ A.Byte) = return $ OccByte maxBound
|
||||
evalExpression (A.MostNeg _ A.Byte) = return $ OccByte minBound
|
||||
evalExpression (A.MostPos _ A.UInt16) = return $ OccUInt16 maxBound
|
||||
evalExpression (A.MostNeg _ A.UInt16) = return $ OccUInt16 minBound
|
||||
evalExpression (A.MostPos _ A.UInt32) = return $ OccUInt32 maxBound
|
||||
evalExpression (A.MostNeg _ A.UInt32) = return $ OccUInt32 minBound
|
||||
evalExpression (A.MostPos _ A.UInt64) = return $ OccUInt64 maxBound
|
||||
evalExpression (A.MostNeg _ A.UInt64) = return $ OccUInt64 minBound
|
||||
evalExpression (A.MostPos _ A.Int8) = return $ OccInt8 maxBound
|
||||
evalExpression (A.MostNeg _ A.Int8) = return $ OccInt8 minBound
|
||||
evalExpression (A.MostPos _ A.Int) = return $ OccInt maxBound
|
||||
evalExpression (A.MostNeg _ A.Int) = return $ OccInt minBound
|
||||
evalExpression (A.MostPos _ A.Int16) = return $ OccInt16 maxBound
|
||||
|
@ -163,6 +171,10 @@ evalExpression e = throwError "bad expression"
|
|||
|
||||
evalMonadicOp :: (forall t. (Num t, Integral t, Bits t) => t -> t) -> OccValue -> EvalM OccValue
|
||||
evalMonadicOp f (OccByte a) = return $ OccByte (f a)
|
||||
evalMonadicOp f (OccUInt16 a) = return $ OccUInt16 (f a)
|
||||
evalMonadicOp f (OccUInt32 a) = return $ OccUInt32 (f a)
|
||||
evalMonadicOp f (OccUInt64 a) = return $ OccUInt64 (f a)
|
||||
evalMonadicOp f (OccInt8 a) = return $ OccInt8 (f a)
|
||||
evalMonadicOp f (OccInt a) = return $ OccInt (f a)
|
||||
evalMonadicOp f (OccInt16 a) = return $ OccInt16 (f a)
|
||||
evalMonadicOp f (OccInt32 a) = return $ OccInt32 (f a)
|
||||
|
@ -179,6 +191,10 @@ evalMonadic _ _ = throwError "bad monadic op"
|
|||
|
||||
evalDyadicOp :: (forall t. (Num t, Integral t, Bits t) => t -> t -> t) -> OccValue -> OccValue -> EvalM OccValue
|
||||
evalDyadicOp f (OccByte a) (OccByte b) = return $ OccByte (f a b)
|
||||
evalDyadicOp f (OccUInt16 a) (OccUInt16 b) = return $ OccUInt16 (f a b)
|
||||
evalDyadicOp f (OccUInt32 a) (OccUInt32 b) = return $ OccUInt32 (f a b)
|
||||
evalDyadicOp f (OccUInt64 a) (OccUInt64 b) = return $ OccUInt64 (f a b)
|
||||
evalDyadicOp f (OccInt8 a) (OccInt8 b) = return $ OccInt8 (f a b)
|
||||
evalDyadicOp f (OccInt a) (OccInt b) = return $ OccInt (f a b)
|
||||
evalDyadicOp f (OccInt16 a) (OccInt16 b) = return $ OccInt16 (f a b)
|
||||
evalDyadicOp f (OccInt32 a) (OccInt32 b) = return $ OccInt32 (f a b)
|
||||
|
@ -187,6 +203,10 @@ evalDyadicOp _ _ _ = throwError "dyadic operator not implemented for this type"
|
|||
|
||||
evalCompareOp :: (forall t. (Eq t, Ord t) => t -> t -> Bool) -> OccValue -> OccValue -> EvalM OccValue
|
||||
evalCompareOp f (OccByte a) (OccByte b) = return $ OccBool (f a b)
|
||||
evalCompareOp f (OccUInt16 a) (OccUInt16 b) = return $ OccBool (f a b)
|
||||
evalCompareOp f (OccUInt32 a) (OccUInt32 b) = return $ OccBool (f a b)
|
||||
evalCompareOp f (OccUInt64 a) (OccUInt64 b) = return $ OccBool (f a b)
|
||||
evalCompareOp f (OccInt8 a) (OccInt8 b) = return $ OccBool (f a b)
|
||||
evalCompareOp f (OccInt a) (OccInt b) = return $ OccBool (f a b)
|
||||
evalCompareOp f (OccInt16 a) (OccInt16 b) = return $ OccBool (f a b)
|
||||
evalCompareOp f (OccInt32 a) (OccInt32 b) = return $ OccBool (f a b)
|
||||
|
@ -233,6 +253,10 @@ renderValue m v = (t, A.Literal m t lr)
|
|||
|
||||
renderLiteral :: Meta -> OccValue -> (A.Type, A.LiteralRepr)
|
||||
renderLiteral m (OccByte c) = (A.Byte, A.ByteLiteral m $ renderChar (chr $ fromIntegral c))
|
||||
renderLiteral m (OccUInt16 i) = (A.UInt16, A.IntLiteral m $ show i)
|
||||
renderLiteral m (OccUInt32 i) = (A.UInt32, A.IntLiteral m $ show i)
|
||||
renderLiteral m (OccUInt64 i) = (A.UInt64, A.IntLiteral m $ show i)
|
||||
renderLiteral m (OccInt8 i) = (A.Int8, A.IntLiteral m $ show i)
|
||||
renderLiteral m (OccInt i) = (A.Int, A.IntLiteral m $ show i)
|
||||
renderLiteral m (OccInt16 i) = (A.Int16, A.IntLiteral m $ show i)
|
||||
renderLiteral m (OccInt32 i) = (A.Int32, A.IntLiteral m $ show i)
|
||||
|
|
|
@ -43,6 +43,12 @@ instance Die EvalM where
|
|||
data OccValue =
|
||||
OccBool Bool
|
||||
| OccByte Word8
|
||||
-- The following four aren't occam types, but I need to put them in here for handling Rain code:
|
||||
| OccUInt16 Word16
|
||||
| OccUInt32 Word32
|
||||
| OccUInt64 Word64
|
||||
| OccInt8 Int8
|
||||
|
||||
| OccInt Int32
|
||||
| OccInt16 Int16
|
||||
| OccInt32 Int32
|
||||
|
@ -112,6 +118,22 @@ evalSimpleLiteral (A.Literal _ A.Byte (A.IntLiteral _ s))
|
|||
= fromRead OccByte (readSigned readDec) s
|
||||
evalSimpleLiteral (A.Literal _ A.Byte (A.HexLiteral _ s))
|
||||
= fromRead OccByte readHex s
|
||||
evalSimpleLiteral (A.Literal _ A.UInt16 (A.IntLiteral _ s))
|
||||
= fromRead OccUInt16 (readSigned readDec) s
|
||||
evalSimpleLiteral (A.Literal _ A.UInt16 (A.HexLiteral _ s))
|
||||
= fromRead OccUInt16 readHex s
|
||||
evalSimpleLiteral (A.Literal _ A.UInt32 (A.IntLiteral _ s))
|
||||
= fromRead OccUInt32 (readSigned readDec) s
|
||||
evalSimpleLiteral (A.Literal _ A.UInt32 (A.HexLiteral _ s))
|
||||
= fromRead OccUInt32 readHex s
|
||||
evalSimpleLiteral (A.Literal _ A.UInt64 (A.IntLiteral _ s))
|
||||
= fromRead OccUInt64 (readSigned readDec) s
|
||||
evalSimpleLiteral (A.Literal _ A.UInt64 (A.HexLiteral _ s))
|
||||
= fromRead OccUInt64 readHex s
|
||||
evalSimpleLiteral (A.Literal _ A.Int8 (A.IntLiteral _ s))
|
||||
= fromRead OccInt8 (readSigned readDec) s
|
||||
evalSimpleLiteral (A.Literal _ A.Int8 (A.HexLiteral _ s))
|
||||
= fromRead OccInt8 readHex s
|
||||
evalSimpleLiteral (A.Literal _ A.Int (A.IntLiteral _ s))
|
||||
= fromRead OccInt (readSigned readDec) s
|
||||
evalSimpleLiteral (A.Literal _ A.Int (A.HexLiteral _ s))
|
||||
|
|
|
@ -318,6 +318,10 @@ genName n = tell [nameString n]
|
|||
cgetScalarType :: GenOps -> A.Type -> Maybe String
|
||||
cgetScalarType _ A.Bool = Just "bool"
|
||||
cgetScalarType _ A.Byte = Just "uint8_t"
|
||||
cgetScalarType _ A.UInt16 = Just "uint16_t"
|
||||
cgetScalarType _ A.UInt32 = Just "uint32_t"
|
||||
cgetScalarType _ A.UInt64 = Just "uint64_t"
|
||||
cgetScalarType _ A.Int8 = Just "int8_t"
|
||||
cgetScalarType _ A.Int = Just "int"
|
||||
cgetScalarType _ A.Int16 = Just "int16_t"
|
||||
cgetScalarType _ A.Int32 = Just "int32_t"
|
||||
|
|
|
@ -961,6 +961,10 @@ cppgenSizeSuffix _ dim = tell [".extent(", dim, ")"]
|
|||
cppgetScalarType :: GenOps -> A.Type -> Maybe String
|
||||
cppgetScalarType _ A.Bool = Just "tockBool"
|
||||
cppgetScalarType _ A.Byte = Just "uint8_t"
|
||||
cppgetScalarType _ A.UInt16 = Just "uint16_t"
|
||||
cppgetScalarType _ A.UInt32 = Just "uint32_t"
|
||||
cppgetScalarType _ A.UInt64 = Just "uint64_t"
|
||||
cppgetScalarType _ A.Int8 = Just "int8_t"
|
||||
cppgetScalarType _ A.Int = Just "int"
|
||||
cppgetScalarType _ A.Int16 = Just "int16_t"
|
||||
cppgetScalarType _ A.Int32 = Just "int32_t"
|
||||
|
|
61
PassTest.hs
61
PassTest.hs
|
@ -140,6 +140,66 @@ testFunctionsToProcs2 = testPassWithItemsStateCheck "testFunctionsToProcs2 A" ex
|
|||
assertEqual "testFunctionsToProcs2 F" (Just [A.Int]) (Map.lookup "foo" (csFunctionReturns state))
|
||||
assertEqual "testFunctionsToProcs2 G" (Just [A.Int]) (Map.lookup "fooOuter" (csFunctionReturns state))
|
||||
|
||||
--Not strictly a pass test but it can live here for now:
|
||||
testIsSafeConversion :: Test
|
||||
testIsSafeConversion = TestList $ map runTestRow resultsWithIndexes
|
||||
where
|
||||
resultsWithIndexes :: [(Int,[(Int,Bool)])]
|
||||
resultsWithIndexes = zip [0..] $ map (zip [0..]) results
|
||||
|
||||
runTestRow :: (Int,[(Int,Bool)]) -> Test
|
||||
runTestRow (a,b) = TestList $ map (runTest a) b
|
||||
where
|
||||
runTest :: Int -> (Int,Bool) -> Test
|
||||
runTest destIndex (srcIndex,result) = TestCase $ assertEqual
|
||||
("Testing from type: " ++ (show $ index srcIndex) ++ " to: " ++ (show $ index destIndex))
|
||||
result $ isSafeConversion (index srcIndex) (index destIndex)
|
||||
|
||||
--Integer types are:
|
||||
--A.Bool
|
||||
--A.Byte
|
||||
--A.UInt16
|
||||
--A.UInt32
|
||||
--A.UInt64
|
||||
--A.Int8
|
||||
--A.Int
|
||||
--A.Int16
|
||||
--A.Int32
|
||||
--A.Int64
|
||||
|
||||
--We will assume (like the rest of Tock) that Int is 32-bits for testing. We can actually perform an exhaustive test without too much trouble:
|
||||
index :: Int -> A.Type
|
||||
index 0 = A.Bool
|
||||
index 1 = A.Byte
|
||||
index 2 = A.UInt16
|
||||
index 3 = A.UInt32
|
||||
index 4 = A.UInt64
|
||||
index 5 = A.Int8
|
||||
index 6 = A.Int16
|
||||
index 7 = A.Int
|
||||
index 8 = A.Int32
|
||||
index 9 = A.Int64
|
||||
|
||||
t = True
|
||||
f = False
|
||||
|
||||
results :: [[Bool]]
|
||||
--Each row is a conversion to that type. For example, the first row is conversions *to* Bool:
|
||||
results =
|
||||
[ [t, f,f,f,f, f,f,f,f,f] --to Bool
|
||||
|
||||
,[t, t,f,f,f, f,f,f,f,f] --to Byte
|
||||
,[t, t,t,f,f, f,f,f,f,f] --to UInt16
|
||||
,[t, t,t,t,f, f,f,f,f,f] --to UInt32
|
||||
,[t, t,t,t,t, f,f,f,f,f] --to UInt64
|
||||
|
||||
,[t, f,f,f,f, t,f,f,f,f] --to Int8
|
||||
,[t, t,f,f,f, t,t,f,f,f] --to Int16
|
||||
,[t, t,t,f,f, t,t,t,t,f] --to Int
|
||||
,[t, t,t,f,f, t,t,t,t,f] --to Int32
|
||||
,[t, t,t,t,f, t,t,t,t,t] --to Int64
|
||||
]
|
||||
|
||||
|
||||
|
||||
--Returns the list of tests:
|
||||
|
@ -149,6 +209,7 @@ tests = TestList
|
|||
testFunctionsToProcs0
|
||||
,testFunctionsToProcs1
|
||||
,testFunctionsToProcs2
|
||||
,testIsSafeConversion
|
||||
]
|
||||
|
||||
|
||||
|
|
66
Types.hs
66
Types.hs
|
@ -303,30 +303,52 @@ isPreciseConversion fromT toT
|
|||
= fromT == toT || not (isRealType fromT || isRealType toT)
|
||||
|
||||
-- | Will a conversion between two types always succeed?
|
||||
--Parameters are src dest
|
||||
isSafeConversion :: A.Type -> A.Type -> Bool
|
||||
isSafeConversion A.Real32 A.Real64 = True
|
||||
isSafeConversion fromT toT = (fromT == toT) || ((fromP /= -1) && (toP /= -1) && (fromP <= toP))
|
||||
isSafeConversion src dest = (src' == dest') || ((src' == A.Bool || isIntegerType src') && (dest' == A.Bool || isIntegerType dest') && (findCastRoute dest' src'))
|
||||
where
|
||||
fromP = precNum fromT
|
||||
toP = precNum toT
|
||||
src' = convInt src
|
||||
dest' = convInt dest
|
||||
|
||||
precNum :: A.Type -> Int
|
||||
precNum t = precNum' t 0 convPrec
|
||||
--Turn Int into Int32:
|
||||
convInt :: A.Type -> A.Type
|
||||
convInt A.Int = A.Int32
|
||||
convInt t = t
|
||||
|
||||
precNum' :: A.Type -> Int -> [[A.Type]] -> Int
|
||||
precNum' _ n [] = (-1)
|
||||
precNum' t n (tl:tls)
|
||||
= if t `elem` tl then n
|
||||
else precNum' t (n + 1) tls
|
||||
--Parameters are dest src
|
||||
findCastRoute :: A.Type -> A.Type -> Bool
|
||||
findCastRoute dest src
|
||||
--Either a direct converstion is possible
|
||||
= (elem (dest,src) possibleConversions)
|
||||
--Or there exists some chained conversion:
|
||||
|| (any (findCastRoute dest) (findDests src possibleConversions))
|
||||
|
||||
convPrec :: [[A.Type]]
|
||||
convPrec
|
||||
= [ [A.Bool]
|
||||
, [A.Byte]
|
||||
, [A.Int16]
|
||||
, [A.Int, A.Int32]
|
||||
, [A.Int64]
|
||||
]
|
||||
--Finds all the conversions from the src type using the given list of (dest,src)
|
||||
--Note that the list must not allow any cycles! (or else we will engage in infinite recursion)
|
||||
findDests :: A.Type -> [(A.Type,A.Type)] -> [A.Type]
|
||||
findDests _ [] = []
|
||||
findDests src ((dest,src'):ts) = if src == src' then dest : (findDests src ts) else findDests src ts
|
||||
|
||||
--Listed in order (dest, src)
|
||||
--Signed numbers cannot be safely cast to unsigned numbers. So (A.UInt16, A.Int8) isn't possible
|
||||
possibleConversions :: [(A.Type,A.Type)]
|
||||
possibleConversions
|
||||
= [
|
||||
(A.Byte, A.Bool)
|
||||
,(A.Int8, A.Bool)
|
||||
|
||||
,(A.Int16, A.Int8)
|
||||
,(A.Int16, A.Byte)
|
||||
,(A.Int32, A.Int16)
|
||||
,(A.Int32, A.UInt16)
|
||||
,(A.Int64, A.Int32)
|
||||
,(A.Int64, A.UInt32)
|
||||
|
||||
,(A.UInt16, A.Byte)
|
||||
,(A.UInt32, A.UInt16)
|
||||
,(A.UInt64, A.UInt32)
|
||||
]
|
||||
|
||||
--{{{ classes of types
|
||||
-- | Scalar integer types.
|
||||
|
@ -334,6 +356,10 @@ isIntegerType :: A.Type -> Bool
|
|||
isIntegerType t
|
||||
= case t of
|
||||
A.Byte -> True
|
||||
A.UInt16 -> True
|
||||
A.UInt32 -> True
|
||||
A.UInt64 -> True
|
||||
A.Int8 -> True
|
||||
A.Int -> True
|
||||
A.Int16 -> True
|
||||
A.Int32 -> True
|
||||
|
@ -389,6 +415,10 @@ data BytesInResult =
|
|||
-- | Return the size in bytes of a data type.
|
||||
bytesInType :: (CSM m, Die m) => A.Type -> m BytesInResult
|
||||
bytesInType A.Byte = return $ BIJust 1
|
||||
bytesInType A.UInt16 = return $ BIJust 2
|
||||
bytesInType A.UInt32 = return $ BIJust 4
|
||||
bytesInType A.UInt64 = return $ BIJust 8
|
||||
bytesInType A.Int8 = return $ BIJust 1
|
||||
-- FIXME This is tied to the backend we're using (as is the constant folder).
|
||||
bytesInType A.Int = return $ BIJust 4
|
||||
bytesInType A.Int16 = return $ BIJust 2
|
||||
|
|
Loading…
Reference in New Issue
Block a user