module Language.Clafer.Intermediate.GLPKScopeAnalyzer (glpkScopeAnalysis) where
import Language.Clafer.Front.Absclafer hiding (Path)
import qualified Language.Clafer.Intermediate.Intclafer as I
import Language.Clafer.Intermediate.Analysis
import Language.Clafer.Intermediate.ResolverType
import Control.Applicative (Applicative(..), (<$>))
import Control.Monad
import Control.Monad.List
import Control.Monad.LPMonad
import Control.Monad.Maybe
import Control.Monad.Reader
import Control.Monad.State
import Data.Either
import Data.LinearProgram hiding (constraints)
import Data.List
import Data.Map ()
import qualified Data.Map as Map
import Data.Maybe
import System.IO.Unsafe
import Text.Parsec.Combinator
import Text.Parsec.Error
import Text.Parsec.Pos
import Text.Parsec.Prim
import Text.Parsec.String ()
glpkScopeAnalysis :: I.IModule -> [(String, Integer)]
glpkScopeAnalysis imodule =
intScope ++ scopes
where
intScope = if bitwidth > 4 then return ("int", bitwidth) else fail "Bitwidth less than default."
bitwidth = bitwidthAnalysis (constants ++ map snd scopes)
scopes =
removeZeroes $ removeRoot $ removeAux $
case unsafePerformIO solution of
(Success, Just (_, s)) -> Map.toList $ Map.map round s
_ -> []
((_, constants), analysis) = runScopeAnalysis run $ gatherInfo imodule
run =
do
setConstraints
abstracts' <- clafers `suchThat` isAbstract
constants' <- constantsAnalysis
return (abstracts', constants')
solution = glpSolveVars mipDefaults{msgLev = MsgOff} $ analysis
removeZeroes = filter ((/= 0) . snd)
removeRoot = filter ((/= rootUid) . fst)
removeAux = filter (not . (uniqNameSpace `isPrefixOf`) . fst)
bitwidthAnalysis :: [Integer] -> Integer
bitwidthAnalysis constants =
toInteger $ 1 + fromJust (findIndex (\x -> all (`within` x) constants) bitRange)
where
within a (minB, maxB) = a >= minB && a <= maxB
bitRange = [(2^i, 2^i1) | i <- ([0..]::[Integer])]
constantsAnalysis :: ScopeAnalysis [Integer]
constantsAnalysis =
do
cons <- constraintsUnder anything `select` snd
return $ mapMaybe integerConstant [I._exp sub | con <- cons, sub <- subexpressions con]
where
integerConstant (I.IInt i) = Just i
integerConstant _ = Nothing
data Between =
Between Integer Integer
deriving Show
mult :: Integer -> Integer -> Integer
mult (1) _ = 1
mult _ (1) = 1
mult a b = a * b
simpleAnalysis :: ScopeAnalysis [(String, Between)]
simpleAnalysis =
do
root <- claferWithUid rootUid
analysis <- simpleAnalysis' root (Between 1 1)
return analysis
where
simpleAnalysis' cur cb@(Between l h) =
runListT $ return (uid cur, cb) `mplus` do
child <- foreach $ (anything |^ cur) `select` fst
let b
| groupLow cur == 0 && groupHigh cur == 1 = Between (low child * l) (high child `mult` h)
| otherwise = Between 0 (1)
foreach (simpleAnalysis' child b)
setConstraints :: ScopeAnalysis ()
setConstraints =
do
simpleAnalysis
p <- flatten
withExtraClafers p $ do
optFormula
colonConstraints
refConstraints
parentConstraints
constraintConstraints
(var rootUid) `equalTo` 1
optFormula :: ScopeAnalysis ()
optFormula =
do
setDirection Min
c <- clafers
let concretes = [uid concrete | concrete <- c, isConcrete concrete, isDerived concrete, not $ uniqNameSpace `isPrefixOf` uid concrete]
setObjective $ varSum concretes
parentConstraints :: ScopeAnalysis ()
parentConstraints =
runListT_ $ do
(child, parent) <- foreach $ anything |^ anything
let uchild = uid child
let uparent = uid parent
if low child == high child
then do
var uchild `equal` (low child *^ var uparent)
else do
var uchild `geq` (low child *^ var uparent)
if high child /= 1
then var uchild `leq` (high child *^ var uparent)
else (smallM *^ var uchild) `leq` var uparent
setVarKind uchild IntVar
setVarKind uparent IntVar
refConstraints :: ScopeAnalysis ()
refConstraints =
runListT_ $ do
(sub, sup) <- foreach $ (anything |-> anything) `suchThat` (isDerived . superClafers)
let usub = uid sub
let usup = uid sup
aux <- testPositive usub
var usup `geq` ((max 1 $ low sub) *^ var aux)
colonConstraints :: ScopeAnalysis ()
colonConstraints =
runListT_ $ do
c <- foreach $ clafers `suchThat` isDerived
subs <- findAll $ (anything |: c) `select` (uid . subClafers)
when (not $ null subs) $
var (uid c) `equal` varSum subs
flatten :: ScopeAnalysis [SClafer]
flatten =
runListT $ do
abs' <- clafers `suchThat` isAbstract
(c, s) <- foreach $ anything |: anything
ListT $ runReaderT (addChildren (map uid abs') (Part [uid c, uid s]) (Part [])) []
addChildren :: MonadAnalysis m => [String] -> Part -> Part -> m [SClafer]
addChildren abs' (Part steps) ss@(Part supSteps) =
do
let parBase = last steps
chis <- directChildrenOf parBase
achis <- forM chis $
\chi -> do
let chiP = Part $ init steps ++ [chi]
let par = Part steps
let supP = Part $ supSteps ++ [chi]
chiC <- claferWithUid chi
let s = SClafer (reifyPartName chiP) chi False (low chiC) (high chiC) (groupLow chiC) (groupHigh chiC) (Just $ reifyPartName par) (Just $ Colon $ reifyPartName supP) (constraints chiC)
return s <:> addChildren abs' chiP ss
col <- runMaybeT $ colonOf parBase
case col of
Just col' -> do
acol <- addChildren abs' (Part $ steps ++ [col']) (Part $ supSteps ++ [parBase])
return $ concat achis ++ acol
Nothing -> return $ concat achis
where
notAbs = not . (`elem` abs')
reifyPartName (Part (t : target)) = reifyPartName' $ t : filter notAbs target
reifyPartName (Part []) = error "Function reifyPartName from GLPKScopeAnalyzer expects a non empty Part, but was given one!"
reifyPartName' [target] = target
reifyPartName' target = uniqNameSpace ++ "reify_" ++ intercalate "_" target
data Path =
Path {parts::[Part]}
deriving (Eq, Ord, Show)
data Part =
Part {steps::[String]}
deriving (Eq, Ord, Show)
data Expr =
This Path I.IType |
Global Path I.IType |
Const Integer |
Concat [Expr] I.IType |
Positive [Path] Integer I.IType
deriving Show
eType :: Expr -> I.IType
eType (This _ e) = e
eType (Global _ e) = e
eType (Concat _ e) = e
eType (Positive _ _ e) = e
eType (Const _) = error "Function eType from GLPK did not expect a Const"
isThis :: Expr -> Bool
isThis This{} = True
isThis _ = False
isGlobal :: Expr -> Bool
isGlobal Global{} = True
isGlobal _ = False
parentOfPart :: MonadAnalysis m => Part -> m Part
parentOfPart (Part s) =
do
s' <- parentOf $ last s
cs' <- claferWithUid s'
return $ if isAbstract cs'
then Part $ init s
else Part $ init s ++ [s']
optimizeInConstraints :: [I.PExp] -> [I.PExp]
optimizeInConstraints constraints =
noOpt ++ opt
where
(noOpt, toOpt) = partitionEithers (constraints >>= partitionConstraint)
opt = [ unionPExpAll (map fst inSame) `inPExp` snd (head inSame)
| inSame <- groupBy (testing' $ syntaxOf . snd) $ sortBy (comparing' snd) toOpt ]
inPExp a b = I.PExp (Just I.TBoolean) "" noSpan $ I.IFunExp "in" [a, b]
unionPExpAll es = foldr1 unionPExp es
unionPExp a b = I.PExp (liftM2 (+++) (I._iType a) (I._iType b)) "" noSpan $ I.IFunExp "++" [a, b]
partitionConstraint I.PExp{I._exp = I.IFunExp {I._op = "in", I._exps = [exp1, exp2]}} = return $ Right (exp1, exp2)
partitionConstraint I.PExp{I._exp = I.IFunExp {I._op = "&&", I._exps = [exp1, exp2]}} = partitionConstraint exp1 `mplus` partitionConstraint exp2
partitionConstraint e = return $ Left e
testing' f a b = f a == f b
comparing' f a b = f a `compare` f b
optimizeAllConstraints :: MonadAnalysis m => SClafer -> [I.PExp] -> m [(SClafer, I.PExp)]
optimizeAllConstraints curThis constraints =
runListT $ partitionConstraint =<< foreachM constraints
where
partitionConstraint I.PExp{I._exp = I.IDeclPExp I.IAll [I.IDecl _ [decl] I.PExp{I._exp = I.IClaferId{I._sident}}] bpexp} =
do
under <- claferWithUid _sident
return (under, rename decl bpexp)
partitionConstraint I.PExp{I._exp = I.IFunExp {I._op = "&&", I._exps = [exp1, exp2]}} = partitionConstraint exp1 `mplus` partitionConstraint exp2
partitionConstraint e = return (curThis, e)
rename :: String -> I.PExp -> I.PExp
rename f p@I.PExp{I._exp = exp'} =
p{I._exp = renameIExp exp'}
where
renameIExp (I.IFunExp op exps) = I.IFunExp op $ map (rename f) exps
renameIExp (I.IDeclPExp quant oDecls bpexp) = I.IDeclPExp quant (map renameDecl oDecls) $ rename f bpexp
renameIExp (I.IClaferId modName sident isTop)
| f == sident = I.IClaferId modName "this" isTop
| otherwise = I.IClaferId modName sident isTop
renameIExp i = i
renameDecl (I.IDecl isDisj decls body)
| f `elem` decls = I.IDecl isDisj decls body
| otherwise = I.IDecl isDisj decls $ rename f body
optConstraintsUnder :: MonadAnalysis m => SClafer -> m [(SClafer, [I.PExp])]
optConstraintsUnder clafer =
do
cons <- constraintsUnder clafer `select` snd
allCons <- optimizeAllConstraints clafer cons
let inCons = [(fst $ head c, optimizeInConstraints $ map snd c) | c <- groupBy (testing' $ uid . fst) $ sortBy (comparing' $ uid . fst) allCons]
return inCons
where
testing' f a b = f a == f b
comparing' f a b = f a `compare` f b
constraintConstraints :: MonadScope m => m ()
constraintConstraints =
do
runListT_ $ do
clafer <- foreach clafers
(supThis, cons) <- foreach $ optConstraintsUnder clafer
con <- foreachM cons
curThis <-
if isAbstract supThis
then
foreach $ colonsTo supThis
else
return supThis
constraint <- foreach $ scopeConstraint curThis con
oneConstraint curThis constraint
where
oneConstraint c (e1, con, e2) =
void $ runMaybeT $ oneConstraintOneWay c e1 con e2 `mplus` oneConstraintOneWay c e2 (reverseCon con) e1
oneConstraintOneWay c@SClafer{uid} e1 con e2 =
oneConstraint' e1 e2
where
oneConstraint' _ (This (Path []) _) =
mzero
oneConstraint' _ (Global (Path []) _) =
mzero
oneConstraint' (This (Path []) _) (This (Path parts) _) =
return (var uid) `comp` reifyVar (last parts)
oneConstraint' (This (Path []) _) (Global (Path parts) _) =
return (var uid) `comp` reifyVar (last parts)
oneConstraint' (Positive [Path []] _ _) _ =
mzero
oneConstraint' _ (Positive [Path []] _ _) =
mzero
oneConstraint' (Global (Path gParts) _) (Positive allPaths claf _) =
do
aux <- testPositives (map (reifyVarName . last . parts) allPaths)
reifyVar (last gParts) `comp` return (claf *^ var aux)
oneConstraint' (This (Path parts) _) (Const constant)
| con == EQU = oneConstraintOneWay c e1 LEQ e2 >> oneConstraintOneWay c e1 GEQ e2
| con `elem` [GTH, GEQ] = foldM_ mkCon 1 (reverse parts)
| con `elem` [LTH, LEQ] = reifyVar (last parts) `comp` (return $ (fromInteger constant :: Double) *^ var uid)
where
mkCon :: MonadScope m => Integer -> Part -> m Integer
mkCon multiplier part =
do
let frac = (1 / fromInteger multiplier) * fromInteger constant :: Double
(reifyVar part) `comp` return (frac *^ var uid)
mult multiplier <$> prod part
oneConstraint' (Global (Path parts) _) (Const constant)
| con == EQU = oneConstraintOneWay c e1 LEQ e2 >> oneConstraintOneWay c e1 GEQ e2
| con `elem` [GTH, GEQ] =
do
k <- testPositive uid
foldM_ (mkCon k) 1 (reverse parts)
| con `elem` [LTH, LEQ] = reifyVar (last parts) `compTo` (return $ fromInteger constant)
where
mkCon :: MonadScope m => String -> Integer -> Part -> m Integer
mkCon pos (1) part =
do
(reifyVar part) `comp` return (var pos)
return (1)
mkCon pos multiplier part =
do
let frac = (1 / fromInteger multiplier) * fromInteger constant :: Double
(reifyVar part) `comp` return (frac *^ var pos)
mult multiplier <$> prod part
oneConstraint' (This (Path parts1) _) (This (Path parts2) _) =
reifyVar (last parts1) `comp` reifyVar (last parts2)
oneConstraint' (Global (Path parts1) _) (Global (Path parts2) _) =
reifyVar (last parts1) `comp` reifyVar (last parts2)
oneConstraint' (Global (Path parts) _) (Concat exprs _) =
if all isGlobal exprs
then reifyVar (last parts) `comp` reifyVars [last p | Global (Path p) _ <- exprs]
else mzero
oneConstraint' (This (Path parts) _) (Concat exprs _) =
if all isGlobal exprs
then do
let vs = [last p | Global (Path p) _ <- exprs]
claf <- mapM (claferWithUid . last . steps) $ vs
s <- mapM constantCard claf
p <- parentOfPart $ last parts
reifyVar (last parts) `comp` ((sum s *^) <$> reifyVar p)
else if all isThis exprs
then reifyVar (last parts) `comp` reifyVars [last p | This (Path p) _ <- exprs]
else mzero
oneConstraint' _ _ = mzero
constantCard SClafer{low, high}
| low == high = return low
| otherwise = mzero
prod (Part steps) = foldr1 mult <$> mapM (return . high <=< claferWithUid) steps
comp x y =
do
x' <- x
y' <- y
case con of
LTH -> (x' ^-^ y') `leqTo` (smallM)
LEQ -> x' `leq` y'
EQU -> x' `equal` y'
GTH -> (x' ^-^ y') `geqTo` smallM
GEQ -> x' `geq` y'
compTo x y =
do
x' <- x
y' <- y
case con of
LTH -> x' `leqTo` (y' smallM)
LEQ -> x' `leqTo` y'
EQU -> x' `equalTo` y'
GTH -> x' `geqTo` (y' + smallM)
GEQ -> x' `geqTo` y'
reifyVar p = return (var $ reifyVarName p)
reifyVars p = return (varSum $ map reifyVarName p)
reifyVarName (Part [target]) = target
reifyVarName (Part target) = uniqNameSpace ++ "reify_" ++ intercalate "_" target
data Con = EQU | LTH | LEQ | GTH | GEQ deriving (Eq, Ord, Show)
reverseCon :: Con -> Con
reverseCon EQU = EQU
reverseCon LTH = GTH
reverseCon LEQ = GEQ
reverseCon GTH = LTH
reverseCon GEQ = LEQ
data Limit = Exact {lExpr::Expr} | AtLeast {lExpr::Expr} deriving Show
scopeConstraint :: MonadScope m => SClafer -> I.PExp -> m [(Expr, Con, Expr)]
scopeConstraint curThis pexp =
runListT $ scopeConstraint' $ I._exp pexp
where
scopeConstraint' I.IFunExp {I._op = "&&", I._exps} = msum $ map (scopeConstraint' . I._exp) _exps
scopeConstraint' I.IDeclPExp {I._quant = I.ISome, I._oDecls = [], I._bpexp} = parsePath curThis _bpexp `greaterThanEqual` constant (1::Integer)
scopeConstraint' I.IDeclPExp {I._quant = I.ISome, I._oDecls} = msum $ map pathAndMultDecl _oDecls
where
pathAndMultDecl I.IDecl {I._isDisj = True, I._decls, I._body} = parsePath curThis _body `greaterThanEqual` constant (length _decls)
pathAndMultDecl I.IDecl {I._isDisj = False, I._body} = parsePath curThis _body `greaterThanEqual` constant (1::Integer)
scopeConstraint' I.IDeclPExp {I._quant = I.IOne, I._oDecls = [], I._bpexp} = parsePath curThis _bpexp `eqTo` constant (1::Integer)
scopeConstraint' I.IDeclPExp {I._quant = I.IOne, I._oDecls} =
do
oDecl <- foreachM _oDecls
parsePath curThis (I._body oDecl) `eqTo` constant (1::Integer)
scopeConstraint' I.IFunExp {I._op, I._exps = [exp1, exp2]}
| _op == "in" = inConstraint1 exp1 exp2 `mplus` inConstraint2 exp1 exp2
| _op == "=" = equalConstraint1 exp1 exp2 `mplus` equalConstraint2 exp1 exp2
| _op == "<" = scopeConstraintNum exp1 `lessThan` scopeConstraintNum exp2
| _op == "<=" = scopeConstraintNum exp1 `lessThanEqual` scopeConstraintNum exp2
| _op == ">" = scopeConstraintNum exp1 `greaterThan` scopeConstraintNum exp2
| _op == ">=" = scopeConstraintNum exp1 `greaterThanEqual` scopeConstraintNum exp2
| _op == "<=>" = (exp1 `implies` exp2) `mplus` (exp2 `implies` exp1)
| _op == "=>" = exp1 `implies` exp2
scopeConstraint' _ = mzero
implies exp1 exp2 =
do
e1 <- scopeConstraint' $ I._exp exp1
e2 <- scopeConstraint' $ I._exp exp2
case (e1, e2) of
((This thisPath t1, GEQ, Const 1), (Global globalPath t0, comp, Positive allPaths c t2)) ->
return $ (Global globalPath t0, comp, Positive (thisPath : allPaths) c $ t1 +++ t2)
((This thisPath e1', GEQ, Const 1), (Global globalPath e2', comp, Const c)) ->
return $ (Global globalPath e2', comp, Positive [thisPath] c e1')
((Global path1 t1, GEQ, Const 1), (Global path2 t0, comp, Positive allPaths c t2)) ->
return $ (Global path2 t0, comp, Positive (path1 : allPaths) c $ t1 +++ t2)
((Global path1 e1', GEQ, Const 1), (Global path2 e2', comp, Const c)) ->
return $ (Global path2 e2', comp, Positive [path1] c e1')
((t1@(This (Path [thisPart1]) _), GEQ, Const 1), (t2@(This (Path [_]) _), GEQ, Const 1)) ->
do
c <- claferWithUid $ last $ steps thisPart1
guard (high c == 1)
return (t2, GEQ, t1)
_ -> mzero
equalConstraint1 exp1 exp2 =
do
l1 <- scopeConstraintSet exp1
l2 <- scopeConstraintSet exp2
case (l1, l2) of
(Exact e1, Exact e2) -> return e1 `eqTo` return e2
(AtLeast e1, Exact e2) -> return e1 `greaterThanEqual` return e2
(Exact e1, AtLeast e2) -> return e1 `lessThanEqual` return e2
_ -> mzero
equalConstraint2 exp1 exp2 = scopeConstraintNum exp1 `eqTo` scopeConstraintNum exp2
inConstraint1 exp1 exp2 =
do
l1 <- scopeConstraintSet exp1
l2 <- scopeConstraintSet exp2
case l2 of
Exact e2 -> return (lExpr l1) `lessThanEqual` return e2
_ -> mzero
inConstraint2 exp1 exp2 = scopeConstraintNum exp1 `lessThanEqual` scopeConstraintNum exp2
scopeConstraintSet I.PExp {I._exp = I.IFunExp {I._op = "++", I._exps = [e1, e2]}} =
do
l1' <- scopeConstraintSet e1
l2' <- scopeConstraintSet e2
i <- intersects (eType $ lExpr l1') (eType $ lExpr l2')
if i
then return $ AtLeast $ lExpr l1'
else return $ combineDisjoint l1' l2'
scopeConstraintSet x = Exact <$> parsePath curThis x
combineDisjoint (Exact e1) (Exact e2) =
Exact (Concat ([e1, e2] >>= flattenConcat) $ eType e1 +++ eType e2)
combineDisjoint l1 l2 =
AtLeast (Concat ([e1, e2] >>= flattenConcat) $ eType e1 +++ eType e2)
where
e1 = lExpr l1
e2 = lExpr l2
flattenConcat (Concat es _) = es >>= flattenConcat
flattenConcat e = [e]
scopeConstraintNum I.PExp {I._exp = I.IInt const'} = constant const'
scopeConstraintNum I.PExp {I._exp = I.IFunExp {I._op = "#", I._exps = [path]}} = parsePath curThis path
scopeConstraintNum _ = mzero
constant :: (Monad m, Integral i) => i -> m Expr
constant = return . Const . toInteger
greaterThan = liftM2 (,GTH,)
greaterThanEqual = liftM2 (,GEQ,)
lessThan = liftM2 (,LTH,)
lessThanEqual = liftM2 (,LEQ,)
eqTo = liftM2 (,EQU,)
parsePath :: MonadScope m => SClafer -> I.PExp -> m Expr
parsePath start pexp =
do
start' <- claferWithUid (origUid start)
parsePath2 start' pexp
parsePath2 :: MonadScope m => SClafer -> I.PExp -> m Expr
parsePath2 start pexp =
do
root <- claferWithUid rootUid
case unfoldJoins pexp of
Just unfold -> do
match <- patternMatch parsePath' (ParseState root []) unfold
either (fail . show) return match
Nothing -> fail "Cannot unfold."
where
asPath :: [[String]] -> Path
asPath parts = Path [Part part | part <- parts, not $ null part]
parsePath' = (This <$> (asPath <$> parseThisPath) <*> getThisType) <|> (Global <$> (asPath <$> parseNonthisPath) <*> getThisType)
getThisType =
do
t <- getThis
return $ fromJust $ fromUnionType [uid t]
parseThisPath =
do
t <- _this_
do
many1 _parent_
return [[uid start]]
<|> (follow t >> parseNonthisPath)
parseNonthisPath =
do
paths <- many (step >>= follow)
lifo <- popStack
let end = if null paths then [] else [last paths]
let result = reverse $ end ++ map uid lifo
do
_ref_ >>= follow
rec <- parseNonthisPath
return $ result : rec
<|> return [result]
step :: MonadScope m => ParseT m String
step = _parent_ <|> _directChild_ <|> try (pushThis >> _indirectChild_)
follow :: MonadScope m => String -> ParseT m String
follow path =
do
curThis <- getThis
case path of
"this" -> putThis start
"parent" -> lift (parentOf curThis) >>= putThis
"ref" -> lift (refOf curThis) >>= putThis
u -> lift (claferWithUid u) >>= putThis
return path
newtype ScopeAnalysis a = ScopeAnalysis (VSupplyT (AnalysisT (LPM String Double)) a)
deriving (Monad, Functor, MonadState (LP String Double), MonadSupply Var, MonadReader Info, MonadAnalysis)
class (MonadAnalysis m, MonadState (LP String Double) m, MonadSupply Var m) => MonadScope m
instance (MonadAnalysis m, MonadState (LP String Double) m, MonadSupply Var m) => MonadScope m
runScopeAnalysis :: ScopeAnalysis a -> Info -> (a, LP String Double)
runScopeAnalysis (ScopeAnalysis s) info = runLPM $ runAnalysisT (runVSupplyT s) info
unfoldJoins :: Monad m => I.PExp -> m [Token]
unfoldJoins pexp =
unfoldJoins' pexp
where
unfoldJoins' I.PExp{I._exp = (I.IFunExp "." args)} =
return $ args >>= (fromMaybe [] . unfoldJoins)
unfoldJoins' I.PExp{I._inPos, I._exp = I.IClaferId{I._sident}} =
return $ [Token (spanToSourcePos _inPos) _sident]
unfoldJoins' _ =
fail "not a join"
uniqNameSpace :: String
uniqNameSpace = "_aux_"
uniqVar :: MonadScope m => m String
uniqVar =
do
c <- supplyNew
return $ uniqNameSpace ++ show (varId c)
testPositive :: MonadScope m => String -> m String
testPositive v =
do
aux <- uniqVar
var aux `leq` var v
var aux `geq` (smallM *^ var v)
var aux `leqTo` 1
setVarKind aux IntVar
return aux
testPositives :: MonadScope m => [String] -> m String
testPositives [v] = testPositive v
testPositives vs =
do
auxs <- mapM testPositive vs
aux <- uniqVar
(length vs *^ var aux) `equal` varSum auxs
a <- uniqVar
(var a ^-^ var aux) `geqTo` (0.9999)
(var a ^-^ var aux) `leqTo` 0.0001
setVarKind a IntVar
return a
smallM :: Double
smallM = 0.0005
data Token = Token {tPos::SourcePos, tLexeme::String} deriving Show
data ParseState = ParseState
{psThis::SClafer,
psStack::[SClafer]
}
deriving Show
type ParseT = ParsecT [Token] ParseState
getThis :: MonadScope m => ParseT m SClafer
getThis =
do
s <- getState
return (psThis s)
putThis :: MonadScope m => SClafer -> ParseT m ()
putThis newThis =
do
state' <- getState
putState $ state'{psThis = newThis}
popStack :: MonadScope m => ParseT m [SClafer]
popStack =
do
state' <- getState
let stack = psStack state'
putState state'{psStack = []}
return stack
pushThis :: MonadScope m => ParseT m ()
pushThis =
do
state' <- getState
putState $ state'{psStack = psThis state' : psStack state'}
_this_ :: MonadScope m => ParseT m String
_this_ = satisfy (== "this")
_parent_ :: MonadScope m => ParseT m String
_parent_ = satisfy (== "parent")
_ref_ :: MonadScope m => ParseT m String
_ref_ = satisfy (== "ref")
_child_ :: MonadScope m => ParseT m String
_child_ = satisfy (not . (`elem` ["this", "parent", "ref"]))
_directChild_ :: MonadScope m => ParseT m String
_directChild_ =
try $ do
curThis <- getThis
clafer <- _child_ >>= lift . claferWithUid
check <- lift $ isDirectChild clafer curThis
when (not check) $ unexpected $ (uid clafer) ++ " is not a direct child of " ++ (uid curThis)
return $ uid clafer
_indirectChild_ :: MonadScope m => ParseT m String
_indirectChild_ =
try $ do
curThis <- getThis
clafer <- _child_ >>= lift . claferWithUid
check <- lift $ isIndirectChild clafer curThis
when (not check) $ unexpected $ (uid clafer) ++ " is not an indirect child of " ++ (uid curThis)
return $ uid clafer
satisfy :: MonadScope m => (String -> Bool) -> ParseT m String
satisfy f = tLexeme <$> tokenPrim (tLexeme)
(\_ c _ -> tPos c)
(\c -> if f $ tLexeme c then Just c else Nothing)
spanToSourcePos :: Span -> SourcePos
spanToSourcePos (Span (Pos l c) _) = (newPos "" (fromInteger l) (fromInteger c))
patternMatch :: MonadScope m => ParseT m a -> ParseState -> [Token] -> m (Either ParseError a)
patternMatch parse' state' =
runParserT (parse' <* eof) state' ""
subexpressions :: I.PExp -> [I.PExp]
subexpressions p@I.PExp{I._exp = exp'} =
p : subexpressions' exp'
where
subexpressions' I.IDeclPExp{I._oDecls, I._bpexp} =
concatMap (subexpressions . I._body) _oDecls ++ subexpressions _bpexp
subexpressions' I.IFunExp{I._exps} = concatMap subexpressions _exps
subexpressions' _ = []
instance MonadSupply s m => MonadSupply s (ListT m) where
supplyNew = lift supplyNew
instance MonadSupply s m => MonadSupply s (MaybeT m) where
supplyNew = lift supplyNew
instance MonadSupply s m => MonadSupply s (ParsecT a b m) where
supplyNew = lift supplyNew