-- Common code used by various converters module AExpr2Util( getMethodOutputPort ) where import qualified Data.Map as M import Data.List(find) import ErrorUtil(internalError) import PPrint import Id(qualEq) import ASyntax import VModInfo(VModInfo(..), VFieldInfo(..), vName_to_id) -- ------------------------- -- Different methods on submodules might be defined to use the same ports, -- so two AMethCall expressions might differ but be logically equivalent. -- If we declare separate variables for the two calls, then the solver will -- not recognize that they are equal. Rather than assert all of the -- equivalences in the solver's context, we can reduce each AMethCall to a -- canonical form before declaring a variable. The canonical form is defined -- to be the same for two AMethCalls that are logically equivalent. -- This canonicalization needs to happen for any expression with arguments -- that is being replaced with a variable, because method calls might appear -- in the arguments. -- XXX For SMT solvers, instead of replacing foreign expressions with a variable, -- XXX we can replace them with an unevaluated function applied to its arguments! -- XXX That way, the SMT solver will handle any equivalence of the arguments. getMethodOutputPort :: (M.Map AId VModInfo) -> AId -> AId -> AId getMethodOutputPort stateMap modId methId = let mod_err = internalError("canonMethCalls: module not found: " ++ ppReadable modId) fields = vFields $ M.findWithDefault mod_err modId stateMap meth_err = internalError("canonMethCalls: method not found: " ++ ppReadable (modId, methId)) findFn (Method { vf_name = i }) = qualEq i methId findFn _ = False mport = case (find findFn fields) of Just (Method { vf_output = mo }) -> mo _ -> meth_err out_err = internalError("canonMethCalls: method has no output: " ++ ppReadable (modId, methId)) in case mport of Just (vn,_) -> vName_to_id vn _ -> out_err -- -------------------------