1-- SPDX-FileCopyrightText: 2025 Sören Tempel <soeren+git@soeren-tempel.net>2--3-- SPDX-License-Identifier: GPL-3.0-only45module Language.QBE.Simulator.Default.Generator (generateOperators) where67import Language.Haskell.TH89data ValueCons10 = VWord11 | VLong12 | VSingle13 | VDouble14 deriving (Show)1516toSigned :: ValueCons -> Maybe String17toSigned VWord = Just "Int32"18toSigned VLong = Just "Int64"19toSigned VSingle = Nothing20toSigned VDouble = Nothing2122toSignedExp :: ValueCons -> Exp -> Exp23toSignedExp vCons expr =24 case toSigned vCons of25 Nothing -> expr26 Just st ->27 let cast = AppE (VarE $ mkName "fromIntegral") expr28 in SigE cast (ConT $ mkName st)2930------------------------------------------------------------------------3132thBinaryFunc :: Exp -> Exp -> Exp -> Exp33thBinaryFunc func lhs = AppE (AppE func lhs)3435thBinaryOp :: Exp -> Exp -> Exp -> Exp36thBinaryOp op = thBinaryFunc (ParensE op)3738------------------------------------------------------------------------3940-- Takes an lhs and rhs value and transform it to some 'Exp'.41type Transformer = ValueCons -> Exp -> Exp -> Exp4243applyFunc :: Exp -> ValueCons -> Exp -> Exp -> Exp44applyFunc func vCon lhs rhs =45 AppE (ConE $ mkName (show vCon)) (thBinaryFunc func lhs rhs)4647applyOp :: Name -> ValueCons -> Exp -> Exp -> Exp48applyOp opName =49 applyFunc (ParensE (VarE opName))5051applySignedOp :: Name -> ValueCons -> Exp -> Exp -> Exp52applySignedOp opName vCon lhs rhs =53 let lhs' = toSignedExp vCon lhs54 rhs' = toSignedExp vCon rhs55 cast = AppE (VarE $ mkName "fromIntegral")56 in -- TODO: Code duplication with applyFunc57 AppE (ConE $ mkName (show vCon)) (cast $ thBinaryFunc (VarE opName) lhs' rhs')5859applyBoolOp :: Name -> ValueCons -> Exp -> Exp -> Exp60applyBoolOp opName _vCons lhs rhs =61 let res = thBinaryOp (VarE opName) lhs rhs62 toL = AppE (AppE (VarE $ mkName "E.fromLit") (AppE (ConE $ mkName "QBE.Base") (ConE $ mkName "QBE.Long")))63 in toL $ CondE res (LitE $ IntegerL 1) (LitE $ IntegerL 0)6465applySignedBoolOp :: Name -> ValueCons -> Exp -> Exp -> Exp66applySignedBoolOp opName vCons lhs rhs =67 applyBoolOp opName vCons (toSignedExp vCons lhs) (toSignedExp vCons rhs)6869------------------------------------------------------------------------7071operators :: [(Name, Transformer)]72operators =73 [ (mkName "add'", applyOp (mkName "+")),74 (mkName "sub'", applyOp (mkName "-")),75 (mkName "mul'", applyOp (mkName "*")),76 (mkName "eq'", applyBoolOp (mkName "==")),77 (mkName "ne'", applyBoolOp (mkName "/=")),78 (mkName "sle'", applySignedBoolOp (mkName "<=")),79 (mkName "slt'", applySignedBoolOp (mkName "<")),80 (mkName "sge'", applySignedBoolOp (mkName ">=")),81 (mkName "sgt'", applySignedBoolOp (mkName ">")),82 (mkName "ule'", applyBoolOp (mkName "<=")),83 (mkName "ult'", applyBoolOp (mkName "<")),84 (mkName "uge'", applyBoolOp (mkName ">=")),85 (mkName "ugt'", applyBoolOp (mkName ">"))86 ]8788decOperators :: [(Name, Transformer)]89decOperators =90 [ (mkName "srem'", applySignedOp (mkName "rem")),91 (mkName "urem'", applyOp (mkName "rem")),92 (mkName "udiv'", applyOp (mkName "quot")),93 (mkName "or'", applyOp (mkName ".|.")),94 (mkName "xor'", applyOp (mkName "Data.Bits.xor")),95 (mkName "and'", applyOp (mkName ".&."))96 ]9798------------------------------------------------------------------------99100decCons :: [ValueCons]101decCons = [VWord, VLong]102103cons :: [ValueCons]104cons = decCons ++ [VSingle, VDouble]105106makeClause :: Transformer -> ValueCons -> Q Clause107makeClause trans vCon = do108 lhs <- newName "lhs"109 rhs <- newName "rhs"110111 let res = trans vCon (VarE lhs) (VarE rhs)112 let body = AppE (ConE (mkName "Just")) res113114 let con = mkName (show vCon)115 return $116 Clause117 [ ConP con [] [VarP lhs],118 ConP con [] [VarP rhs]119 ]120 (NormalB body)121 []122123typingErrorClause :: Clause124typingErrorClause =125 Clause126 [WildP, WildP]127 (NormalB (ConE $ mkName "Nothing"))128 []129130------------------------------------------------------------------------131132genOp :: [ValueCons] -> (Name, Transformer) -> Q Dec133genOp opLst (name, trans) = do134 valDefs <- mapM (makeClause trans) opLst135 return $ FunD name (valDefs ++ [typingErrorClause])136137generateOperators :: Q [Dec]138generateOperators = do139 o1 <- mapM (genOp cons) operators140 o2 <- mapM (genOp decCons) decOperators141 pure $ o1 ++ o2