qute-0.1.0: src/Language/QBE/Simulator/Default/Generator.hs
-- SPDX-FileCopyrightText: 2025 Sören Tempel <soeren+git@soeren-tempel.net>
--
-- SPDX-License-Identifier: GPL-3.0-only
module Language.QBE.Simulator.Default.Generator (generateOperators) where
import Language.Haskell.TH
data ValueCons
= VWord
| VLong
| VSingle
| VDouble
deriving (Show)
toSigned :: ValueCons -> Maybe String
toSigned VWord = Just "Int32"
toSigned VLong = Just "Int64"
toSigned VSingle = Nothing
toSigned VDouble = Nothing
toSignedExp :: ValueCons -> Exp -> Exp
toSignedExp vCons expr =
case toSigned vCons of
Nothing -> expr
Just st ->
let cast = AppE (VarE $ mkName "fromIntegral") expr
in SigE cast (ConT $ mkName st)
------------------------------------------------------------------------
thBinaryFunc :: Exp -> Exp -> Exp -> Exp
thBinaryFunc func lhs = AppE (AppE func lhs)
thBinaryOp :: Exp -> Exp -> Exp -> Exp
thBinaryOp op = thBinaryFunc (ParensE op)
------------------------------------------------------------------------
-- Takes an lhs and rhs value and transform it to some 'Exp'.
type Transformer = ValueCons -> Exp -> Exp -> Exp
applyFunc :: Exp -> ValueCons -> Exp -> Exp -> Exp
applyFunc func vCon lhs rhs =
AppE (ConE $ mkName (show vCon)) (thBinaryFunc func lhs rhs)
applyOp :: Name -> ValueCons -> Exp -> Exp -> Exp
applyOp opName =
applyFunc (ParensE (VarE opName))
applySignedOp :: Name -> ValueCons -> Exp -> Exp -> Exp
applySignedOp opName vCon lhs rhs =
let lhs' = toSignedExp vCon lhs
rhs' = toSignedExp vCon rhs
cast = AppE (VarE $ mkName "fromIntegral")
in -- TODO: Code duplication with applyFunc
AppE (ConE $ mkName (show vCon)) (cast $ thBinaryFunc (VarE opName) lhs' rhs')
applyBoolOp :: Name -> ValueCons -> Exp -> Exp -> Exp
applyBoolOp opName _vCons lhs rhs =
let res = thBinaryOp (VarE opName) lhs rhs
toL = AppE (AppE (VarE $ mkName "E.fromLit") (AppE (ConE $ mkName "QBE.Base") (ConE $ mkName "QBE.Long")))
in toL $ CondE res (LitE $ IntegerL 1) (LitE $ IntegerL 0)
applySignedBoolOp :: Name -> ValueCons -> Exp -> Exp -> Exp
applySignedBoolOp opName vCons lhs rhs =
applyBoolOp opName vCons (toSignedExp vCons lhs) (toSignedExp vCons rhs)
------------------------------------------------------------------------
operators :: [(Name, Transformer)]
operators =
[ (mkName "add'", applyOp (mkName "+")),
(mkName "sub'", applyOp (mkName "-")),
(mkName "mul'", applyOp (mkName "*")),
(mkName "eq'", applyBoolOp (mkName "==")),
(mkName "ne'", applyBoolOp (mkName "/=")),
(mkName "sle'", applySignedBoolOp (mkName "<=")),
(mkName "slt'", applySignedBoolOp (mkName "<")),
(mkName "sge'", applySignedBoolOp (mkName ">=")),
(mkName "sgt'", applySignedBoolOp (mkName ">")),
(mkName "ule'", applyBoolOp (mkName "<=")),
(mkName "ult'", applyBoolOp (mkName "<")),
(mkName "uge'", applyBoolOp (mkName ">=")),
(mkName "ugt'", applyBoolOp (mkName ">"))
]
decOperators :: [(Name, Transformer)]
decOperators =
[ (mkName "srem'", applySignedOp (mkName "rem")),
(mkName "urem'", applyOp (mkName "rem")),
(mkName "udiv'", applyOp (mkName "quot")),
(mkName "or'", applyOp (mkName ".|.")),
(mkName "xor'", applyOp (mkName "Data.Bits.xor")),
(mkName "and'", applyOp (mkName ".&."))
]
------------------------------------------------------------------------
decCons :: [ValueCons]
decCons = [VWord, VLong]
cons :: [ValueCons]
cons = decCons ++ [VSingle, VDouble]
makeClause :: Transformer -> ValueCons -> Q Clause
makeClause trans vCon = do
lhs <- newName "lhs"
rhs <- newName "rhs"
let res = trans vCon (VarE lhs) (VarE rhs)
let body = AppE (ConE (mkName "Just")) res
let con = mkName (show vCon)
return $
Clause
[ ConP con [] [VarP lhs],
ConP con [] [VarP rhs]
]
(NormalB body)
[]
typingErrorClause :: Clause
typingErrorClause =
Clause
[WildP, WildP]
(NormalB (ConE $ mkName "Nothing"))
[]
------------------------------------------------------------------------
genOp :: [ValueCons] -> (Name, Transformer) -> Q Dec
genOp opLst (name, trans) = do
valDefs <- mapM (makeClause trans) opLst
return $ FunD name (valDefs ++ [typingErrorClause])
generateOperators :: Q [Dec]
generateOperators = do
o1 <- mapM (genOp cons) operators
o2 <- mapM (genOp decCons) decOperators
pure $ o1 ++ o2