2016-02-04 11:19:08 +03:00
|
|
|
{-# LANGUAGE NoMonomorphismRestriction, FlexibleContexts, TypeFamilies #-}
|
|
|
|
module Translate(
|
2016-02-24 10:14:00 +03:00
|
|
|
translateString,
|
|
|
|
drawingFromDecl,
|
|
|
|
drawingsFromModule
|
2016-02-04 11:19:08 +03:00
|
|
|
) where
|
|
|
|
|
|
|
|
import qualified Diagrams.Prelude as DIA
|
2016-02-05 08:53:21 +03:00
|
|
|
import Diagrams.Prelude((<>))
|
2016-02-04 11:19:08 +03:00
|
|
|
|
2016-02-19 09:51:16 +03:00
|
|
|
import Language.Haskell.Exts(Decl(..), parseDecl, Name(..), Pat(..), Rhs(..),
|
|
|
|
Exp(..), QName(..), fromParseResult, Match(..), QOp(..), GuardedRhs(..),
|
2016-02-24 10:14:00 +03:00
|
|
|
Stmt(..), Binds(..), Alt(..), Module(..))
|
2016-02-19 07:34:08 +03:00
|
|
|
import qualified Language.Haskell.Exts as Exts
|
2016-02-06 08:07:06 +03:00
|
|
|
import Control.Monad.State(State, evalState)
|
2016-02-27 09:58:49 +03:00
|
|
|
import Data.Either(partitionEithers)
|
2016-02-24 07:47:08 +03:00
|
|
|
import Data.List(unzip4, partition)
|
|
|
|
import Control.Monad(replicateM)
|
2016-02-04 11:19:08 +03:00
|
|
|
|
2016-02-27 09:58:49 +03:00
|
|
|
import Types(Drawing(..), NameAndPort(..), IDState,
|
|
|
|
initialIdState)
|
|
|
|
import Util(toNames, makeSimpleEdge, nameAndPort, justName, mapFst)
|
2016-02-04 11:19:08 +03:00
|
|
|
import Icons(Icon(..))
|
2016-02-27 09:58:49 +03:00
|
|
|
import TranslateCore(Reference, IconGraph(..), EvalContext, GraphAndRef,
|
|
|
|
iconGraphFromIcons, iconGraphFromIconsEdges, getUniqueName, combineExpressions,
|
|
|
|
edgesForRefPortList, iconGraphToDrawing, qualifyNameAndPort, makeApplyGraph,
|
|
|
|
namesInPattern, lookupReference, deleteBindings, makeEdges, makeEdgesCore,
|
|
|
|
coerceExpressionResult, makeBox)
|
2016-02-04 11:19:08 +03:00
|
|
|
|
2016-02-27 09:58:49 +03:00
|
|
|
-- OVERVIEW --
|
|
|
|
-- The core functions and data types used in this module are in TranslateCore.
|
|
|
|
-- The TranslateCore also contains most/all of the translation functions that
|
|
|
|
-- do not use Language.Haskell.Exts.
|
2016-02-18 10:14:14 +03:00
|
|
|
|
2016-02-05 08:53:21 +03:00
|
|
|
nameToString :: Language.Haskell.Exts.Name -> String
|
2016-02-04 11:19:08 +03:00
|
|
|
nameToString (Ident s) = s
|
|
|
|
nameToString (Symbol s) = s
|
|
|
|
|
2016-02-25 02:10:06 +03:00
|
|
|
qNameToString :: QName -> String
|
2016-02-27 09:58:49 +03:00
|
|
|
qNameToString (Qual (Exts.ModuleName modName) name) = modName ++ "." ++ nameToString name
|
2016-02-25 02:10:06 +03:00
|
|
|
qNameToString (UnQual name) = nameToString name
|
|
|
|
|
2016-02-23 00:26:47 +03:00
|
|
|
evalPApp :: QName -> [Pat] -> State IDState (IconGraph, NameAndPort)
|
2016-02-25 02:10:06 +03:00
|
|
|
evalPApp name [] = makeBox $ qNameToString name
|
2016-02-23 00:26:47 +03:00
|
|
|
evalPApp name patterns = do
|
|
|
|
patName <- DIA.toName <$> getUniqueName "pat"
|
|
|
|
let
|
|
|
|
context = mempty
|
|
|
|
evaledPatterns <- mapM evalPattern patterns
|
2016-02-27 02:58:50 +03:00
|
|
|
constructorName <- evalQName name context
|
2016-02-23 00:26:47 +03:00
|
|
|
let
|
|
|
|
gr = makeApplyGraph True patName constructorName evaledPatterns (length evaledPatterns)
|
|
|
|
pure gr
|
2016-02-22 07:26:12 +03:00
|
|
|
|
2016-02-23 00:26:47 +03:00
|
|
|
|
2016-02-23 09:01:03 +03:00
|
|
|
evalPLit :: Exts.Sign -> Exts.Literal -> State IDState (IconGraph, NameAndPort)
|
|
|
|
evalPLit Exts.Signless l = evalLit l
|
|
|
|
evalPLit Exts.Negative l = makeBox ('-' : showLiteral l)
|
|
|
|
|
2016-02-23 00:26:47 +03:00
|
|
|
evalPattern :: Pat -> State IDState GraphAndRef
|
2016-02-04 11:19:08 +03:00
|
|
|
evalPattern p = case p of
|
2016-02-23 00:26:47 +03:00
|
|
|
PVar n -> pure (mempty, Left $ nameToString n)
|
2016-02-23 09:01:03 +03:00
|
|
|
PLit s l -> fmap Right <$> evalPLit s l
|
2016-02-23 00:26:47 +03:00
|
|
|
PApp name patterns -> fmap Right <$> evalPApp name patterns
|
2016-02-24 10:14:00 +03:00
|
|
|
-- TODO special tuple handling.
|
2016-02-27 09:58:49 +03:00
|
|
|
PTuple _ patterns -> fmap Right <$> evalPApp (Exts.UnQual $ Ident "(,)") patterns
|
2016-02-23 00:26:47 +03:00
|
|
|
PParen pat -> evalPattern pat
|
2016-02-25 01:46:49 +03:00
|
|
|
PWildCard -> fmap Right <$> makeBox "_"
|
2016-02-04 11:19:08 +03:00
|
|
|
|
2016-02-27 02:58:50 +03:00
|
|
|
--TODO: Consider making this have unique values.
|
|
|
|
evalQName :: QName -> EvalContext -> State IDState (IconGraph, Reference)
|
|
|
|
evalQName (UnQual n) context = do
|
|
|
|
let nameString = nameToString n
|
|
|
|
--graph = iconGraphFromIcons [(DIA.toName nameString, TextBoxIcon nameString)]
|
|
|
|
graph <- makeBox nameString
|
|
|
|
pure $ if nameString `elem` context
|
2016-02-21 06:22:09 +03:00
|
|
|
then (mempty, Left nameString)
|
2016-02-27 02:58:50 +03:00
|
|
|
else fmap Right graph
|
2016-02-25 01:46:49 +03:00
|
|
|
-- TODO remove initialIdState
|
2016-02-27 02:58:50 +03:00
|
|
|
evalQName (Special Exts.UnitCon) _ = pure $ Right <$> evalState (makeBox "()") initialIdState
|
2016-02-04 11:19:08 +03:00
|
|
|
|
2016-02-27 02:58:50 +03:00
|
|
|
evalQOp :: QOp -> EvalContext -> State IDState (IconGraph, Reference)
|
2016-02-19 09:07:38 +03:00
|
|
|
evalQOp (QVarOp n) = evalQName n
|
|
|
|
evalQOp (QConOp n) = evalQName n
|
|
|
|
|
2016-02-19 02:03:31 +03:00
|
|
|
evalApp :: (Exp, [Exp]) -> EvalContext -> State IDState (IconGraph, NameAndPort)
|
2016-02-18 07:59:43 +03:00
|
|
|
evalApp (funExp, argExps) c = do
|
2016-02-10 05:58:28 +03:00
|
|
|
funVal <- evalExp c funExp
|
|
|
|
argVals <- mapM (evalExp c) argExps
|
2016-02-18 10:14:14 +03:00
|
|
|
applyIconName <- DIA.toName <$> getUniqueName "app0"
|
2016-02-23 00:26:47 +03:00
|
|
|
pure $ makeApplyGraph False applyIconName funVal argVals (length argExps)
|
2016-02-19 09:07:38 +03:00
|
|
|
|
|
|
|
evalInfixApp :: EvalContext -> Exp -> QOp -> Exp -> State IDState (IconGraph, NameAndPort)
|
|
|
|
evalInfixApp c e1 op e2 = do
|
|
|
|
argVals <- mapM (evalExp c) [e1, e2]
|
|
|
|
applyIconName <- DIA.toName <$> getUniqueName "app0"
|
2016-02-27 02:58:50 +03:00
|
|
|
funVal <- evalQOp op c
|
2016-02-23 00:26:47 +03:00
|
|
|
pure $ makeApplyGraph False applyIconName funVal argVals 2
|
2016-02-10 05:58:28 +03:00
|
|
|
|
|
|
|
-- TODO add test for this function
|
|
|
|
simplifyApp :: Exp -> (Exp, [Exp])
|
|
|
|
simplifyApp (App exp1 exp2) = (funExp, args <> [exp2])
|
|
|
|
where
|
|
|
|
(funExp, args) = simplifyApp exp1
|
|
|
|
simplifyApp e = (e, [])
|
2016-02-06 08:07:06 +03:00
|
|
|
|
2016-02-18 10:14:14 +03:00
|
|
|
evalIf :: EvalContext -> Exp -> Exp -> Exp -> State IDState (IconGraph, NameAndPort)
|
|
|
|
evalIf c e1 e2 e3 = do
|
|
|
|
e1Val <- evalExp c e1
|
|
|
|
e2Val <- evalExp c e2
|
|
|
|
e3Val <- evalExp c e3
|
|
|
|
guardName <- DIA.toName <$> getUniqueName "if"
|
|
|
|
let
|
|
|
|
icons = [(guardName, GuardIcon 2)]
|
|
|
|
combinedGraph =
|
2016-02-23 00:26:47 +03:00
|
|
|
combineExpressions False $ zip [e1Val, e2Val, e3Val] (map (nameAndPort guardName) [3, 2, 4])
|
2016-02-21 07:15:40 +03:00
|
|
|
newGraph = iconGraphFromIcons icons <> combinedGraph
|
2016-02-18 10:14:14 +03:00
|
|
|
pure (newGraph, NameAndPort guardName (Just 0))
|
2016-02-18 02:36:57 +03:00
|
|
|
|
2016-02-21 06:22:09 +03:00
|
|
|
evalStmt :: EvalContext -> Stmt -> State IDState GraphAndRef
|
2016-02-19 09:51:16 +03:00
|
|
|
evalStmt c (Qualifier e) = evalExp c e
|
|
|
|
|
2016-02-21 06:22:09 +03:00
|
|
|
evalStmts :: EvalContext -> [Stmt] -> State IDState GraphAndRef
|
2016-02-19 09:51:16 +03:00
|
|
|
evalStmts c [stmt] = evalStmt c stmt
|
|
|
|
|
2016-02-21 06:22:09 +03:00
|
|
|
evalGuaredRhs :: EvalContext -> GuardedRhs -> State IDState (GraphAndRef, GraphAndRef)
|
2016-02-19 09:51:16 +03:00
|
|
|
evalGuaredRhs c (GuardedRhs _ stmts e) = do
|
|
|
|
expVal <- evalExp c e
|
|
|
|
stmtsVal <- evalStmts c stmts
|
|
|
|
pure (stmtsVal, expVal)
|
|
|
|
|
|
|
|
evalGuardedRhss :: EvalContext -> [GuardedRhs] -> State IDState (IconGraph, NameAndPort)
|
|
|
|
evalGuardedRhss c rhss = do
|
|
|
|
guardName <- DIA.toName <$> getUniqueName "guard"
|
|
|
|
evaledRhss <- mapM (evalGuaredRhs c) rhss
|
|
|
|
let
|
|
|
|
(bools, exps) = unzip evaledRhss
|
|
|
|
expsWithPorts = zip exps $ map (nameAndPort guardName) [2,4..]
|
|
|
|
boolsWithPorts = zip bools $ map (nameAndPort guardName) [3,5..]
|
2016-02-23 00:26:47 +03:00
|
|
|
combindedGraph = combineExpressions False $ expsWithPorts <> boolsWithPorts
|
2016-02-19 09:51:16 +03:00
|
|
|
icons = [(guardName, GuardIcon (length rhss))]
|
2016-02-21 07:15:40 +03:00
|
|
|
newGraph = iconGraphFromIcons icons <> combindedGraph
|
2016-02-26 04:10:12 +03:00
|
|
|
pure (newGraph, NameAndPort guardName (Just 1))
|
2016-02-19 09:51:16 +03:00
|
|
|
|
2016-02-27 09:58:49 +03:00
|
|
|
-- This is in Translate and not Translate core since currently it is only used by evalLit.
|
2016-02-23 09:01:03 +03:00
|
|
|
makeLiteral :: (Show x) => x -> State IDState (IconGraph, NameAndPort)
|
|
|
|
makeLiteral = makeBox. show
|
|
|
|
|
2016-02-20 00:46:14 +03:00
|
|
|
evalLit :: Exts.Literal -> State IDState (IconGraph, NameAndPort)
|
|
|
|
evalLit (Exts.Int x) = makeLiteral x
|
|
|
|
evalLit (Exts.Char x) = makeLiteral x
|
|
|
|
evalLit (Exts.String x) = makeLiteral x
|
|
|
|
-- TODO: Print the Rational as a floating point.
|
|
|
|
evalLit (Exts.Frac x) = makeLiteral x
|
|
|
|
-- TODO: Test the unboxed literals
|
|
|
|
evalLit (Exts.PrimInt x) = makeLiteral x
|
|
|
|
evalLit (Exts.PrimWord x) = makeLiteral x
|
|
|
|
evalLit (Exts.PrimFloat x) = makeLiteral x
|
|
|
|
evalLit (Exts.PrimDouble x) = makeLiteral x
|
|
|
|
evalLit (Exts.PrimChar x) = makeLiteral x
|
|
|
|
evalLit (Exts.PrimString x) = makeLiteral x
|
|
|
|
|
2016-02-23 09:01:03 +03:00
|
|
|
showLiteral :: Exts.Literal -> String
|
|
|
|
showLiteral (Exts.Int x) = show x
|
|
|
|
showLiteral (Exts.Char x) = show x
|
|
|
|
showLiteral (Exts.String x) = show x
|
|
|
|
-- TODO: Print the Rational as a floating point.
|
|
|
|
showLiteral (Exts.Frac x) = show x
|
|
|
|
-- TODO: Test the unboxed literals
|
|
|
|
showLiteral (Exts.PrimInt x) = show x
|
|
|
|
showLiteral (Exts.PrimWord x) = show x
|
|
|
|
showLiteral (Exts.PrimFloat x) = show x
|
|
|
|
showLiteral (Exts.PrimDouble x) = show x
|
|
|
|
showLiteral (Exts.PrimChar x) = show x
|
|
|
|
showLiteral (Exts.PrimString x) = show x
|
|
|
|
|
2016-02-22 07:26:12 +03:00
|
|
|
getBoundVarName :: Decl -> [String]
|
2016-02-23 00:26:47 +03:00
|
|
|
-- TODO Should evalState be used here?
|
|
|
|
getBoundVarName (PatBind _ pat _ _) = namesInPattern $ evalState (evalPattern pat) initialIdState
|
2016-02-25 01:46:49 +03:00
|
|
|
getBoundVarName (FunBind (Match _ name _ _ _ _:_)) = [nameToString name]
|
2016-02-21 05:47:56 +03:00
|
|
|
|
2016-02-22 02:15:16 +03:00
|
|
|
--TODO: Should this call makeEdges?
|
2016-02-21 09:35:13 +03:00
|
|
|
evalBinds :: EvalContext -> Binds -> State IDState (IconGraph, EvalContext)
|
2016-02-21 05:47:56 +03:00
|
|
|
evalBinds c (BDecls decls) = do
|
|
|
|
let
|
2016-02-22 07:26:12 +03:00
|
|
|
boundNames = concatMap getBoundVarName decls
|
2016-02-21 05:47:56 +03:00
|
|
|
augmentedContext = boundNames <> c
|
2016-02-21 09:35:13 +03:00
|
|
|
evaledDecl <- mconcat <$> mapM (evalDecl augmentedContext) decls
|
|
|
|
pure (evaledDecl, augmentedContext)
|
2016-02-21 05:47:56 +03:00
|
|
|
|
2016-02-22 06:34:33 +03:00
|
|
|
evalGeneralLet :: (EvalContext -> State IDState (IconGraph, Reference)) -> EvalContext -> Binds -> State IDState (IconGraph, Reference)
|
|
|
|
evalGeneralLet expOrRhsEvaler c bs = do
|
2016-02-21 09:35:13 +03:00
|
|
|
(bindGraph, bindContext) <- evalBinds c bs
|
2016-02-22 06:34:33 +03:00
|
|
|
expVal <- expOrRhsEvaler bindContext
|
2016-02-21 05:47:56 +03:00
|
|
|
let
|
2016-02-21 09:35:13 +03:00
|
|
|
(expGraph, expResult) = expVal
|
2016-02-22 02:15:16 +03:00
|
|
|
newGraph = deleteBindings . makeEdges $ expGraph <> bindGraph
|
|
|
|
(IconGraph _ _ _ _ bindings) = bindGraph
|
2016-02-23 09:01:03 +03:00
|
|
|
pure (newGraph, lookupReference bindings expResult)
|
2016-02-20 00:46:14 +03:00
|
|
|
|
2016-02-22 06:34:33 +03:00
|
|
|
evalLet :: EvalContext -> Binds -> Exp -> State IDState (IconGraph, Reference)
|
|
|
|
evalLet context binds e = evalGeneralLet (`evalExp` e) context binds
|
|
|
|
|
2016-02-24 07:47:08 +03:00
|
|
|
-- TODO: Refactor this with evalPatBind
|
|
|
|
evalPatAndRhs :: EvalContext -> Pat -> Rhs -> Maybe Binds -> State IDState (Bool, IconGraph, Reference, NameAndPort)
|
|
|
|
evalPatAndRhs c pat rhs maybeWhereBinds = do
|
|
|
|
patternNames <- namesInPattern <$> evalPattern pat
|
|
|
|
let rhsContext = patternNames <> c
|
|
|
|
-- TODO: remove coerceExpressionResult
|
2016-02-25 01:46:49 +03:00
|
|
|
(rhsGraph, rhsRef) <- rhsWithBinds maybeWhereBinds rhs rhsContext >>= coerceExpressionResult
|
2016-02-24 07:47:08 +03:00
|
|
|
(patGraph, patRef) <- evalPattern pat
|
|
|
|
let
|
|
|
|
grWithEdges = makeEdges (rhsGraph <> patGraph)
|
|
|
|
-- The pattern and rhs are conneted if makeEdges added extra edges.
|
|
|
|
patRhsAreConnected =
|
|
|
|
length (igEdges grWithEdges) > (length (igEdges rhsGraph) + length (igEdges patGraph))
|
|
|
|
pure (patRhsAreConnected, deleteBindings grWithEdges, patRef, rhsRef)
|
|
|
|
|
|
|
|
-- returns (combined graph, pattern reference, rhs reference)
|
|
|
|
evalAlt :: EvalContext -> Exts.Alt -> State IDState (Bool, IconGraph, Reference, NameAndPort)
|
2016-02-27 09:58:49 +03:00
|
|
|
evalAlt c (Exts.Alt _ pat rhs maybeBinds) = evalPatAndRhs c pat rhs maybeBinds
|
2016-02-24 07:47:08 +03:00
|
|
|
|
|
|
|
evalCase :: EvalContext -> Exp -> [Alt] -> State IDState (IconGraph, NameAndPort)
|
|
|
|
evalCase c e alts = do
|
|
|
|
evaledAlts <- mapM (evalAlt c) alts
|
|
|
|
(expGraph, expRef) <- evalExp c e
|
|
|
|
caseIconName <- getUniqueName "case"
|
|
|
|
let
|
|
|
|
(patRhsConnected, altGraphs, patRefs, rhsRefs) = unzip4 evaledAlts
|
|
|
|
combindedAltGraph = mconcat altGraphs
|
|
|
|
numAlts = length alts
|
|
|
|
icons = toNames [(caseIconName, CaseIcon numAlts)]
|
2016-02-24 10:14:00 +03:00
|
|
|
caseGraph = iconGraphFromIcons icons
|
2016-02-24 07:47:08 +03:00
|
|
|
expEdge = (expRef, nameAndPort caseIconName 0)
|
|
|
|
patEdges = zip patRefs $ map (nameAndPort caseIconName ) [2,4..]
|
|
|
|
rhsEdges = zip patRhsConnected $ zip rhsRefs $ map (nameAndPort caseIconName) [3,5..]
|
|
|
|
(connectedRhss, unConnectedRhss) = partition fst rhsEdges
|
|
|
|
resultIconNames <- replicateM numAlts (getUniqueName "caseResult")
|
|
|
|
let
|
|
|
|
makeCaseResult resultIconName rhsPort = iconGraphFromIconsEdges rhsNewIcons rhsNewEdges
|
|
|
|
where
|
|
|
|
rhsNewIcons = toNames [(resultIconName, CaseResultIcon)]
|
2016-02-26 05:37:04 +03:00
|
|
|
rhsNewEdges = [makeSimpleEdge (rhsPort, justName resultIconName)]
|
2016-02-24 07:47:08 +03:00
|
|
|
caseResultGraphs = mconcat $ zipWith makeCaseResult resultIconNames (fmap (fst . snd) connectedRhss)
|
|
|
|
filteredRhsEdges = mapFst Right $ fmap snd unConnectedRhss
|
2016-02-26 05:37:04 +03:00
|
|
|
patternEdgesGraph = edgesForRefPortList True patEdges
|
|
|
|
caseEdgeGraph = edgesForRefPortList False (expEdge : filteredRhsEdges)
|
|
|
|
finalGraph = mconcat [patternEdgesGraph, caseResultGraphs, expGraph, caseEdgeGraph, caseGraph, combindedAltGraph]
|
2016-02-24 07:47:08 +03:00
|
|
|
pure (finalGraph, nameAndPort caseIconName 1)
|
|
|
|
|
2016-02-24 10:14:00 +03:00
|
|
|
evalTuple :: EvalContext -> [Exp] -> State IDState (IconGraph, NameAndPort)
|
|
|
|
evalTuple c exps = do
|
|
|
|
argVals <- mapM (evalExp c) exps
|
|
|
|
funVal <- makeBox "(,)"
|
|
|
|
applyIconName <- DIA.toName <$> getUniqueName "tupleApp"
|
|
|
|
pure $ makeApplyGraph False applyIconName (fmap Right funVal) argVals (length exps)
|
|
|
|
|
2016-02-21 06:22:09 +03:00
|
|
|
evalExp :: EvalContext -> Exp -> State IDState (IconGraph, Reference)
|
2016-02-10 05:58:28 +03:00
|
|
|
evalExp c x = case x of
|
2016-02-27 02:58:50 +03:00
|
|
|
Var n -> evalQName n c
|
|
|
|
Con n -> evalQName n c
|
2016-02-21 06:22:09 +03:00
|
|
|
Lit l -> fmap Right <$> evalLit l
|
|
|
|
InfixApp e1 op e2 -> fmap Right <$> evalInfixApp c e1 op e2
|
|
|
|
e@App{} -> fmap Right <$> evalApp (simplifyApp e) c
|
|
|
|
Lambda _ patterns e -> fmap Right <$> evalLambda c patterns e
|
2016-02-21 09:35:13 +03:00
|
|
|
Let bs e -> evalLet c bs e
|
2016-02-21 06:22:09 +03:00
|
|
|
If e1 e2 e3 -> fmap Right <$> evalIf c e1 e2 e3
|
2016-02-24 07:47:08 +03:00
|
|
|
Case e alts -> fmap Right <$> evalCase c e alts
|
2016-02-24 10:14:00 +03:00
|
|
|
-- TODO special tuple symbol
|
|
|
|
Tuple _ exps -> fmap Right <$> evalTuple c exps
|
2016-02-21 05:47:56 +03:00
|
|
|
Paren e -> evalExp c e
|
2016-02-04 11:19:08 +03:00
|
|
|
|
2016-02-08 05:01:57 +03:00
|
|
|
-- | First argument is the right hand side.
|
|
|
|
-- The second arugement is a list of strings that are bound in the environment.
|
2016-02-23 09:01:03 +03:00
|
|
|
evalRhs :: EvalContext -> Rhs -> State IDState (IconGraph, Reference)
|
|
|
|
evalRhs c (UnGuardedRhs e) = evalExp c e
|
|
|
|
evalRhs c (GuardedRhss rhss) = fmap Right <$> evalGuardedRhss c rhss
|
|
|
|
|
|
|
|
rhsWithBinds :: Maybe Binds -> Rhs -> EvalContext -> State IDState (IconGraph, Reference)
|
|
|
|
rhsWithBinds maybeWhereBinds rhs rhsContext = case maybeWhereBinds of
|
|
|
|
Nothing -> evalRhs rhsContext rhs
|
|
|
|
Just b -> evalGeneralLet (`evalRhs` rhs) rhsContext b
|
2016-02-04 11:19:08 +03:00
|
|
|
|
2016-02-21 05:47:56 +03:00
|
|
|
evalPatBind :: EvalContext -> Decl -> State IDState IconGraph
|
2016-02-23 00:26:47 +03:00
|
|
|
evalPatBind c (PatBind _ pat rhs maybeWhereBinds) = do
|
2016-02-23 09:01:03 +03:00
|
|
|
patternNames <- namesInPattern <$> evalPattern pat
|
|
|
|
let rhsContext = patternNames <> c
|
|
|
|
(rhsGraph, rhsRef) <- rhsWithBinds maybeWhereBinds rhs rhsContext
|
2016-02-23 00:26:47 +03:00
|
|
|
(patGraph, patRef) <- evalPattern pat
|
|
|
|
let
|
|
|
|
(newEdges, newSinks, bindings) = case patRef of
|
|
|
|
(Left s) -> (mempty, mempty, [(s, rhsRef)])
|
|
|
|
(Right patPort) -> case rhsRef of
|
2016-02-26 05:37:04 +03:00
|
|
|
-- TODO This edge/sink should have a special arrow head to indicate an input to a pattern.
|
2016-02-23 00:26:47 +03:00
|
|
|
(Left rhsStr) -> (mempty, [(rhsStr, patPort)], mempty)
|
2016-02-26 05:37:04 +03:00
|
|
|
(Right rhsPort) -> ([makeSimpleEdge (rhsPort, patPort)], mempty, mempty)
|
2016-02-23 00:26:47 +03:00
|
|
|
gr = IconGraph mempty newEdges mempty newSinks bindings
|
2016-02-23 09:01:03 +03:00
|
|
|
pure . makeEdges $ (gr <> rhsGraph <> patGraph)
|
2016-02-22 06:34:33 +03:00
|
|
|
|
2016-02-23 09:01:03 +03:00
|
|
|
generalEvalLambda :: EvalContext -> [Pat] -> (EvalContext -> State IDState GraphAndRef) -> State IDState (IconGraph, NameAndPort)
|
|
|
|
generalEvalLambda context patterns rhsEvalFun = do
|
2016-02-23 03:13:53 +03:00
|
|
|
lambdaName <- getUniqueName "lam"
|
|
|
|
patternVals <- mapM evalPattern patterns
|
|
|
|
let
|
|
|
|
patternStrings = concatMap namesInPattern patternVals
|
2016-02-23 09:01:03 +03:00
|
|
|
rhsContext = patternStrings <> context
|
2016-02-23 03:13:53 +03:00
|
|
|
lambdaPorts = map (nameAndPort lambdaName) [0,1..]
|
|
|
|
patternGraph = mconcat $ map fst patternVals
|
|
|
|
|
|
|
|
(patternEdgeGraphs, rawNewBinds) =
|
|
|
|
partitionEithers $ zipWith (makePatternEdges lambdaName) patternVals lambdaPorts
|
|
|
|
patternEdgeGraph = mconcat patternEdgeGraphs
|
|
|
|
|
2016-02-23 09:01:03 +03:00
|
|
|
newBinds = rawNewBinds
|
2016-02-23 03:13:53 +03:00
|
|
|
numParameters = length patterns
|
|
|
|
-- TODO remove coerceExpressionResult here
|
2016-02-25 01:46:49 +03:00
|
|
|
(rhsRawGraph, rhsResult) <- rhsEvalFun rhsContext >>= coerceExpressionResult
|
2016-02-23 03:13:53 +03:00
|
|
|
resultIconName <- getUniqueName "res"
|
|
|
|
rhsDrawingName <- DIA.toName <$> getUniqueName "rhsDraw"
|
|
|
|
let
|
|
|
|
rhsAndPatternGraph@(IconGraph _ _ _ sinks _) = makeEdges $ patternGraph <> rhsRawGraph
|
|
|
|
qualifiedSinks = fmap (fmap (qualifyNameAndPort lambdaName)) sinks
|
2016-02-23 09:01:03 +03:00
|
|
|
(newSinks, internalEdges) = makeEdgesCore qualifiedSinks newBinds
|
2016-02-23 03:13:53 +03:00
|
|
|
rhsDrawing = makeRhsDrawing resultIconName (rhsAndPatternGraph, rhsResult)
|
|
|
|
icons = toNames [(lambdaName, LambdaRegionIcon numParameters rhsDrawingName)]
|
|
|
|
finalGraph = IconGraph icons internalEdges [(rhsDrawingName, rhsDrawing)]
|
2016-02-23 09:01:03 +03:00
|
|
|
newSinks mempty
|
|
|
|
pure (patternEdgeGraph <> finalGraph, justName lambdaName)
|
2016-02-27 09:58:49 +03:00
|
|
|
where
|
|
|
|
makeRhsDrawing :: DIA.IsName a => a -> (IconGraph, NameAndPort) -> Drawing
|
|
|
|
makeRhsDrawing resultIconName (rhsGraph, rhsResult)= rhsDrawing where
|
|
|
|
rhsNewIcons = toNames [(resultIconName, ResultIcon)]
|
|
|
|
rhsNewEdges = [makeSimpleEdge (rhsResult, justName resultIconName)]
|
|
|
|
rhsGraphWithResult = rhsGraph <> iconGraphFromIconsEdges rhsNewIcons rhsNewEdges
|
|
|
|
rhsDrawing = iconGraphToDrawing rhsGraphWithResult
|
|
|
|
|
|
|
|
-- TODO Like evalPatBind, this edge should have an indicator that it is the input to a pattern.
|
|
|
|
makePatternEdges :: String -> GraphAndRef -> NameAndPort -> Either IconGraph (String, Reference)
|
|
|
|
makePatternEdges lambdaName (_, Right patPort) lamPort =
|
|
|
|
Left $ iconGraphFromIconsEdges mempty
|
|
|
|
[makeSimpleEdge (lamPort, qualifyNameAndPort lambdaName patPort)]
|
|
|
|
makePatternEdges _ (_, Left str) lamPort = Right (str, Right lamPort)
|
|
|
|
|
2016-02-23 09:01:03 +03:00
|
|
|
|
|
|
|
evalLambda :: EvalContext -> [Pat] -> Exp -> State IDState (IconGraph, NameAndPort)
|
|
|
|
evalLambda c patterns e = generalEvalLambda c patterns (`evalExp` e)
|
2016-02-23 02:45:53 +03:00
|
|
|
|
2016-02-23 09:01:03 +03:00
|
|
|
evalMatch :: EvalContext -> Match -> State IDState IconGraph
|
|
|
|
evalMatch c (Match _ name patterns _ rhs maybeWhereBinds) = do
|
|
|
|
let
|
|
|
|
matchFunNameString = nameToString name
|
|
|
|
newContext = matchFunNameString : c
|
|
|
|
(lambdaGraph, lambdaPort) <-
|
|
|
|
generalEvalLambda newContext patterns (rhsWithBinds maybeWhereBinds rhs)
|
|
|
|
let
|
|
|
|
newBinding = IconGraph mempty mempty mempty mempty [(matchFunNameString, Right lambdaPort)]
|
|
|
|
pure $ makeEdges (newBinding <> lambdaGraph)
|
2016-02-23 02:45:53 +03:00
|
|
|
|
2016-02-27 09:58:49 +03:00
|
|
|
|
2016-02-27 02:58:50 +03:00
|
|
|
matchesToCase :: Match -> [Match] -> State IDState Match
|
|
|
|
matchesToCase match [] = pure match
|
|
|
|
matchesToCase firstMatch@(Match srcLoc funName pats mType _ _) restOfMatches = do
|
2016-02-25 01:46:49 +03:00
|
|
|
tempStrings <- replicateM (length pats) (getUniqueName "_tempvar")
|
|
|
|
let
|
|
|
|
tempPats = fmap (PVar . Ident) tempStrings
|
|
|
|
tempVars = fmap (Var . UnQual . Ident) tempStrings
|
|
|
|
tuple = Tuple Exts.Boxed tempVars
|
2016-02-27 02:58:50 +03:00
|
|
|
caseExp = case tempVars of
|
2016-02-27 09:58:49 +03:00
|
|
|
[oneTempVar] -> Case oneTempVar alts
|
2016-02-27 02:58:50 +03:00
|
|
|
_ -> Case tuple alts
|
2016-02-25 01:46:49 +03:00
|
|
|
rhs = UnGuardedRhs caseExp
|
|
|
|
match = Match srcLoc funName tempPats mType rhs Nothing
|
|
|
|
pure match
|
2016-02-27 09:58:49 +03:00
|
|
|
where
|
|
|
|
allMatches = firstMatch:restOfMatches
|
|
|
|
alts = fmap matchToAlt allMatches
|
|
|
|
matchToAlt :: Match -> Alt
|
|
|
|
matchToAlt (Match srcLocation _ mtaPats _ rhs binds) = Alt srcLocation altPattern rhs binds where
|
|
|
|
altPattern = case mtaPats of
|
|
|
|
[onePat] -> onePat
|
|
|
|
_ -> PTuple Exts.Boxed pats
|
|
|
|
|
2016-02-25 01:46:49 +03:00
|
|
|
|
2016-02-21 05:47:56 +03:00
|
|
|
evalMatches :: EvalContext -> [Match] -> State IDState IconGraph
|
2016-02-22 02:15:16 +03:00
|
|
|
evalMatches _ [] = pure mempty
|
2016-02-27 02:58:50 +03:00
|
|
|
evalMatches c (firstMatch:restOfMatches) = matchesToCase firstMatch restOfMatches >>= evalMatch c
|
2016-02-04 11:19:08 +03:00
|
|
|
|
2016-02-21 05:47:56 +03:00
|
|
|
evalDecl :: EvalContext -> Decl -> State IDState IconGraph
|
|
|
|
evalDecl c d = evaluatedDecl where
|
2016-02-18 07:59:43 +03:00
|
|
|
evaluatedDecl = case d of
|
2016-02-21 05:47:56 +03:00
|
|
|
pat@PatBind{} -> evalPatBind c pat
|
|
|
|
FunBind matches -> evalMatches c matches
|
2016-02-24 10:14:00 +03:00
|
|
|
--TODO: Add other cases here
|
|
|
|
_ -> pure mempty
|
2016-02-21 08:26:25 +03:00
|
|
|
|
2016-02-21 05:47:56 +03:00
|
|
|
drawingFromDecl :: Decl -> Drawing
|
|
|
|
drawingFromDecl d = iconGraphToDrawing $ evalState evaluatedDecl initialIdState
|
2016-02-27 09:58:49 +03:00
|
|
|
where
|
|
|
|
evaluatedDecl = evalDecl mempty d >>= showTopLevelBinds
|
|
|
|
showTopLevelBinds :: IconGraph -> State IDState IconGraph
|
|
|
|
showTopLevelBinds gr@(IconGraph _ _ _ _ binds) = do
|
|
|
|
let
|
|
|
|
addBind (_, Left _) = pure mempty
|
|
|
|
addBind (patName, Right port) = do
|
|
|
|
uniquePatName <- getUniqueName patName
|
|
|
|
let
|
|
|
|
icons = toNames [(uniquePatName, TextBoxIcon patName)]
|
|
|
|
edges = [makeSimpleEdge (justName uniquePatName, port)]
|
|
|
|
edgeGraph = iconGraphFromIconsEdges icons edges
|
|
|
|
pure edgeGraph
|
|
|
|
newGraph <- mconcat <$> mapM addBind binds
|
|
|
|
pure $ newGraph <> gr
|
|
|
|
|
|
|
|
-- Profiling: about 1.5% of total time.
|
2016-02-04 11:19:08 +03:00
|
|
|
translateString :: String -> (Drawing, Decl)
|
|
|
|
translateString s = (drawing, decl) where
|
|
|
|
parseResult = parseDecl s -- :: ParseResult Module
|
|
|
|
decl = fromParseResult parseResult
|
2016-02-21 05:47:56 +03:00
|
|
|
drawing = drawingFromDecl decl
|
2016-02-24 10:14:00 +03:00
|
|
|
|
|
|
|
drawingsFromModule :: Module -> [Drawing]
|
|
|
|
drawingsFromModule (Module _ _ _ _ _ _ decls) = fmap drawingFromDecl decls
|