1-- SPDX-FileCopyrightText: 2026 Sören Tempel <soeren+git@soeren-tempel.net>2--3-- SPDX-License-Identifier: GPL-3.0-only45-- | This module implements type classes on top of 'Language.QBE.Types' that6-- implement a map operation over the 'Language.QBE.Value',7-- 'Language.QBE.UserIdent', and 'Language.QBE.GlobalIdent' used by AST nodes.8module Language.QBE.Uses9 ( Value (..),10 GlobalIdent (..),11 UserIdent (..),12 )13where1415import Data.Map qualified as Map16import Language.QBE.Types qualified as Q1718mapFieldType :: Q.Field -> (Q.UserIdent -> Q.UserIdent) -> Q.Field19mapFieldType (sty, n) f = (mapType sty f, n)2021-- | Type class for AST nodes using a 'Q.UserIdent' internally.22class UserIdent a where23 -- | Invoke the provided function for each 'Q.UserIdent' within the AST node @a@.24 mapType :: a -> (Q.UserIdent -> Q.UserIdent) -> a2526instance UserIdent Q.TypeDef where27 mapType ty@(Q.TypeDef {Q.aggName = name, Q.aggType = aTy}) f =28 ty {Q.aggName = f name, Q.aggType = mapType aTy f}2930instance UserIdent Q.SubType where31 mapType (Q.SUserDef uid) f = Q.SUserDef $ f uid32 mapType ty@(Q.SExtType _) _ = ty3334instance UserIdent Q.AggType where35 mapType (Q.ARegular fields) f = Q.ARegular $ map (`mapFieldType` f) fields36 mapType (Q.AUnion fields) f = Q.AUnion $ map (map (`mapFieldType` f)) fields37 mapType (Q.AOpaque w64) _ = Q.AOpaque w643839instance UserIdent Q.Abity where40 mapType (Q.AUserDef uid) f = Q.AUserDef (f uid)41 mapType abity _ = abity4243instance UserIdent Q.FuncDef where44 mapType func@(Q.FuncDef {Q.fAbity = Just abity}) f =45 func {Q.fAbity = Just $ mapType abity f}46 mapType func _ = func4748------------------------------------------------------------------------4950replaceGlobal :: (Q.GlobalIdent -> Q.GlobalIdent) -> Q.Value -> Q.Value51replaceGlobal _ v@(Q.VLocal _) = v52replaceGlobal f (Q.VConst dynConst) =53 Q.VConst $ mapGlobals dynConst f5455-- | Type class for AST nodes using a 'Q.GlobalIdent' internally.56class GlobalIdent a where57 -- | Invoke the provided function for each 'Q.GlobalIdent' within the AST node @a@.58 mapGlobals :: a -> (Q.GlobalIdent -> Q.GlobalIdent) -> a5960instance GlobalIdent Q.Const where61 mapGlobals (Q.Global i) f = Q.Global (f i)62 mapGlobals c@(Q.DFP _) _ = c63 mapGlobals c@(Q.SFP _) _ = c64 mapGlobals c@(Q.Number _) _ = c6566instance GlobalIdent Q.DynConst where67 mapGlobals (Q.Const c) f = Q.Const $ mapGlobals c f68 mapGlobals (Q.Thread i) f = Q.Thread (f i)69 mapGlobals (Q.Common i) f = Q.Common (f i)70 mapGlobals (Q.Extern i) f = Q.Extern (f i)71 mapGlobals (Q.ExternThread i) f = Q.ExternThread (f i)7273instance GlobalIdent Q.DataDef where74 mapGlobals def f =75 def76 { Q.name = f $ Q.name def,77 Q.objs = map (`mapGlobals` f) $ Q.objs def78 }7980instance GlobalIdent Q.DataObj where81 mapGlobals o@(Q.OZeroFill _) _ = o82 mapGlobals (Q.OItem ty items) f =83 Q.OItem ty $ map (`mapGlobals` f) items8485instance GlobalIdent Q.DataItem where86 mapGlobals (Q.DSymOff ident off) f = Q.DSymOff (f ident) off87 mapGlobals (Q.DConst c) f = Q.DConst $ mapGlobals c f88 mapGlobals s@(Q.DString _) _ = s8990instance GlobalIdent Q.FuncDef where91 mapGlobals func f =92 func93 { Q.fName = f (Q.fName func),94 Q.fBlock = Map.map (`mapOperands` replaceGlobal f) $ Q.fBlock func95 }9697------------------------------------------------------------------------9899-- | Type class for AST nodes using a 'Q.Value' internally.100class Value a where101 -- | Invoke the provided function for each 'Q.Value' within the AST node @a@.102 mapOperands :: a -> (Q.Value -> Q.Value) -> a103104instance Value Q.FuncArg where105 mapOperands fa f =106 case fa of107 Q.ArgReg a v -> Q.ArgReg a (f v)108 Q.ArgEnv v -> Q.ArgEnv (f v)109 Q.ArgVar -> Q.ArgVar110111instance Value Q.JumpInstr where112 mapOperands ji f =113 case ji of114 Q.Jump ident -> Q.Jump ident115 Q.Jnz v ifT ifF -> Q.Jnz (f v) ifT ifF116 Q.Return mayVal -> Q.Return (f <$> mayVal)117 Q.Halt -> Q.Halt118119instance Value Q.Instr where120 mapOperands instr f =121 case instr of122 Q.Add lhs rhs -> Q.Add (f lhs) (f rhs)123 Q.Sub lhs rhs -> Q.Sub (f lhs) (f rhs)124 Q.Div lhs rhs -> Q.Div (f lhs) (f rhs)125 Q.Mul lhs rhs -> Q.Mul (f lhs) (f rhs)126 Q.Neg val -> Q.Neg (f val)127 Q.URem lhs rhs -> Q.URem (f lhs) (f rhs)128 Q.Rem lhs rhs -> Q.Rem (f lhs) (f rhs)129 Q.UDiv lhs rhs -> Q.UDiv (f lhs) (f rhs)130 Q.Or lhs rhs -> Q.Or (f lhs) (f rhs)131 Q.Xor lhs rhs -> Q.Xor (f lhs) (f rhs)132 Q.And lhs rhs -> Q.And (f lhs) (f rhs)133 Q.Sar lhs rhs -> Q.Sar (f lhs) (f rhs)134 Q.Shr lhs rhs -> Q.Shr (f lhs) (f rhs)135 Q.Shl lhs rhs -> Q.Shl (f lhs) (f rhs)136 Q.Alloc siz val -> Q.Alloc siz (f val)137 Q.Load ty val -> Q.Load ty (f val)138 Q.CompareInt a c lhs rhs -> Q.CompareInt a c (f lhs) (f rhs)139 Q.CompareFloat a c lhs rhs -> Q.CompareFloat a c (f lhs) (f rhs)140 Q.Ext n val -> Q.Ext n (f val)141 Q.FloatToInt a b val -> Q.FloatToInt a b (f val)142 Q.IntToFloat a b val -> Q.IntToFloat a b (f val)143 Q.TruncDouble val -> Q.TruncDouble (f val)144 Q.Cast val -> Q.Cast (f val)145 Q.Copy val -> Q.Copy (f val)146 Q.VAArg val -> Q.VAArg (f val)147148instance Value Q.VolatileInstr where149 mapOperands vi f =150 case vi of151 Q.Store ty lhs rhs -> Q.Store ty (f lhs) (f rhs)152 Q.VAStart val -> Q.VAStart (f val)153 Q.Blit lhs rhs w -> Q.Blit (f lhs) (f rhs) w154 dbg@(Q.DBGLoc {}) -> dbg155156instance Value Q.Statement where157 mapOperands s f =158 case s of159 Q.Assign ident ty instr -> Q.Assign ident ty (mapOperands instr f)160 Q.Call retTy func args -> Q.Call retTy (f func) (map (`mapOperands` f) args)161 Q.Volatile vi -> Q.Volatile (mapOperands vi f)162163instance Value Q.Phi where164 mapOperands p f = p {Q.pLabels = Map.map f (Q.pLabels p)}165166instance Value Q.Block where167 mapOperands b f =168 b169 { Q.phi = map (`mapOperands` f) $ Q.phi b,170 Q.stmt = map (`mapOperands` f) $ Q.stmt b,171 Q.term = mapOperands (Q.term b) f172 }