glance/app/Translate.hs

517 lines
22 KiB
Haskell
Raw Normal View History

{-# LANGUAGE NoMonomorphismRestriction, FlexibleContexts, TypeFamilies #-}
module Translate(
2016-02-24 10:14:00 +03:00
translateString,
drawingFromDecl,
drawingsFromModule,
stringToSyntaxGraph
) where
import Diagrams.Prelude((<>))
2016-11-28 04:25:30 +03:00
import Control.Monad(replicateM)
2016-02-06 08:07:06 +03:00
import Control.Monad.State(State, evalState)
import Data.Either(partitionEithers)
2016-02-24 07:47:08 +03:00
import Data.List(unzip4, partition)
2016-11-28 04:25:30 +03:00
import qualified Language.Haskell.Exts as Exts
import Language.Haskell.Exts(Decl(..), parseDecl, Name(..), Pat(..), Rhs(..),
Exp(..), QName(..), fromParseResult, Match(..), QOp(..), GuardedRhs(..),
Stmt(..), Binds(..), Alt(..), Module(..), SpecialCon(..))
import qualified Data.Graph.Inductive.PatriciaTree as FGR
--import Data.Maybe(catMaybes)
2016-11-28 04:25:30 +03:00
import GraphAlgorithms(collapseNodes)
import TranslateCore(Reference, SyntaxGraph(..), EvalContext, GraphAndRef,
syntaxGraphFromNodes, syntaxGraphFromNodesEdges, getUniqueName, combineExpressions,
2016-11-22 00:57:53 +03:00
edgesForRefPortList, makeApplyGraph,
2016-03-28 02:49:58 +03:00
namesInPattern, lookupReference, deleteBindings, makeEdges,
2016-11-28 04:25:30 +03:00
coerceExpressionResult, makeBox, nTupleString, nListString,
syntaxGraphToFglGraph, getUniqueString)
import Types(NameAndPort(..), IDState,
initialIdState, Edge, SyntaxNode(..), IngSyntaxGraph, NodeName, Port(..))
import Util(makeSimpleEdge, nameAndPort, justName, mapFst)
-- 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
nameToString :: Language.Haskell.Exts.Name -> String
nameToString (Ident s) = s
nameToString (Symbol s) = s
qNameToString :: QName -> String
qNameToString (Qual (Exts.ModuleName modName) name) = modName ++ "." ++ nameToString name
qNameToString (UnQual name) = nameToString name
2016-03-05 11:12:55 +03:00
qNameToString (Special UnitCon) = "()"
qNameToString (Special ListCon) = "[]"
qNameToString (Special FunCon) = "(->)"
qNameToString (Special (TupleCon _ n)) = nTupleString n
qNameToString (Special Cons) = "(:)"
-- unboxed singleton tuple constructor
qNameToString (Special UnboxedSingleCon) = "(# #)"
evalPApp :: QName -> [Pat] -> State IDState (SyntaxGraph, NameAndPort)
evalPApp name [] = makeBox $ qNameToString name
evalPApp name patterns = do
patName <- getUniqueName "pat"
evaledPatterns <- mapM evalPattern patterns
let
2016-03-22 03:36:02 +03:00
constructorName = qNameToString name
gr = makePatternGraph patName constructorName evaledPatterns (length evaledPatterns)
pure gr
evalPLit :: Exts.Sign -> Exts.Literal -> State IDState (SyntaxGraph, NameAndPort)
evalPLit Exts.Signless l = evalLit l
evalPLit Exts.Negative l = makeBox ('-' : showLiteral l)
2016-03-05 00:24:09 +03:00
evalPAsPat :: Name -> Pat -> State IDState GraphAndRef
evalPAsPat n p = do
(evaledPatGraph, evaledPatRef) <- evalPattern p
let
newBind = [(nameToString n, evaledPatRef)]
2016-12-07 05:39:38 +03:00
newGraph = SyntaxGraph mempty mempty mempty newBind mempty
2016-03-05 00:24:09 +03:00
pure (newGraph <> evaledPatGraph, evaledPatRef)
evalPattern :: Pat -> State IDState GraphAndRef
evalPattern p = case p of
PVar n -> pure (mempty, Left $ nameToString n)
PLit s l -> fmap Right <$> evalPLit s l
PInfixApp p1 qName p2 -> evalPattern (PApp qName [p1, p2])
PApp name patterns -> fmap Right <$> evalPApp name patterns
2016-02-24 10:14:00 +03:00
-- TODO special tuple handling.
PTuple _ patterns ->
fmap Right <$> evalPApp (Exts.UnQual . Ident . nTupleString . length $ patterns) patterns
PList patterns ->
fmap Right <$> evalPApp (Exts.UnQual . Ident . nListString . length $ patterns) patterns
PParen pat -> evalPattern pat
2016-03-05 00:24:09 +03:00
PAsPat n subPat -> evalPAsPat n subPat
2016-02-25 01:46:49 +03:00
PWildCard -> fmap Right <$> makeBox "_"
2016-03-05 00:24:09 +03:00
_ -> error $ "evalPattern: No pattern in case for " ++ show p
-- TODO: Other cases
2016-03-05 05:49:02 +03:00
-- strToGraphRef is not in TranslateCore, since it is only used by evalQName.
strToGraphRef :: EvalContext -> String -> State IDState (SyntaxGraph, Reference)
2016-03-05 05:49:02 +03:00
strToGraphRef c str = fmap mapper (makeBox str) where
mapper gr = if str `elem` c
then (mempty, Left str)
else fmap Right gr
evalQName :: QName -> EvalContext -> State IDState (SyntaxGraph, Reference)
2016-03-05 05:49:02 +03:00
evalQName qName@(UnQual _) c = strToGraphRef c (qNameToString qName)
evalQName qName@(Qual _ _) c = strToGraphRef c (qNameToString qName)
2016-03-05 11:12:55 +03:00
evalQName qName _ = fmap Right <$> makeBox (qNameToString qName)
-- evalQOp :: QOp -> EvalContext -> State IDState (SyntaxGraph, Reference)
2016-03-28 02:49:58 +03:00
-- evalQOp (QVarOp n) = evalQName n
-- evalQOp (QConOp n) = evalQName n
2016-02-19 09:07:38 +03:00
-- qOpToString :: QOp -> String
-- qOpToString (QVarOp n) = qNameToString n
-- qOpToString (QConOp n) = qNameToString n
--findReferencedIcon :: Reference -> [(NodeName, Icon)] -> Maybe (Name, Icon)
-- findReferencedIcon :: Either t NameAndPort -> [(NodeName, t1)] -> Maybe (NodeName, t1)
-- findReferencedIcon (Left str) _ = Nothing
-- findReferencedIcon (Right (NameAndPort name _)) nameIconMap = (\x -> (name, x)) <$> lookup name nameIconMap
makePatternGraph :: NodeName -> String -> [(SyntaxGraph, Reference)] -> Int -> (SyntaxGraph, NameAndPort)
makePatternGraph applyIconName funStr argVals numArgs = (newGraph <> combinedGraph, nameAndPort applyIconName (Port 1))
where
argumentPorts = map (nameAndPort applyIconName . Port) [2,3..]
combinedGraph = combineExpressions True $ zip argVals argumentPorts
icons = [(applyIconName, PatternApplyNode funStr numArgs)]
newGraph = syntaxGraphFromNodes icons
evalApp :: EvalContext -> (Exp, [Exp]) -> State IDState (SyntaxGraph, NameAndPort)
2016-11-28 04:25:30 +03:00
evalApp c (funExp, argExps) = do
2016-02-10 05:58:28 +03:00
funVal <- evalExp c funExp
argVals <- mapM (evalExp c) argExps
applyIconName <- getUniqueName "app0"
pure $ makeApplyGraph False applyIconName funVal argVals (length argExps)
2016-02-19 09:07:38 +03:00
2016-03-05 08:35:23 +03:00
qOpToExp :: QOp -> Exp
qOpToExp (QVarOp n) = Var n
qOpToExp (QConOp n) = Con n
evalInfixApp :: EvalContext -> Exp -> QOp -> Exp -> State IDState (SyntaxGraph, Reference)
2016-04-10 04:59:40 +03:00
evalInfixApp c e1 (QVarOp (UnQual (Symbol "$"))) e2 = evalExp c (App e1 e2)
evalInfixApp c e1 op e2 = fmap Right <$> evalApp c (qOpToExp op, [e1, e2])
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
evalIf :: EvalContext -> Exp -> Exp -> Exp -> State IDState (SyntaxGraph, NameAndPort)
2016-02-18 10:14:14 +03:00
evalIf c e1 e2 e3 = do
e1Val <- evalExp c e1
e2Val <- evalExp c e2
e3Val <- evalExp c e3
guardName <- getUniqueName "if"
2016-02-18 10:14:14 +03:00
let
icons = [(guardName, GuardNode 2)]
2016-02-18 10:14:14 +03:00
combinedGraph =
combineExpressions False $ zip [e1Val, e2Val, e3Val] (map (nameAndPort guardName . Port) [3, 2, 4])
newGraph = syntaxGraphFromNodes icons <> combinedGraph
pure (newGraph, nameAndPort guardName (Port 0))
2016-02-18 02:36:57 +03:00
evalStmt :: EvalContext -> Stmt -> State IDState GraphAndRef
2016-02-19 09:51:16 +03:00
evalStmt c (Qualifier e) = evalExp c e
evalStmts :: EvalContext -> [Stmt] -> State IDState GraphAndRef
2016-02-19 09:51:16 +03:00
evalStmts c [stmt] = evalStmt c stmt
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 (SyntaxGraph, NameAndPort)
2016-02-19 09:51:16 +03:00
evalGuardedRhss c rhss = do
guardName <- getUniqueName "guard"
2016-02-19 09:51:16 +03:00
evaledRhss <- mapM (evalGuaredRhs c) rhss
let
(bools, exps) = unzip evaledRhss
expsWithPorts = zip exps $ map (nameAndPort guardName . Port) [2,4..]
boolsWithPorts = zip bools $ map (nameAndPort guardName . Port) [3,5..]
combindedGraph = combineExpressions False $ expsWithPorts <> boolsWithPorts
icons = [(guardName, GuardNode (length rhss))]
newGraph = syntaxGraphFromNodes icons <> combindedGraph
pure (newGraph, nameAndPort guardName (Port 1))
2016-02-19 09:51:16 +03:00
-- This is in Translate and not Translate core since currently it is only used by evalLit.
makeLiteral :: (Show x) => x -> State IDState (SyntaxGraph, NameAndPort)
makeLiteral = makeBox. show
evalLit :: Exts.Literal -> State IDState (SyntaxGraph, NameAndPort)
2016-02-20 00:46:14 +03:00
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
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
getBoundVarName :: Decl -> [String]
-- 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-03-05 05:49:02 +03:00
-- TODO: Other cases
getBoundVarName (TypeSig _ _ _) = []
2016-03-05 05:49:02 +03:00
getBoundVarName decl = error $ "getBoundVarName: No pattern in case for " ++ show decl
2016-02-21 05:47:56 +03:00
2016-02-22 02:15:16 +03:00
--TODO: Should this call makeEdges?
evalBinds :: EvalContext -> Binds -> State IDState (SyntaxGraph, EvalContext)
2016-02-21 05:47:56 +03:00
evalBinds c (BDecls decls) = do
let
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
evalGeneralLet :: (EvalContext -> State IDState (SyntaxGraph, Reference)) -> EvalContext -> Binds -> State IDState (SyntaxGraph, Reference)
2016-02-22 06:34:33 +03:00
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
2016-12-07 05:39:38 +03:00
bindings = sgSources bindGraph
pure (newGraph, lookupReference bindings expResult)
2016-02-20 00:46:14 +03:00
evalLet :: EvalContext -> Binds -> Exp -> State IDState (SyntaxGraph, Reference)
2016-02-22 06:34:33 +03:00
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, SyntaxGraph, Reference, NameAndPort)
2016-02-24 07:47:08 +03:00
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 (sgEdges grWithEdges) > (length (sgEdges rhsGraph) + length (sgEdges patGraph))
2016-02-24 07:47:08 +03:00
pure (patRhsAreConnected, deleteBindings grWithEdges, patRef, rhsRef)
-- returns (combined graph, pattern reference, rhs reference)
evalAlt :: EvalContext -> Exts.Alt -> State IDState (Bool, SyntaxGraph, Reference, NameAndPort)
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 (SyntaxGraph, NameAndPort)
2016-02-24 07:47:08 +03:00
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 = [(caseIconName, CaseNode numAlts)]
caseGraph = syntaxGraphFromNodes icons
expEdge = (expRef, nameAndPort caseIconName (Port 0))
patEdges = zip patRefs $ map (nameAndPort caseIconName . Port) [2,4..]
rhsEdges = zip patRhsConnected $ zip rhsRefs $ map (nameAndPort caseIconName . Port) [3,5..]
2016-02-24 07:47:08 +03:00
(connectedRhss, unConnectedRhss) = partition fst rhsEdges
resultIconNames <- replicateM numAlts (getUniqueName "caseResult")
let
makeCaseResult resultIconName rhsPort = syntaxGraphFromNodesEdges rhsNewIcons rhsNewEdges
2016-02-24 07:47:08 +03:00
where
rhsNewIcons = [(resultIconName, CaseResultNode)]
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
patternEdgesGraph = edgesForRefPortList True patEdges
caseEdgeGraph = edgesForRefPortList False (expEdge : filteredRhsEdges)
finalGraph = mconcat [patternEdgesGraph, caseResultGraphs, expGraph, caseEdgeGraph, caseGraph, combindedAltGraph]
pure (finalGraph, nameAndPort caseIconName (Port 1))
2016-02-24 07:47:08 +03:00
evalTuple :: EvalContext -> [Exp] -> State IDState (SyntaxGraph, NameAndPort)
2016-02-24 10:14:00 +03:00
evalTuple c exps = do
argVals <- mapM (evalExp c) exps
funVal <- makeBox $ nTupleString (length exps)
applyIconName <- getUniqueName "tupleApp"
pure $ makeApplyGraph False applyIconName (fmap Right funVal) argVals (length exps)
2016-02-24 10:14:00 +03:00
2016-03-28 02:49:58 +03:00
makeVarExp :: String -> Exp
makeVarExp = Var . UnQual . Ident
evalListExp :: EvalContext -> [Exp] -> State IDState (SyntaxGraph, NameAndPort)
2016-03-28 02:49:58 +03:00
evalListExp _ [] = makeBox "[]"
evalListExp c exps = evalApp c (makeVarExp . nListString . length $ exps, exps)
2016-03-05 10:49:48 +03:00
evalLeftSection :: EvalContext -> Exp -> QOp -> State IDState (SyntaxGraph, NameAndPort)
2016-03-05 08:35:23 +03:00
evalLeftSection c e op = evalApp c (qOpToExp op, [e])
evalRightSection:: EvalContext -> QOp -> Exp -> State IDState (SyntaxGraph, NameAndPort)
2016-03-05 08:35:23 +03:00
evalRightSection c op e = do
expVal <- evalExp c e
funVal <- evalExp c (qOpToExp op)
applyIconName <- getUniqueName "tupleApp"
2016-03-05 08:35:23 +03:00
-- TODO: A better option would be for makeApplyGraph to take the list of expressions as Maybes.
neverUsedPort <- Left <$> getUniqueString "unusedArgument"
pure $ makeApplyGraph False applyIconName funVal [(mempty, neverUsedPort), expVal] 2
2016-03-05 08:35:23 +03:00
2016-03-05 05:49:02 +03:00
-- evalEnums is only used by evalExp
evalEnums :: EvalContext -> String -> [Exp] -> State IDState (SyntaxGraph, Reference)
2016-03-05 05:49:02 +03:00
evalEnums c s exps = fmap Right <$> evalApp c (Var . UnQual . Ident $ s, exps)
2016-03-28 02:49:58 +03:00
makeQVarOp :: String -> QOp
2016-03-06 05:01:35 +03:00
makeQVarOp = QVarOp . UnQual . Ident
desugarDo :: [Stmt] -> Exp
desugarDo [Qualifier e] = e
desugarDo (Qualifier e : stmts) = InfixApp e thenOp (desugarDo stmts)
where thenOp = makeQVarOp ">>"
desugarDo (Generator srcLoc pat e : stmts) =
InfixApp e (makeQVarOp ">>=") (Lambda srcLoc [pat] (desugarDo stmts))
desugarDo (LetStmt binds : stmts) = Let binds (desugarDo stmts)
-- TODO: Finish evalRecConstr
evalRecConstr :: EvalContext -> QName -> [Exts.FieldUpdate] -> State IDState (SyntaxGraph, Reference)
2016-03-28 02:49:58 +03:00
evalRecConstr c qName _ = evalQName qName c
evalExp :: EvalContext -> Exp -> State IDState (SyntaxGraph, Reference)
2016-02-10 05:58:28 +03:00
evalExp c x = case x of
Var n -> evalQName n c
Con n -> evalQName n c
Lit l -> fmap Right <$> evalLit l
2016-04-10 04:59:40 +03:00
InfixApp e1 op e2 -> evalInfixApp c e1 op e2
e@(App _ _) -> fmap Right <$> evalApp c (simplifyApp e)
NegApp e -> evalExp c (App (makeVarExp "negate") e)
Lambda _ patterns e -> fmap Right <$> evalLambda c patterns e
2016-02-21 09:35:13 +03:00
Let bs e -> evalLet c bs e
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-03-06 05:01:35 +03:00
Do stmts -> evalExp c (desugarDo stmts)
2016-02-24 10:14:00 +03:00
-- TODO special tuple symbol
Tuple _ exps -> fmap Right <$> evalTuple c exps
2016-03-05 10:49:48 +03:00
List exps -> fmap Right <$> evalListExp c exps
2016-02-21 05:47:56 +03:00
Paren e -> evalExp c e
2016-03-05 08:35:23 +03:00
LeftSection e op -> fmap Right <$> evalLeftSection c e op
RightSection op e -> fmap Right <$> evalRightSection c op e
RecConstr n updates -> evalRecConstr c n updates
-- TODO: Do RecUpdate correcly
2016-03-28 02:49:58 +03:00
RecUpdate e _ -> evalExp c e
2016-03-05 05:49:02 +03:00
EnumFrom e -> evalEnums c "enumFrom" [e]
EnumFromTo e1 e2 -> evalEnums c "enumFromTo" [e1, e2]
EnumFromThen e1 e2 -> evalEnums c "enumFromThen" [e1, e2]
EnumFromThenTo e1 e2 e3 -> evalEnums c "enumFromThenTo" [e1, e2, e3]
-- TODO: Add the type signiture to ExpTypeSig.
ExpTypeSig _ e _ -> evalExp c e
2016-03-05 05:49:02 +03:00
-- TODO: Add other cases
_ -> error $ "evalExp: No pattern in case for " ++ show x
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.
evalRhs :: EvalContext -> Rhs -> State IDState (SyntaxGraph, Reference)
evalRhs c (UnGuardedRhs e) = evalExp c e
evalRhs c (GuardedRhss rhss) = fmap Right <$> evalGuardedRhss c rhss
rhsWithBinds :: Maybe Binds -> Rhs -> EvalContext -> State IDState (SyntaxGraph, Reference)
rhsWithBinds maybeWhereBinds rhs rhsContext = case maybeWhereBinds of
Nothing -> evalRhs rhsContext rhs
Just b -> evalGeneralLet (`evalRhs` rhs) rhsContext b
evalPatBind :: EvalContext -> Decl -> State IDState SyntaxGraph
evalPatBind c (PatBind _ pat rhs maybeWhereBinds) = do
patternNames <- namesInPattern <$> evalPattern pat
let rhsContext = patternNames <> c
(rhsGraph, rhsRef) <- rhsWithBinds maybeWhereBinds rhs rhsContext
(patGraph, patRef) <- evalPattern pat
let
(newEdges, newSinks, bindings) = case patRef of
(Left s) -> (mempty, mempty, [(s, rhsRef)])
(Right patPort) -> case rhsRef of
-- TODO This edge/sink should have a special arrow head to indicate an input to a pattern.
(Left rhsStr) -> (mempty, [(rhsStr, patPort)], mempty)
(Right rhsPort) -> ([makeSimpleEdge (rhsPort, patPort)], mempty, mempty)
2016-12-07 05:39:38 +03:00
gr = SyntaxGraph mempty newEdges newSinks bindings mempty
pure . makeEdges $ (gr <> rhsGraph <> patGraph)
2016-02-22 06:34:33 +03:00
generalEvalLambda :: EvalContext -> [Pat] -> (EvalContext -> State IDState GraphAndRef) -> State IDState (SyntaxGraph, NameAndPort)
generalEvalLambda context patterns rhsEvalFun = do
lambdaName <- getUniqueName "lam"
patternVals <- mapM evalPattern patterns
let
patternStrings = concatMap namesInPattern patternVals
rhsContext = patternStrings <> context
lambdaPorts = map (nameAndPort lambdaName . Port) [2,3..]
patternGraph = mconcat $ map fst patternVals
(patternEdges, newBinds) =
2016-03-28 02:49:58 +03:00
partitionEithers $ zipWith makePatternEdges patternVals lambdaPorts
numParameters = length patterns
-- TODO remove coerceExpressionResult here
2016-02-25 01:46:49 +03:00
(rhsRawGraph, rhsResult) <- rhsEvalFun rhsContext >>= coerceExpressionResult
let
icons = [(lambdaName, FunctionDefNode numParameters)]
resultIconEdge = makeSimpleEdge (rhsResult, nameAndPort lambdaName (Port 0))
finalGraph = SyntaxGraph icons (resultIconEdge:patternEdges)
2016-12-07 05:39:38 +03:00
mempty newBinds mempty
pure (deleteBindings . makeEdges $ (rhsRawGraph <> patternGraph <> finalGraph), nameAndPort lambdaName (Port 1))
where
-- TODO Like evalPatBind, this edge should have an indicator that it is the input to a pattern.
2016-03-22 03:36:02 +03:00
-- makePatternEdges creates the edges between the patterns and the parameter ports.
2016-03-28 02:49:58 +03:00
makePatternEdges :: GraphAndRef -> NameAndPort -> Either Edge (String, Reference)
makePatternEdges (_, Right patPort) lamPort =
Left $ makeSimpleEdge (lamPort, patPort)
2016-03-28 02:49:58 +03:00
makePatternEdges (_, Left str) lamPort = Right (str, Right lamPort)
evalLambda :: EvalContext -> [Pat] -> Exp -> State IDState (SyntaxGraph, NameAndPort)
evalLambda c patterns e = generalEvalLambda c patterns (`evalExp` e)
2016-02-23 02:45:53 +03:00
evalMatch :: EvalContext -> Match -> State IDState SyntaxGraph
evalMatch c (Match _ name patterns _ rhs maybeWhereBinds) = do
let
matchFunNameString = nameToString name
newContext = matchFunNameString : c
(lambdaGraph, lambdaPort) <-
generalEvalLambda newContext patterns (rhsWithBinds maybeWhereBinds rhs)
let
2016-12-07 05:39:38 +03:00
newBinding = SyntaxGraph mempty mempty mempty [(matchFunNameString, Right lambdaPort)] mempty
pure $ makeEdges (newBinding <> lambdaGraph)
2016-02-23 02:45:53 +03:00
-- Only used by matchesToCase
matchToAlt :: Match -> Alt
matchToAlt (Match srcLocation _ mtaPats _ rhs binds) = Alt srcLocation altPattern rhs binds where
altPattern = case mtaPats of
[onePat] -> onePat
_ -> PTuple Exts.Boxed mtaPats
matchesToCase :: Match -> [Match] -> State IDState Match
matchesToCase match [] = pure match
matchesToCase firstMatch@(Match srcLoc funName pats mType _ _) restOfMatches = do
tempStrings <- replicateM (length pats) (getUniqueString "_tempvar")
2016-02-25 01:46:49 +03:00
let
tempPats = fmap (PVar . Ident) tempStrings
tempVars = fmap (Var . UnQual . Ident) tempStrings
tuple = Tuple Exts.Boxed tempVars
caseExp = case tempVars of
[oneTempVar] -> Case oneTempVar alts
_ -> Case tuple alts
2016-02-25 01:46:49 +03:00
rhs = UnGuardedRhs caseExp
match = Match srcLoc funName tempPats mType rhs Nothing
pure match
where
allMatches = firstMatch:restOfMatches
alts = fmap matchToAlt allMatches
2016-02-25 01:46:49 +03:00
evalMatches :: EvalContext -> [Match] -> State IDState SyntaxGraph
2016-02-22 02:15:16 +03:00
evalMatches _ [] = pure mempty
evalMatches c (firstMatch:restOfMatches) = matchesToCase firstMatch restOfMatches >>= evalMatch c
evalDecl :: EvalContext -> Decl -> State IDState SyntaxGraph
2016-02-21 05:47:56 +03:00
evalDecl c d = evaluatedDecl where
2016-02-18 07:59:43 +03:00
evaluatedDecl = case d of
pat@(PatBind _ _ _ _) -> evalPatBind c pat
2016-02-21 05:47:56 +03:00
FunBind matches -> evalMatches c matches
2016-02-24 10:14:00 +03:00
--TODO: Add other cases here
_ -> pure mempty
showTopLevelBinds :: SyntaxGraph -> State IDState SyntaxGraph
2016-12-07 05:39:38 +03:00
showTopLevelBinds gr = do
let
2016-12-07 05:39:38 +03:00
binds = sgSources gr
addBind (_, Left _) = pure mempty
addBind (patName, Right port) = do
uniquePatName <- getUniqueName patName
let
icons = [(uniquePatName, BindNameNode patName)]
edges = [makeSimpleEdge (justName uniquePatName, port)]
edgeGraph = syntaxGraphFromNodesEdges icons edges
pure edgeGraph
newGraph <- mconcat <$> mapM addBind binds
pure $ newGraph <> gr
-- TODO Rename these functions to not have "drawing" in them.
drawingFromDecl :: Decl -> IngSyntaxGraph FGR.Gr
drawingFromDecl d = drawing
where
evaluatedDecl = evalDecl mempty d >>= showTopLevelBinds
syntaxGraph = evalState evaluatedDecl initialIdState
drawing = collapseNodes $ syntaxGraphToFglGraph syntaxGraph
2016-12-06 04:14:54 +03:00
--drawing = syntaxGraphToFglGraph syntaxGraph
-- Profiling: about 1.5% of total time.
translateString :: String -> (IngSyntaxGraph FGR.Gr, Decl)
translateString s = (drawing, decl) where
2016-05-10 09:45:37 +03:00
decl = fromParseResult (parseDecl s) -- :: ParseResult Module
2016-02-21 05:47:56 +03:00
drawing = drawingFromDecl decl
2016-02-24 10:14:00 +03:00
drawingsFromModule :: Module -> [IngSyntaxGraph FGR.Gr]
2016-02-24 10:14:00 +03:00
drawingsFromModule (Module _ _ _ _ _ _ decls) = fmap drawingFromDecl decls
stringToSyntaxGraph :: String -> SyntaxGraph
stringToSyntaxGraph s = graph where
decl = fromParseResult (parseDecl s)
evaluatedDecl = evalDecl mempty decl >>= showTopLevelBinds
graph = evalState evaluatedDecl initialIdState