Change node identifier from string to Int. Now, data NameAndPort = NameAndPort NodeName (Maybe Port), where NodeName and Port are both Int newtypes.

This commit is contained in:
Robbie Gleichman 2016-12-06 17:02:54 -08:00
parent d3c463d41f
commit 5e1d724418
7 changed files with 251 additions and 250 deletions

View File

@ -21,7 +21,7 @@ module Icons
coloredTextBox
) where
import Diagrams.Prelude hiding ((&), (#))
import Diagrams.Prelude hiding ((&), (#), Name)
import Data.List(find)
import Data.Maybe(catMaybes, listToMaybe)
@ -30,11 +30,11 @@ import Data.Maybe(catMaybes, listToMaybe)
--import Diagrams.TwoD.Text(Text)
--import Data.Maybe(fromMaybe)
import Types(Icon(..), SpecialQDiagram, SpecialBackend, SpecialNum)
import Types(Icon(..), SpecialQDiagram, SpecialBackend, SpecialNum, NodeName, Port(..))
import DrawingColors(colorScheme, ColorStyle(..))
-- TYPES --
type TransformableDia b n = Name -> Bool -> Angle n -> SpecialQDiagram b n
type TransformableDia b n = NodeName -> Bool -> Angle n -> SpecialQDiagram b n
-- COLORS --
lineCol :: Colour Double
@ -55,27 +55,27 @@ iconToDiagram (FlatLambdaIcon n) = identDiaFunc $ flatLambda n
iconToDiagram (NestedApply args) = nestedApplyDia args
iconToDiagram (NestedPApp args) = nestedPAppDia args
applyPortAngles :: (Integral a, Floating n) => a -> [Angle n]
applyPortAngles x = fmap (@@ turn) $ case x of
applyPortAngles :: Floating n => Port -> [Angle n]
applyPortAngles (Port x) = fmap (@@ turn) $ case x of
0 -> [3/8, 5/8] -- TODO Add back an angle of 1/2 for non-nested icons
1 -> [0, 1/8, 7/8]
_ -> [1/4, 3/4]
guardPortAngles :: (Integral a, Floating n) => a -> [Angle n]
guardPortAngles port = case port of
guardPortAngles :: Floating n => Port -> [Angle n]
guardPortAngles (Port port) = case port of
0 -> [1/4 @@ turn]
1 -> [3/4 @@ turn]
_ -> otherAngles where otherAngles
| even port = [0 @@ turn]
| otherwise = [1/2 @@ turn]
findNestedIcon :: Name -> Icon -> Maybe Icon
findNestedIcon :: NodeName -> Icon -> Maybe Icon
findNestedIcon name icon = case icon of
NestedApply args -> findIcon name args
NestedPApp args -> findIcon name args
_ -> Nothing
findIcon :: Name -> [Maybe (Name, Icon)] -> Maybe Icon
findIcon :: NodeName -> [Maybe (NodeName, Icon)] -> Maybe Icon
findIcon name args = icon where
filteredArgs = catMaybes args
nameMatches (n, _) = n == name
@ -85,15 +85,15 @@ findIcon name args = icon where
Nothing -> listToMaybe $ catMaybes $ fmap (findNestedIcon name . snd) filteredArgs
Just (_, finalIcon) -> Just finalIcon
nestedApplyPortAngles :: (Integral a, Floating n) => [Maybe (Name, Icon)] -> a -> Maybe Name -> [Angle n]
nestedApplyPortAngles args port maybeName = case maybeName of
nestedApplyPortAngles :: Floating n => [Maybe (NodeName, Icon)] -> Port -> Maybe NodeName -> [Angle n]
nestedApplyPortAngles args port maybeNodeName = case maybeNodeName of
Nothing -> applyPortAngles port
Just name -> case findIcon name args of
Nothing -> []
Just icon -> getPortAngles icon port Nothing
getPortAngles :: (Integral a, Floating n) => Icon -> a -> Maybe Name -> [Angle n]
getPortAngles icon port maybeName = case icon of
getPortAngles :: (Floating n) => Icon -> Port -> Maybe NodeName -> [Angle n]
getPortAngles icon port maybeNodeName = case icon of
ApplyAIcon _ -> applyPortAngles port
PAppIcon _ _ -> applyPortAngles port
ResultIcon -> []
@ -104,8 +104,8 @@ getPortAngles icon port maybeName = case icon of
CaseIcon _ -> guardPortAngles port
CaseResultIcon -> []
FlatLambdaIcon _ -> applyPortAngles port
NestedApply args -> nestedApplyPortAngles args port maybeName
NestedPApp args -> nestedApplyPortAngles args port maybeName
NestedApply args -> nestedApplyPortAngles args port maybeNodeName
NestedPApp args -> nestedApplyPortAngles args port maybeNodeName
-- END FUNCTIONS --
@ -122,7 +122,7 @@ nameDiagram name dia = named name (name .>> dia)
-- | Make an port with an integer name. Always use <> to add a ports (not === or |||)
--- since mempty has no size and will not be placed where you want it.
makePort :: SpecialNum n => Int -> SpecialQDiagram b n
makePort :: SpecialNum n => Port -> SpecialQDiagram b n
makePort x = named x mempty
--makePort x = circle 0.2 # fc green # named x
-- Note, the version of makePort below seems to have a different type.
@ -153,10 +153,10 @@ coloredApplyADia ::
coloredApplyADia appColor n = centerXY finalDia where
trianglePortsCircle = hcat [
reflectX (fc appColor apply0Triangle),
hcat $ take n $ map (\x -> makePort x <> portCircle <> strutX (circleRadius * 1.5)) [2,3..],
makePort 1 <> alignR (lc appColor $ lwG defaultLineWidth $ fc appColor $ circle circleRadius)
hcat $ take n $ map (\x -> makePort (Port x) <> portCircle <> strutX (circleRadius * 1.5)) [2,3..],
makePort (Port 1) <> alignR (lc appColor $ lwG defaultLineWidth $ fc appColor $ circle circleRadius)
]
allPorts = makePort 0 <> alignL trianglePortsCircle
allPorts = makePort (Port 0) <> alignL trianglePortsCircle
topAndBottomLineWidth = width allPorts - circleRadius
topAndBottomLine = alignL $ lwG defaultLineWidth $ lc appColor $ hrule topAndBottomLineWidth
finalDia = topAndBottomLine === allPorts === topAndBottomLine
@ -192,16 +192,16 @@ transformCorrectedTextBox str textCol borderCol reflect angle =
reflectIfTrue shouldReflect dia = if shouldReflect then reflectX dia else dia
nestedApplyDia :: SpecialBackend b n =>
[Maybe (Name, Icon)] -> TransformableDia b n
[Maybe (NodeName, Icon)] -> TransformableDia b n
nestedApplyDia = generalNestedDia (apply0C colorScheme)
nestedPAppDia :: SpecialBackend b n =>
[Maybe (Name, Icon)] -> TransformableDia b n
[Maybe (NodeName, Icon)] -> TransformableDia b n
nestedPAppDia = generalNestedDia (patternC colorScheme)
generalNestedDia :: SpecialBackend b n =>
Colour Double -> [Maybe (Name, Icon)] -> TransformableDia b n
generalNestedDia borderCol funcNameAndArgs name reflect angle = named name $ case funcNameAndArgs of
Colour Double -> [Maybe (NodeName, Icon)] -> TransformableDia b n
generalNestedDia borderCol funcNodeNameAndArgs name reflect angle = named name $ case funcNodeNameAndArgs of
[] -> mempty
(maybeFunText:args) -> centerXY $ transformedText ||| centerY finalDia
where
@ -214,15 +214,15 @@ generalNestedDia borderCol funcNameAndArgs name reflect angle = named name $ cas
trianglePortsCircle = hsep seperation $
reflectX (fc borderCol apply0Triangle) :
zipWith makeInnerIcon [2,3..] args ++
[makeQualifiedPort 1 <> alignR (lc borderCol $ lwG defaultLineWidth $ fc borderCol $ circle circleRadius)]
[makeQualifiedPort (Port 1) <> alignR (lc borderCol $ lwG defaultLineWidth $ fc borderCol $ circle circleRadius)]
allPorts = makeQualifiedPort 0 <> alignL trianglePortsCircle
allPorts = makeQualifiedPort (Port 0) <> alignL trianglePortsCircle
topAndBottomLineWidth = width allPorts - circleRadius
argBox = alignL $ lwG defaultLineWidth $ lc borderCol $ rect topAndBottomLineWidth (height allPorts + verticalSeperation)
finalDia = argBox <> allPorts
makeInnerIcon portNum Nothing = makeQualifiedPort portNum <> portCircle
makeInnerIcon _ (Just (iconName, icon)) = iconToDiagram icon iconName reflect angle
makeInnerIcon portNum Nothing = makeQualifiedPort (Port portNum) <> portCircle
makeInnerIcon _ (Just (iconNodeName, icon)) = iconToDiagram icon iconNodeName reflect angle
-- TEXT ICON --
@ -284,7 +284,7 @@ enclosure dia = dia <> lwG defaultLineWidth (lc (regionPerimC colorScheme) $ bou
lambdaIcon ::
SpecialBackend b n =>
Int -> SpecialQDiagram b n
lambdaIcon x = alignB (coloredTextBox (lamArgResC colorScheme) transparent "λ") <> makePort x
lambdaIcon x = alignB (coloredTextBox (lamArgResC colorScheme) transparent "λ") <> makePort (Port x)
-- LAMBDA REGION --
@ -311,14 +311,14 @@ guardSize = 0.7
guardTriangle :: SpecialBackend b n =>
Int -> SpecialQDiagram b n
guardTriangle x =
alignL $ alignR (triangleAndPort ||| lwG defaultLineWidth (hrule (guardSize * 0.8))) <> makePort x
alignL $ alignR (triangleAndPort ||| lwG defaultLineWidth (hrule (guardSize * 0.8))) <> makePort (Port x)
where
triangleAndPort = alignR $ alignT $ lwG defaultLineWidth $ rotateBy (1/8) $
polygon (polyType .~ PolySides [90 @@ deg, 45 @@ deg] [guardSize, guardSize] $ with)
guardLBracket :: SpecialBackend b n =>
Int -> SpecialQDiagram b n
guardLBracket x = alignL (alignT ell) <> makePort x
guardLBracket x = alignL (alignT ell) <> makePort (Port x)
where
ellShape = fromOffsets $ map r2 [(0, guardSize), (-guardSize,0)]
ell = lineJoin LineJoinRound $ lwG defaultLineWidth $ lc (boolC colorScheme) (strokeLine ellShape)
@ -330,7 +330,7 @@ guardLBracket x = alignL (alignT ell) <> makePort x
-- evens -> right
generalGuardIcon :: SpecialBackend b n =>
Colour Double -> (Int -> SpecialQDiagram b n) -> SpecialQDiagram b n -> Int -> SpecialQDiagram b n
generalGuardIcon triangleColor lBracket bottomDia n = centerXY $ alignT (bottomDia <> makePort 1) <> alignB (bigVerticalLine <> guardDia <> makePort 0)
generalGuardIcon triangleColor lBracket bottomDia n = centerXY $ alignT (bottomDia <> makePort (Port 1)) <> alignB (bigVerticalLine <> guardDia <> makePort (Port 0))
where
--guardTriangles = vsep 0.4 (take n (map guardTriangle [0,1..]))
trianglesWithPorts = map guardTriangle [2,4..]
@ -361,7 +361,7 @@ caseResult = lw none $ lc caseCColor $ fc caseCColor $ circle (circleRadius * 0.
caseC :: SpecialBackend b n =>
Int -> SpecialQDiagram b n
caseC n = caseResult <> makePort n
caseC n = caseResult <> makePort (Port n)
-- | The ports of the case icon are as follows:
@ -380,8 +380,8 @@ caseIcon = generalGuardIcon (patternC colorScheme) caseC caseResult
flatLambda :: SpecialBackend b n => Int -> SpecialQDiagram b n
flatLambda n = finalDia where
lambdaCircle = lwG defaultLineWidth $ lc (regionPerimC colorScheme) $ fc (regionPerimC colorScheme) $ circle circleRadius
lambdaParts = (makePort 0 <> resultIcon) : (portIcons ++ [makePort 1 <> alignR lambdaCircle])
portIcons = take n $ map (\x -> makePort x <> portCircle) [2,3..]
lambdaParts = (makePort (Port 0) <> resultIcon) : (portIcons ++ [makePort (Port 1) <> alignR lambdaCircle])
portIcons = take n $ map (\x -> makePort (Port x) <> portCircle) [2,3..]
middle = alignL (hsep 0.5 lambdaParts)
topAndBottomLineWidth = width middle - circleRadius
topAndBottomLine = alignL $ lwG defaultLineWidth $ lc (regionPerimC colorScheme) $ hrule topAndBottomLineWidth

View File

@ -6,10 +6,8 @@ module Rendering (
renderIngSyntaxGraph
) where
import Diagrams.Core.Names(Name(..))
import Diagrams.Prelude hiding ((#), (&))
import Diagrams.TwoD.GraphViz(mkGraph, getGraph, layoutGraph')
--import Diagrams.Backend.SVG(B)
import qualified Data.GraphViz as GV
import qualified Data.GraphViz.Attributes.Complete as GVA
@ -31,7 +29,7 @@ import Data.Typeable(Typeable)
import Icons(colorScheme, iconToDiagram, defaultLineWidth, ColorStyle(..), getPortAngles)
import TranslateCore(nodeToIcon)
import Types(Edge(..), Icon, EdgeOption(..), Connection, Drawing(..), EdgeEnd(..),
NameAndPort(..), SpecialQDiagram, SpecialBackend, SyntaxNode, SpecialNum)
NameAndPort(..), SpecialQDiagram, SpecialBackend, SyntaxNode, SpecialNum, NodeName(..), Port)
import Util(fromMaybeError)
-- If the inferred types for these functions becomes unweildy,
@ -55,25 +53,17 @@ drawingToGraphvizScaleFactor :: Fractional a => a
-- For Neato, PrismOverlap
drawingToGraphvizScaleFactor = 0.15
-- Note that the name type alias is different from the Name constructor.
getTopLevelName :: Name -> Name
getTopLevelName (Name []) = Name []
getTopLevelName (Name (x:_)) = Name [x]
-- TODO Refactor with syntaxGraphToFglGraph in TranslateCore
-- TODO Make this work with nested icons now that names are not qualified.
drawingToIconGraph :: Drawing -> Gr (Name, Icon) Edge
drawingToIconGraph :: Drawing -> Gr (NodeName, Icon) Edge
drawingToIconGraph (Drawing nodes edges) =
mkGraph nodes labeledEdges where
labeledEdges = fmap makeLabeledEdge edges
makeLabeledEdge e@(Edge _ _ (NameAndPort n1 _, NameAndPort n2 _)) =
let name1 = getTopLevelName n1
name2 = getTopLevelName n2
in
((name1, lookupInNodes name1), (name2, lookupInNodes name2), e) where
((n1, lookupInNodes n1), (n2, lookupInNodes n2), e) where
lookupInNodes name = fromMaybeError errorString (lookup name nodes) where
errorString =
"syntaxGraphToFglGraph edge connects to non-existent node. Node Name ="
"syntaxGraphToFglGraph edge connects to non-existent node. Node NodeName ="
++ show name ++ " Edge=" ++ show e
@ -126,17 +116,17 @@ connectMaybePorts portAngles (Edge opts ends (NameAndPort name0 mPort1, NameAndP
connectFunc (getArrowOpts ends opts portAngles) qPort0 qPort1 where
(connectFunc, qPort0, qPort1) = case (mPort1, mPort2) of
(Just port0, Just port1) -> (connect', name0 .> port0, name1 .> port1)
(Nothing, Just port1) -> (connectOutside', name0, name1 .> port1)
(Just port0, Nothing) -> (connectOutside', name0 .> port0, name1)
(_, _) -> (connectOutside', name0, name1)
(Nothing, Just port1) -> (connectOutside', toName name0, name1 .> port1)
(Just port0, Nothing) -> (connectOutside', name0 .> port0, toName name1)
(_, _) -> (connectOutside', toName name0, toName name1)
-- START addEdges --
nameAndPortToName :: NameAndPort -> Name
nameAndPortToName (NameAndPort name mPort) = case mPort of
Nothing -> name
Nothing -> toName name
Just port -> name .> port
findPortAngles :: Floating n => (Name, Icon) -> NameAndPort -> [Angle n]
findPortAngles :: Floating n => (NodeName, Icon) -> NameAndPort -> [Angle n]
findPortAngles (nodeName, nodeIcon) (NameAndPort diaName mPort) = case mPort of
Nothing -> []
Just port -> foundAngles where
@ -161,14 +151,14 @@ pickClosestAngle (nodeFlip, nodeAngle) emptyCase target shaftAngle angles = case
(+) <$> angle <*> nodeAngle
lookupNodeAngle :: Show n => [((Name, Icon), (Bool, Angle n))] -> (Name, Icon) -> (Bool, Angle n)
lookupNodeAngle :: Show n => [((NodeName, Icon), (Bool, Angle n))] -> (NodeName, Icon) -> (Bool, Angle n)
lookupNodeAngle rotationMap key =
fromMaybeError ("nodeVector: key not in rotaionMap. key = " ++ show key ++ "\n\n rotationMap = " ++ show rotationMap)
$ lookup key rotationMap
makeEdge :: (SpecialBackend b n, ING.Graph gr) =>
gr (Name, Icon) Edge -> SpecialQDiagram b n -> [((Name, Icon), (Bool, Angle n))] ->
gr (NodeName, Icon) Edge -> SpecialQDiagram b n -> [((NodeName, Icon), (Bool, Angle n))] ->
ING.LEdge Edge -> SpecialQDiagram b n -> SpecialQDiagram b n
makeEdge graph dia rotationMap (node0, node1, edge@(Edge _ _ (namePort0, namePort1))) =
connectMaybePorts portAngles edge
@ -181,7 +171,7 @@ makeEdge graph dia rotationMap (node0, node1, edge@(Edge _ _ (namePort0, namePor
node0Angle = lookupNodeAngle rotationMap node0label
node1Angle = lookupNodeAngle rotationMap node1label
diaNamePointMap = names dia
diaNodeNamePointMap = names dia
port0Point = getPortPoint $ nameAndPortToName namePort0
port1Point = getPortPoint $ nameAndPortToName namePort1
shaftVector = port1Point .-. port0Point
@ -193,14 +183,14 @@ makeEdge graph dia rotationMap (node0, node1, edge@(Edge _ _ (namePort0, namePor
icon1PortAngle = pickClosestAngle node1Angle (1/2 @@ turn) shaftAnglePlusOneHalf shaftAngle $ findPortAngles node1label namePort1
getPortPoint n = head $ fromMaybeError
("makeEdge: port not found. Port: " ++ show n ++ ". Valid ports: " ++ show diaNamePointMap)
(lookup n diaNamePointMap)
("makeEdge: port not found. Port: " ++ show n ++ ". Valid ports: " ++ show diaNodeNamePointMap)
(lookup n diaNodeNamePointMap)
portAngles = (icon0PortAngle, icon1PortAngle)
addEdges :: (SpecialBackend b n, ING.Graph gr) =>
gr (Name, Icon) Edge -> (SpecialQDiagram b n, [((Name, Icon), (Bool, Angle n))]) -> SpecialQDiagram b n
gr (NodeName, Icon) Edge -> (SpecialQDiagram b n, [((NodeName, Icon), (Bool, Angle n))]) -> SpecialQDiagram b n
addEdges graph (dia, rotationMap) = applyAll connections dia
where
connections = makeEdge graph dia rotationMap <$> ING.labEdges graph
@ -244,7 +234,7 @@ getFromMapAndScale :: (Fractional a, Functor f, Ord k) => Map.Map k (f a) -> k -
getFromMapAndScale posMap name = graphvizScaleFactor *^ (posMap Map.! name)
-- | Returns [(myport, other node, maybe other node's port)]
connectedPorts :: [Connection] -> Name -> [(Int, Name, Maybe Int)]
connectedPorts :: [Connection] -> NodeName -> [(Port, NodeName, Maybe Port)]
connectedPorts edges name = map edgeToPort $ filter nameInEdge edges
where
isPort = isJust
@ -259,12 +249,12 @@ connectedPorts edges name = map edgeToPort $ filter nameInEdge edges
-- Precondition: the diagrams are already centered
-- todo: confirm precondition (or use a newtype)
rotateNodes :: SpecialBackend b n =>
Map.Map (Name, Icon) (Point V2 n)
Map.Map (NodeName, Icon) (Point V2 n)
-> [Connection]
-> [((Name, Icon), SpecialQDiagram b n, (Bool, Angle n))]
-> [((NodeName, Icon), SpecialQDiagram b n, (Bool, Angle n))]
rotateNodes positionMap edges = map rotateDiagram (Map.keys positionMap)
where
positionMapNameKeys = Map.mapKeys fst positionMap
positionMapNodeNameKeys = Map.mapKeys fst positionMap
rotateDiagram key@(name, icon) = (key, transformedDia, (reflected, angle))
where
originalDia = iconToDiagram icon name
@ -281,40 +271,40 @@ rotateNodes positionMap edges = map rotateDiagram (Map.keys positionMap)
ports = names dia
namesOfPortsWithLines = connectedPorts edges name
--iconInMap :: (Int, Name, Maybe Int) -> Bool
iconInMap (_, otherIconName, _) = Map.member otherIconName positionMapNameKeys
--iconInMap :: (Int, NodeName, Maybe Int) -> Bool
iconInMap (_, otherIconNodeName, _) = Map.member otherIconNodeName positionMapNodeNameKeys
--getPortPoint :: Int -> P2 Double
getPortPoint x =
-- TODO remove partial function head.
head $ fromMaybeError
("rotateNodes: port not found. Port: " ++ show x ++ ". Valid ports: " ++ show ports)
(lookup (name .> toName x) ports)
(lookup (name .> x) ports)
--makePortEdge :: (Int, Name, Maybe Int) -> (P2 Double, P2 Double)
makePortEdge (portInt, otherIconName, _) =
(getPortPoint portInt, getFromMapAndScale positionMapNameKeys otherIconName)
--makePortEdge :: (Int, NodeName, Maybe Int) -> (P2 Double, P2 Double)
makePortEdge (portInt, otherIconNodeName, _) =
(getPortPoint portInt, getFromMapAndScale positionMapNodeNameKeys otherIconNodeName)
portEdges = map makePortEdge $ filter iconInMap namesOfPortsWithLines
minAngle = angleWithMinDist (getFromMapAndScale positionMapNameKeys name) portEdges
minAngle = angleWithMinDist (getFromMapAndScale positionMapNodeNameKeys name) portEdges
type LayoutResult a b = Gr (GV.AttributeNode (Name, b)) (GV.AttributeNode a)
type LayoutResult a b = Gr (GV.AttributeNode (NodeName, b)) (GV.AttributeNode a)
placeNodes :: forall a b. SpecialBackend b Double =>
LayoutResult a Icon
-> [Edge]
-> (SpecialQDiagram b Double, [((Name, Icon), (Bool, Angle Double))])
-> (SpecialQDiagram b Double, [((NodeName, Icon), (Bool, Angle Double))])
placeNodes layoutResult edges = (mconcat placedNodes, rotationMap)
where
connections = fmap edgeConnection edges
positionMap = fst $ getGraph layoutResult
-- The type annotation for rotatedNameDiagramMap is necessary here
rotatedNameDiagramMap = rotateNodes positionMap connections :: [((Name, Icon), SpecialQDiagram b Double, (Bool, Angle Double))]
rotationMap = fmap (\(x, _, z) -> (x, z)) rotatedNameDiagramMap
-- The type annotation for rotatedNodeNameDiagramMap is necessary here
rotatedNodeNameDiagramMap = rotateNodes positionMap connections :: [((NodeName, Icon), SpecialQDiagram b Double, (Bool, Angle Double))]
rotationMap = fmap (\(x, _, z) -> (x, z)) rotatedNodeNameDiagramMap
placedNodes = map placeNode rotatedNameDiagramMap
placedNodes = map placeNode rotatedNodeNameDiagramMap
--placedNodes = map placeNode $ (\key@(name, icon) -> (key, iconToDiagram icon name False 0)) <$> Map.keys positionMap
-- todo: Not sure if the diagrams should already be centered at this point.
placeNode (key, diagram, _) = place (centerXY diagram) (graphvizScaleFactor *^ (positionMap Map.! key))
@ -340,7 +330,7 @@ customLayoutParams = GV.defaultParams{
doGraphLayout :: forall b.
SpecialBackend b Double =>
Gr (Name, Icon) Edge
Gr (NodeName, Icon) Edge
-> [Edge]
-> IO (SpecialQDiagram b Double)
doGraphLayout graph edges = do
@ -348,12 +338,12 @@ doGraphLayout graph edges = do
-- layoutResult <- layoutGraph' layoutParams GVA.Fdp graph
pure $ addEdges graph $ placeNodes layoutResult edges
where
layoutParams :: GV.GraphvizParams Int (Name,Icon) e () (Name,Icon)
layoutParams :: GV.GraphvizParams Int (NodeName,Icon) e () (NodeName,Icon)
--layoutParams :: GV.GraphvizParams Int l el Int l
layoutParams = customLayoutParams{
GV.fmtNode = nodeAttribute
}
nodeAttribute :: (Int, (Name, Icon)) -> [GV.Attribute]
nodeAttribute :: (Int, (NodeName, Icon)) -> [GV.Attribute]
nodeAttribute (_, (_, nodeIcon)) =
-- GVA.Width and GVA.Height have a minimum of 0.01
--[GVA.Width diaWidth, GVA.Height diaHeight]
@ -361,7 +351,7 @@ doGraphLayout graph edges = do
where
-- This type annotation (:: SpecialQDiagram b n) requires Scoped Typed Variables, which only works if the function's
-- type signiture has "forall b e."
dia = iconToDiagram nodeIcon (toName "") False mempty :: SpecialQDiagram b Double
dia = iconToDiagram nodeIcon (NodeName (-1)) False mempty :: SpecialQDiagram b Double
diaWidth = drawingToGraphvizScaleFactor * width dia
diaHeight = drawingToGraphvizScaleFactor * height dia
@ -377,10 +367,10 @@ renderDrawing = renderIconGraph . drawingToIconGraph
renderIngSyntaxGraph ::
SpecialBackend b Double =>
Gr (Name, SyntaxNode) Edge -> IO (SpecialQDiagram b Double)
Gr (NodeName, SyntaxNode) Edge -> IO (SpecialQDiagram b Double)
renderIngSyntaxGraph = renderIconGraph . ING.nmap (Control.Arrow.second nodeToIcon)
renderIconGraph :: SpecialBackend b Double => Gr (Name, Icon) Edge -> IO (SpecialQDiagram b Double)
renderIconGraph :: SpecialBackend b Double => Gr (NodeName, Icon) Edge -> IO (SpecialQDiagram b Double)
renderIconGraph iconGraph = diagramAction where
edges = ING.edgeLabel <$> ING.labEdges iconGraph
diagramAction = doGraphLayout iconGraph edges

View File

@ -6,7 +6,6 @@ module Translate(
stringToSyntaxGraph
) where
import qualified Diagrams.Prelude as DIA hiding ((#), (&))
import Diagrams.Prelude((<>))
import Control.Monad(replicateM)
@ -26,16 +25,15 @@ import TranslateCore(Reference, SyntaxGraph(..), EvalContext, GraphAndRef,
edgesForRefPortList, makeApplyGraph,
namesInPattern, lookupReference, deleteBindings, makeEdges,
coerceExpressionResult, makeBox, nTupleString, nListString,
syntaxGraphToFglGraph)
syntaxGraphToFglGraph, getUniqueString)
import Types(NameAndPort(..), IDState,
initialIdState, Edge, SyntaxNode(..), IngSyntaxGraph)
import Util(toNames, makeSimpleEdge, nameAndPort, justName, mapFst)
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.
-- * Please note that this files uses both DIA.Name from Diagrams.Prelude, and Name from Language.Haskell.Exts
nameToString :: Language.Haskell.Exts.Name -> String
nameToString (Ident s) = s
@ -55,7 +53,7 @@ qNameToString (Special UnboxedSingleCon) = "(# #)"
evalPApp :: QName -> [Pat] -> State IDState (SyntaxGraph, NameAndPort)
evalPApp name [] = makeBox $ qNameToString name
evalPApp name patterns = do
patName <- DIA.toName <$> getUniqueName "pat"
patName <- getUniqueName "pat"
evaledPatterns <- mapM evalPattern patterns
let
constructorName = qNameToString name
@ -111,15 +109,15 @@ evalQName qName _ = fmap Right <$> makeBox (qNameToString qName)
-- qOpToString (QVarOp n) = qNameToString n
-- qOpToString (QConOp n) = qNameToString n
--findReferencedIcon :: Reference -> [(DIA.Name, Icon)] -> Maybe (Name, Icon)
-- findReferencedIcon :: Either t NameAndPort -> [(DIA.Name, t1)] -> Maybe (DIA.Name, t1)
--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 :: DIA.Name -> String -> [(SyntaxGraph, Reference)] -> Int -> (SyntaxGraph, NameAndPort)
makePatternGraph applyIconName funStr argVals numArgs = (newGraph <> combinedGraph, nameAndPort applyIconName 1)
makePatternGraph :: NodeName -> String -> [(SyntaxGraph, Reference)] -> Int -> (SyntaxGraph, NameAndPort)
makePatternGraph applyIconName funStr argVals numArgs = (newGraph <> combinedGraph, nameAndPort applyIconName (Port 1))
where
argumentPorts = map (nameAndPort applyIconName) [2,3..]
argumentPorts = map (nameAndPort applyIconName . Port) [2,3..]
combinedGraph = combineExpressions True $ zip argVals argumentPorts
icons = [(applyIconName, PatternApplyNode funStr numArgs)]
newGraph = syntaxGraphFromNodes icons
@ -128,7 +126,7 @@ evalApp :: EvalContext -> (Exp, [Exp]) -> State IDState (SyntaxGraph, NameAndPor
evalApp c (funExp, argExps) = do
funVal <- evalExp c funExp
argVals <- mapM (evalExp c) argExps
applyIconName <- DIA.toName <$> getUniqueName "app0"
applyIconName <- getUniqueName "app0"
pure $ makeApplyGraph False applyIconName funVal argVals (length argExps)
qOpToExp :: QOp -> Exp
@ -151,13 +149,13 @@ evalIf c e1 e2 e3 = do
e1Val <- evalExp c e1
e2Val <- evalExp c e2
e3Val <- evalExp c e3
guardName <- DIA.toName <$> getUniqueName "if"
guardName <- getUniqueName "if"
let
icons = [(guardName, GuardNode 2)]
combinedGraph =
combineExpressions False $ zip [e1Val, e2Val, e3Val] (map (nameAndPort guardName) [3, 2, 4])
combineExpressions False $ zip [e1Val, e2Val, e3Val] (map (nameAndPort guardName . Port) [3, 2, 4])
newGraph = syntaxGraphFromNodes icons <> combinedGraph
pure (newGraph, NameAndPort guardName (Just 0))
pure (newGraph, nameAndPort guardName (Port 0))
evalStmt :: EvalContext -> Stmt -> State IDState GraphAndRef
evalStmt c (Qualifier e) = evalExp c e
@ -173,16 +171,16 @@ evalGuaredRhs c (GuardedRhs _ stmts e) = do
evalGuardedRhss :: EvalContext -> [GuardedRhs] -> State IDState (SyntaxGraph, NameAndPort)
evalGuardedRhss c rhss = do
guardName <- DIA.toName <$> getUniqueName "guard"
guardName <- 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..]
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 (Just 1))
pure (newGraph, nameAndPort guardName (Port 1))
-- This is in Translate and not Translate core since currently it is only used by evalLit.
makeLiteral :: (Show x) => x -> State IDState (SyntaxGraph, NameAndPort)
@ -274,30 +272,30 @@ evalCase c e alts = do
(patRhsConnected, altGraphs, patRefs, rhsRefs) = unzip4 evaledAlts
combindedAltGraph = mconcat altGraphs
numAlts = length alts
icons = toNames [(caseIconName, CaseNode numAlts)]
icons = [(caseIconName, CaseNode numAlts)]
caseGraph = syntaxGraphFromNodes icons
expEdge = (expRef, nameAndPort caseIconName 0)
patEdges = zip patRefs $ map (nameAndPort caseIconName ) [2,4..]
rhsEdges = zip patRhsConnected $ zip rhsRefs $ map (nameAndPort caseIconName) [3,5..]
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..]
(connectedRhss, unConnectedRhss) = partition fst rhsEdges
resultIconNames <- replicateM numAlts (getUniqueName "caseResult")
let
makeCaseResult resultIconName rhsPort = syntaxGraphFromNodesEdges rhsNewIcons rhsNewEdges
where
rhsNewIcons = toNames [(resultIconName, CaseResultNode)]
rhsNewIcons = [(resultIconName, CaseResultNode)]
rhsNewEdges = [makeSimpleEdge (rhsPort, justName resultIconName)]
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 1)
pure (finalGraph, nameAndPort caseIconName (Port 1))
evalTuple :: EvalContext -> [Exp] -> State IDState (SyntaxGraph, NameAndPort)
evalTuple c exps = do
argVals <- mapM (evalExp c) exps
funVal <- makeBox $ nTupleString (length exps)
applyIconName <- DIA.toName <$> getUniqueName "tupleApp"
applyIconName <- getUniqueName "tupleApp"
pure $ makeApplyGraph False applyIconName (fmap Right funVal) argVals (length exps)
makeVarExp :: String -> Exp
@ -314,9 +312,9 @@ evalRightSection:: EvalContext -> QOp -> Exp -> State IDState (SyntaxGraph, Name
evalRightSection c op e = do
expVal <- evalExp c e
funVal <- evalExp c (qOpToExp op)
applyIconName <- DIA.toName <$> getUniqueName "tupleApp"
applyIconName <- getUniqueName "tupleApp"
-- TODO: A better option would be for makeApplyGraph to take the list of expressions as Maybes.
neverUsedPort <- Left <$> getUniqueName "unusedArgument"
neverUsedPort <- Left <$> getUniqueString "unusedArgument"
pure $ makeApplyGraph False applyIconName funVal [(mempty, neverUsedPort), expVal] 2
-- evalEnums is only used by evalExp
@ -403,7 +401,7 @@ generalEvalLambda context patterns rhsEvalFun = do
let
patternStrings = concatMap namesInPattern patternVals
rhsContext = patternStrings <> context
lambdaPorts = map (nameAndPort lambdaName) [2,3..]
lambdaPorts = map (nameAndPort lambdaName . Port) [2,3..]
patternGraph = mconcat $ map fst patternVals
(patternEdges, newBinds) =
@ -412,11 +410,11 @@ generalEvalLambda context patterns rhsEvalFun = do
-- TODO remove coerceExpressionResult here
(rhsRawGraph, rhsResult) <- rhsEvalFun rhsContext >>= coerceExpressionResult
let
icons = toNames [(lambdaName, FunctionDefNode numParameters)]
resultIconEdge = makeSimpleEdge (rhsResult, nameAndPort lambdaName 0)
icons = [(lambdaName, FunctionDefNode numParameters)]
resultIconEdge = makeSimpleEdge (rhsResult, nameAndPort lambdaName (Port 0))
finalGraph = SyntaxGraph icons (resultIconEdge:patternEdges)
mempty newBinds
pure (deleteBindings . makeEdges $ (rhsRawGraph <> patternGraph <> finalGraph), nameAndPort lambdaName 1)
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.
-- makePatternEdges creates the edges between the patterns and the parameter ports.
@ -450,7 +448,7 @@ matchToAlt (Match srcLocation _ mtaPats _ rhs binds) = Alt srcLocation altPatter
matchesToCase :: Match -> [Match] -> State IDState Match
matchesToCase match [] = pure match
matchesToCase firstMatch@(Match srcLoc funName pats mType _ _) restOfMatches = do
tempStrings <- replicateM (length pats) (getUniqueName "_tempvar")
tempStrings <- replicateM (length pats) (getUniqueString "_tempvar")
let
tempPats = fmap (PVar . Ident) tempStrings
tempVars = fmap (Var . UnQual . Ident) tempStrings
@ -485,7 +483,7 @@ showTopLevelBinds gr@(SyntaxGraph _ _ _ binds) = do
addBind (patName, Right port) = do
uniquePatName <- getUniqueName patName
let
icons = toNames [(uniquePatName, BindNameNode patName)]
icons = [(uniquePatName, BindNameNode patName)]
edges = [makeSimpleEdge (justName uniquePatName, port)]
edgeGraph = syntaxGraphFromNodesEdges icons edges
pure edgeGraph

View File

@ -7,6 +7,7 @@ module TranslateCore(
syntaxGraphFromNodes,
syntaxGraphFromNodesEdges,
getUniqueName,
getUniqueString,
edgesForRefPortList,
combineExpressions,
--qualifyNameAndPort,
@ -29,11 +30,10 @@ import Data.Either(partitionEithers)
import qualified Data.Graph.Inductive.PatriciaTree as FGR
import Data.List(find)
import Data.Semigroup(Semigroup, (<>))
import qualified Diagrams.Prelude as DIA
import Diagrams.TwoD.GraphViz as DiaGV
import Types(Icon, SyntaxNode(..), Edge(..), EdgeOption(..),
NameAndPort(..), IDState, getId, SgNamedNode)
NameAndPort(..), IDState, getId, SgNamedNode, NodeName(..), Port(..))
import Util(noEnds, nameAndPort, makeSimpleEdge, justName, fromMaybeError, maybeBoolToBool)
import Icons(Icon(..))
@ -41,8 +41,6 @@ import Icons(Icon(..))
-- This module has the core functions and data types used by Translate.
-- This module also contains most/all of the translation functions that
-- do not require Language.Haskell.Exts.
-- * Please note that type DIA.Name is not the Name from Language.Haskell.Exts
-- used in Translate.
type Reference = Either String NameAndPort
@ -67,14 +65,18 @@ type EvalContext = [String]
type GraphAndRef = (SyntaxGraph, Reference)
type Sink = (String, NameAndPort)
syntaxGraphFromNodes :: [(DIA.Name, SyntaxNode)] -> SyntaxGraph
syntaxGraphFromNodes :: [(NodeName, SyntaxNode)] -> SyntaxGraph
syntaxGraphFromNodes icons = SyntaxGraph icons mempty mempty mempty
syntaxGraphFromNodesEdges :: [(DIA.Name, SyntaxNode)] -> [Edge] -> SyntaxGraph
syntaxGraphFromNodesEdges :: [(NodeName, SyntaxNode)] -> [Edge] -> SyntaxGraph
syntaxGraphFromNodesEdges icons edges = SyntaxGraph icons edges mempty mempty
getUniqueName :: String -> State IDState String
getUniqueName base = fmap ((base ++). show) getId
-- TODO Remove string parameter
getUniqueName :: String -> State IDState NodeName
getUniqueName _ = fmap NodeName getId
getUniqueString :: String -> State IDState String
getUniqueString base = fmap ((base ++). show) getId
-- TODO: Refactor with combineExpressions
edgesForRefPortList :: Bool -> [(Reference, NameAndPort)] -> SyntaxGraph
@ -98,11 +100,11 @@ combineExpressions inPattern portExpPairs = mconcat $ fmap makeGraph portExpPair
-- qualifyNameAndPort :: String -> NameAndPort -> NameAndPort
-- qualifyNameAndPort s (NameAndPort n p) = NameAndPort (s DIA..> n) p
makeApplyGraph :: Bool -> DIA.Name -> GraphAndRef -> [GraphAndRef] -> Int -> (SyntaxGraph, NameAndPort)
makeApplyGraph inPattern applyIconName funVal argVals numArgs = (newGraph <> combinedGraph, nameAndPort applyIconName 1)
makeApplyGraph :: Bool -> NodeName -> GraphAndRef -> [GraphAndRef] -> Int -> (SyntaxGraph, NameAndPort)
makeApplyGraph inPattern applyIconName funVal argVals numArgs = (newGraph <> combinedGraph, nameAndPort applyIconName (Port 1))
where
argumentPorts = map (nameAndPort applyIconName) [2,3..]
functionPort = nameAndPort applyIconName 0
argumentPorts = map (nameAndPort applyIconName . Port) [2,3..]
functionPort = nameAndPort applyIconName (Port 0)
combinedGraph = combineExpressions inPattern $ zip (funVal:argVals) (functionPort:argumentPorts)
icons = [(applyIconName, ApplyNode numArgs)]
newGraph = syntaxGraphFromNodes icons
@ -151,7 +153,7 @@ coerceExpressionResult (_, Left str) = makeDummyRhs str where
iconName <- getUniqueName s
let
graph = SyntaxGraph icons mempty [(s, port)] mempty
icons = [(DIA.toName iconName, BranchNode)]
icons = [(iconName, BranchNode)]
port = justName iconName
pure (graph, port)
coerceExpressionResult (g, Right x) = pure (g, x)
@ -159,8 +161,8 @@ coerceExpressionResult (g, Right x) = pure (g, x)
-- TODO: remove / change due toSyntaxGraph
makeBox :: String -> State IDState (SyntaxGraph, NameAndPort)
makeBox str = do
name <- DIA.toName <$> getUniqueName str
let graph = syntaxGraphFromNodes [(DIA.toName name, LiteralNode str)]
name <- getUniqueName str
let graph = syntaxGraphFromNodes [(name, LiteralNode str)]
pure (graph, justName name)
nTupleString :: Int -> String
@ -185,8 +187,8 @@ nodeToIcon (CaseNode n) = CaseIcon n
nodeToIcon BranchNode = BranchIcon
nodeToIcon CaseResultNode = CaseResultIcon
makeArg :: [(SgNamedNode, Edge)] -> Int -> Maybe (DIA.Name, Icon)
makeArg args port = case find (findArg port) args of
makeArg :: [(SgNamedNode, Edge)] -> Int -> Maybe (NodeName, Icon)
makeArg args port = case find (findArg (Port port)) args of
Nothing -> Nothing
Just ((argName, argSyntaxNode), _) -> Just (argName, nodeToIcon argSyntaxNode)
@ -199,11 +201,11 @@ nestedApplySyntaxNodeToIcon numArgs args = NestedApply argList where
nestedPatternNodeToIcon :: String -> Int -> [(SgNamedNode, Edge)] -> Icon
nestedPatternNodeToIcon str numArgs args = NestedPApp argList where
-- TODO Using [toName ""] is probably not the best thing to do.
-- TODO Don't use NodeName (-1)
-- TODO Don't use hardcoded port numbers
argList = Just (DIA.toName "", TextBoxIcon str) : fmap (makeArg args) [2..numArgs + 1]
argList = Just (NodeName (-1), TextBoxIcon str) : fmap (makeArg args) [2..numArgs + 1]
findArg :: Int -> (SgNamedNode, Edge) -> Bool
findArg :: Port -> (SgNamedNode, Edge) -> Bool
findArg currentPort ((argName, _), Edge _ _ (NameAndPort fromName fromPort, NameAndPort toName toPort))
| argName == fromName = maybeBoolToBool $ fmap (== currentPort) toPort
| argName == toName = maybeBoolToBool $ fmap (== currentPort) fromPort

View File

@ -3,6 +3,8 @@
module Types (
Icon(..),
SyntaxNode(..),
NodeName(..),
Port(..),
NameAndPort(..),
Connection,
Edge(..),
@ -20,7 +22,7 @@ module Types (
sgNamedNodeToSyntaxNode
) where
import Diagrams.Prelude(Name, QDiagram, V2, Any, Renderable, Path)
import Diagrams.Prelude(QDiagram, V2, Any, Renderable, Path, IsName)
import Diagrams.TwoD.Text(Text)
import Control.Monad.State(State, state)
@ -37,8 +39,8 @@ data Icon = ResultIcon | BranchIcon | TextBoxIcon String | GuardIcon Int
| PAppIcon Int String | CaseIcon Int | CaseResultIcon
| BindTextBoxIcon String
-- TODO: NestedApply should have the type NestedApply (Maybe (Name, Icon)) [Maybe (Name, Icon)]
| NestedApply [Maybe (Name, Icon)]
| NestedPApp [Maybe (Name, Icon)]
| NestedApply [Maybe (NodeName, Icon)]
| NestedPApp [Maybe (NodeName, Icon)]
deriving (Show, Eq, Ord)
-- TODO remove Ints from SyntaxNode data constructors.
@ -58,7 +60,13 @@ data SyntaxNode =
| CaseResultNode -- TODO remove caseResultNode
deriving (Show, Eq, Ord)
data NameAndPort = NameAndPort Name (Maybe Int) deriving (Show, Eq, Ord)
newtype NodeName = NodeName Int deriving (Typeable, Eq, Ord, Show)
instance IsName NodeName
newtype Port = Port Int deriving (Typeable, Eq, Ord, Show)
instance IsName Port
data NameAndPort = NameAndPort NodeName (Maybe Port) deriving (Show, Eq, Ord)
type Connection = (NameAndPort, NameAndPort)
@ -73,7 +81,7 @@ data EdgeEnd = EndAp1Result | EndAp1Arg | EndNone deriving (Show, Eq, Ord)
-- | A drawing is a map from names to Icons, a list of edges,
-- and a map of names to subDrawings
data Drawing = Drawing [(Name, Icon)] [Edge] deriving (Show, Eq)
data Drawing = Drawing [(NodeName, Icon)] [Edge] deriving (Show, Eq)
-- | IDState is an Abstract Data Type that is used as a state whose value is a unique id.
newtype IDState = IDState Int deriving (Eq, Show)
@ -85,7 +93,7 @@ type SpecialBackend b n = (SpecialNum n, Renderable (Path V2 n) b, Renderable (T
type SpecialQDiagram b n = QDiagram b V2 n Any
type SgNamedNode = (Name, SyntaxNode)
type SgNamedNode = (NodeName, SyntaxNode)
type IngSyntaxGraph gr = gr SgNamedNode Edge
sgNamedNodeToSyntaxNode :: SgNamedNode -> SyntaxNode

View File

@ -7,7 +7,6 @@ module Util (
iconToIconEnds,
--iconHeadToPort,
iconTailToPort,
toNames,
makeSimpleEdge,
noEnds,
nameAndPort,
@ -20,50 +19,47 @@ module Util (
)where
import Control.Arrow(first)
import Diagrams.Prelude(IsName, toName, Name)
-- import Diagrams.Prelude(IsName, toName, Name)
import Data.Maybe(fromMaybe)
import qualified Debug.Trace
import Types(EdgeEnd(..), Edge(..), NameAndPort(..), Connection)
import Types(EdgeEnd(..), Edge(..), NameAndPort(..), Connection, NodeName, Port)
mapFst :: Functor f => (a -> b) -> f (a, c) -> f (b, c)
mapFst f = fmap (first f)
toNames :: (IsName a) => [(a, b)] -> [(Name, b)]
toNames = mapFst toName
noEnds :: (EdgeEnd, EdgeEnd)
noEnds = (EndNone, EndNone)
makeSimpleEdge :: Connection -> Edge
makeSimpleEdge = Edge [] noEnds
nameAndPort :: IsName a => a -> Int -> NameAndPort
nameAndPort n p = NameAndPort (toName n) (Just p)
nameAndPort :: NodeName -> Port -> NameAndPort
nameAndPort n p = NameAndPort n (Just p)
justName :: IsName a => a -> NameAndPort
justName n = NameAndPort (toName n) Nothing
justName :: NodeName -> NameAndPort
justName n = NameAndPort n Nothing
-- Edge constructors --
portToPort :: (IsName a, IsName b) => a -> Int -> b -> Int -> Edge
portToPort :: NodeName -> Port -> NodeName -> Port -> Edge
portToPort a b c d = makeSimpleEdge (nameAndPort a b, nameAndPort c d)
iconToPort :: (IsName a, IsName b) => a -> b -> Int -> Edge
iconToPort :: NodeName -> NodeName -> Port -> Edge
iconToPort a c d = makeSimpleEdge (justName a, nameAndPort c d)
iconToIcon :: (IsName a, IsName b) => a -> b -> Edge
iconToIcon :: NodeName -> NodeName -> Edge
iconToIcon a c = makeSimpleEdge (justName a, justName c)
-- If there are gaps between the arrow and the icon, try switching the first two arguments
-- with the last two arguments
iconToIconEnds :: (IsName a, IsName b) => a -> EdgeEnd -> b -> EdgeEnd -> Edge
iconToIconEnds :: NodeName -> EdgeEnd -> NodeName -> EdgeEnd -> Edge
iconToIconEnds a b c d = Edge [] (b, d) (justName a, justName c)
-- iconHeadToPort :: (IsName a, IsName b) => a -> EdgeEnd -> b -> Int -> Edge
-- iconHeadToPort a endHead c d = Edge (justName a, nameAndPort c d) (EndNone, endHead)
iconTailToPort :: (IsName a, IsName b) => a -> EdgeEnd -> b -> Int -> Edge
iconTailToPort :: NodeName -> EdgeEnd -> NodeName -> Port -> Edge
iconTailToPort a endTail c d = Edge [] (endTail, EndNone) (justName a, nameAndPort c d)
fromMaybeError :: String -> Maybe a -> a

View File

@ -14,82 +14,87 @@ import Test.HUnit
import Icons(textBox, colorScheme, ColorStyle(..), coloredTextBox)
import Rendering(renderDrawing, customLayoutParams, renderIngSyntaxGraph)
import Util(toNames, portToPort, iconToPort,
import Util(portToPort, iconToPort,
iconToIconEnds, iconTailToPort)
import Types(Icon(..), Drawing(..), EdgeEnd(..), SgNamedNode, Edge(..), SyntaxNode(..), NameAndPort(..),
IngSyntaxGraph)
IngSyntaxGraph, NodeName(..), Port(..))
import Translate(translateString, stringToSyntaxGraph)
import TranslateCore(syntaxGraphToFglGraph, SyntaxGraph(..))
import GraphAlgorithms(collapseNodes)
import qualified GraphAlgorithms
iconToIntPort :: NodeName -> NodeName -> Int -> Edge
iconToIntPort x y p = iconToPort x y (Port p)
intPortToPort :: NodeName -> Int -> NodeName -> Int -> Edge
intPortToPort x1 port1 x2 port2 = portToPort x1 (Port port1) x2 (Port port2)
drawing0 :: Drawing
drawing0 = Drawing d0Icons d0Edges where
[d0A, d0B, d0Res, d0Foo, d0Bar] = ["A", "B", "res", "foo", "bar"]
d0Icons = toNames
[d0A, d0B, d0Res, d0Foo, d0Bar] = fmap NodeName [0..4] --["A", "B", "res", "foo", "bar"]
d0Icons =
[(d0A, ApplyAIcon 1),
(d0B, ApplyAIcon 1),
(d0Res, ResultIcon),
(d0Foo, TextBoxIcon d0Foo),
(d0Bar, TextBoxIcon d0Bar)
(d0Foo, TextBoxIcon "foo"),
(d0Bar, TextBoxIcon "bar")
]
d0Edges =
[
portToPort d0A 0 d0B 1,
iconToPort d0Foo d0B 0,
iconToPort d0Res d0A 1,
iconToPort d0Foo d0B 0,
iconToPort d0Bar d0B 2,
iconToPort d0Bar d0A 2
intPortToPort d0A 0 d0B 1,
iconToIntPort d0Foo d0B 0,
iconToIntPort d0Res d0A 1,
iconToIntPort d0Foo d0B 0,
iconToIntPort d0Bar d0B 2,
iconToIntPort d0Bar d0A 2
]
fG0, fOne, fEq0, fMinus1, fEq0Ap, fMinus1Ap, fTimes, fRecurAp, fTimesAp, fArg, fRes :: String
fG0, fOne, fEq0, fMinus1, fEq0Ap, fMinus1Ap, fTimes, fRecurAp, fTimesAp, fArg, fRes :: NodeName
[fG0, fOne, fEq0, fMinus1, fEq0Ap, fMinus1Ap, fTimes, fRecurAp, fTimesAp, fArg, fRes] =
["g0", "one", "eq0", "-1", "eq0Ap", "-1Ap", "*", "recurAp", "*Ap", "arg", "res"]
fmap NodeName [0..10]
-- ["g0", "one", "eq0", "-1", "eq0Ap", "-1Ap", "*", "recurAp", "*Ap", "arg", "res"]
fact0Drawing :: Drawing
fact0Drawing = Drawing fact0Icons fact0Edges where
fact0Icons = toNames
fact0Icons =
[
(fG0, GuardIcon 2),
(fOne, TextBoxIcon "1"),
(fEq0, TextBoxIcon "== 0"),
(fMinus1, TextBoxIcon fMinus1),
(fMinus1, TextBoxIcon "-1"),
(fEq0Ap, ApplyAIcon 1),
(fMinus1Ap, ApplyAIcon 1),
(fTimes, TextBoxIcon fTimes),
(fTimes, TextBoxIcon "*"),
(fRecurAp, ApplyAIcon 1),
(fTimesAp, ApplyAIcon 2),
(fArg, BranchIcon),
(fRes, ResultIcon)
]
fact0Edges = [
iconToPort fEq0 fEq0Ap 0,
portToPort fEq0Ap 1 fG0 3,
iconToPort fMinus1 fMinus1Ap 0,
iconToPort fTimes fTimesAp 0,
iconToPort fOne fG0 2,
portToPort fTimesAp 2 fG0 4,
portToPort fRecurAp 1 fTimesAp 3,
iconToPort fArg fEq0Ap 2,
iconToPort fArg fMinus1Ap 2,
iconToPort fArg fTimesAp 1,
portToPort fMinus1Ap 1 fRecurAp 2,
iconToPort fRes fG0 0
iconToIntPort fEq0 fEq0Ap 0,
intPortToPort fEq0Ap 1 fG0 3,
iconToIntPort fMinus1 fMinus1Ap 0,
iconToIntPort fTimes fTimesAp 0,
iconToIntPort fOne fG0 2,
intPortToPort fTimesAp 2 fG0 4,
intPortToPort fRecurAp 1 fTimesAp 3,
iconToIntPort fArg fEq0Ap 2,
iconToIntPort fArg fMinus1Ap 2,
iconToIntPort fArg fTimesAp 1,
intPortToPort fMinus1Ap 1 fRecurAp 2,
iconToIntPort fRes fG0 0
]
fact1Icons :: [(Name, Icon)]
fact1Icons = toNames
fact1Icons :: [(NodeName, Icon)]
fact1Icons =
[
(fG0, GuardIcon 2),
(fOne, TextBoxIcon "1"),
(fEq0, TextBoxIcon "== 0"),
(fMinus1, TextBoxIcon fMinus1),
(fTimes, TextBoxIcon fTimes),
(fMinus1, TextBoxIcon "-1"),
(fTimes, TextBoxIcon "*"),
(fRecurAp, ApplyAIcon 1),
(fTimesAp, ApplyAIcon 2),
(fArg, BranchIcon),
@ -99,15 +104,15 @@ fact1Icons = toNames
fact1Edges :: [Edge]
fact1Edges = [
iconToIconEnds fArg EndNone fEq0 EndAp1Arg,
iconTailToPort fEq0 EndAp1Result fG0 3,
iconTailToPort fEq0 EndAp1Result fG0 (Port 3),
iconToIconEnds fArg EndNone fMinus1 EndAp1Arg,
iconTailToPort fMinus1 EndAp1Result fRecurAp 2,
iconToPort fTimes fTimesAp 0,
iconToPort fOne fG0 2,
portToPort fTimesAp 1 fG0 4,
portToPort fRecurAp 1 fTimesAp 3,
iconToPort fArg fTimesAp 2,
iconToPort fRes fG0 0
iconTailToPort fMinus1 EndAp1Result fRecurAp (Port 2),
iconToIntPort fTimes fTimesAp 0,
iconToIntPort fOne fG0 2,
intPortToPort fTimesAp 1 fG0 4,
intPortToPort fRecurAp 1 fTimesAp 3,
iconToIntPort fArg fTimesAp 2,
iconToIntPort fRes fG0 0
]
fact1Drawing :: Drawing
@ -115,14 +120,14 @@ fact1Drawing = Drawing fact1Icons fact1Edges
-- fact2 is like fact1, but uses fTimesAp port 2 to distrubute the argument,
-- not fArg
fact2Icons :: [(Name, Icon)]
fact2Icons = toNames
fact2Icons :: [(NodeName, Icon)]
fact2Icons =
[
(fG0, GuardIcon 2),
(fOne, TextBoxIcon "1"),
(fEq0, TextBoxIcon "== 0"),
(fMinus1, TextBoxIcon fMinus1),
(fTimes, TextBoxIcon fTimes),
(fMinus1, TextBoxIcon "-1"),
(fTimes, TextBoxIcon "*"),
(fRecurAp, ApplyAIcon 1),
(fTimesAp, ApplyAIcon 2),
--(fArg, BranchIcon),
@ -132,17 +137,17 @@ fact2Icons = toNames
fact2Edges :: [Edge]
fact2Edges = [
--iconToIconEnds fArg EndNone fEq0 EndAp1Arg,
iconTailToPort fEq0 EndAp1Arg fTimesAp 2,
iconTailToPort fEq0 EndAp1Result fG0 3,
iconTailToPort fEq0 EndAp1Arg fTimesAp (Port 2),
iconTailToPort fEq0 EndAp1Result fG0 (Port 3),
--iconToIconEnds fArg EndNone fMinus1 EndAp1Arg,
iconTailToPort fMinus1 EndAp1Arg fTimesAp 2,
iconTailToPort fMinus1 EndAp1Result fRecurAp 2,
iconToPort fTimes fTimesAp 0,
iconToPort fOne fG0 2,
portToPort fTimesAp 1 fG0 4,
portToPort fRecurAp 1 fTimesAp 3,
--iconToPort fArg fTimesAp 2,
iconToPort fRes fG0 0
iconTailToPort fMinus1 EndAp1Arg fTimesAp (Port 2),
iconTailToPort fMinus1 EndAp1Result fRecurAp (Port 2),
iconToIntPort fTimes fTimesAp 0,
iconToIntPort fOne fG0 2,
intPortToPort fTimesAp 1 fG0 4,
intPortToPort fRecurAp 1 fTimesAp 3,
--iconToIntPort fArg fTimesAp 2,
iconToIntPort fRes fG0 0
]
fact2Drawing :: Drawing
@ -150,8 +155,8 @@ fact2Drawing = Drawing fact2Icons fact2Edges
arrowTestDrawing :: Drawing
arrowTestDrawing = Drawing arrowTestIcons arrowTestEdges where
[arr1, arr2, arr3, arr4] = ["arr1", "arr2", "arr3", "arr4"]
arrowTestIcons = toNames [
[arr1, arr2, arr3, arr4] = fmap NodeName [0..3] --["arr1", "arr2", "arr3", "arr4"]
arrowTestIcons = [
(arr1, TextBoxIcon "1"),
(arr2, TextBoxIcon "2"),
(arr3, TextBoxIcon "3"),
@ -165,39 +170,36 @@ arrowTestDrawing = Drawing arrowTestIcons arrowTestEdges where
]
nestedTestIcons :: [(Name, Icon)]
nestedTestIcons = toNames [
("n1", NestedApply args),
("t1", TextBoxIcon "T1"),
("t2", TextBoxIcon "t2")
]
where
innerArgs = [
Just (toName "_inner", TextBoxIcon "inner"),
Just (toName "t", TextBoxIcon "t"),
Nothing,
Just (toName "n2", NestedApply [Just (toName "_N2", TextBoxIcon "N2"), Nothing])
]
args = [
Just (toName "_N1", TextBoxIcon "N1"),
Nothing,
Just (toName "foo", TextBoxIcon "3"),
Just (toName "in", NestedApply innerArgs)
]
nestedTestEdges :: [Edge]
nestedTestEdges = [
iconToPort "t1" "n1" 2,
--iconToPort "t1" "in" 1,
--iconToPort "t2" ("n1" .> "in") 3,
--iconToPort "t2" ("n1" .> "in" .> "n2") 2
-- TODO This edge is not drawn currently. See todo in drawingToIconGraph in Rendering.
iconToPort "t2" "n2" 2
]
nestedTextDrawing :: Drawing
nestedTextDrawing = Drawing nestedTestIcons nestedTestEdges
nestedTextDrawing = Drawing nestedTestIcons nestedTestEdges where
[n1, t1, t2, inner, t, n2, n3, foo, in1, n4] = fmap NodeName [0..9]
nestedTestIcons = [
(n1, NestedApply args),
(t1, TextBoxIcon "T1"),
(t2, TextBoxIcon "t2")
]
where
innerArgs = [
Just (inner, TextBoxIcon "inner"),
Just (t, TextBoxIcon "t"),
Nothing,
Just (n2, NestedApply [Just (n4, TextBoxIcon "N4"), Nothing])
]
args = [
Just (n3, TextBoxIcon "n3"),
Nothing,
Just (foo, TextBoxIcon "3"),
Just (in1, NestedApply innerArgs)
]
nestedTestEdges = [
iconToIntPort t1 n1 2,
--iconToIntPort "t1" "in" 1,
--iconToIntPort "t2" ("n1" .> "in") 3,
--iconToIntPort "t2" ("n1" .> "in" .> "n2") 2
-- TODO This edge is not drawn currently. See todo in drawingToIconGraph in Rendering.
iconToIntPort t2 n2 2
]
renderTests :: IO (Diagram B)
renderTests = do
renderedDiagrams <- traverse renderDrawing allDrawings
@ -443,6 +445,7 @@ translateStringToDrawing :: String -> IO (Diagram B)
translateStringToDrawing s = do
putStrLn $ "Translating string: " ++ s
let
(drawing, decl) = translateString s
syntaxGraph = stringToSyntaxGraph s
fglGraph = syntaxGraphToFglGraph syntaxGraph
collapsedGraph = collapseNodes fglGraph
@ -463,7 +466,7 @@ translateTests :: IO (Diagram B)
translateTests = do
drawings <- traverse translateStringToDrawing testDecls
let
textDrawings = fmap (\t -> alignL $ textBox t (toName "") False mempty) testDecls
textDrawings = fmap (\t -> alignL $ textBox t (NodeName (-1)) False mempty) testDecls
vCattedDrawings = vsep 1 $ zipWith (===) (fmap alignL drawings) textDrawings
pure vCattedDrawings
@ -596,8 +599,8 @@ makeTreeRootTest (testName, expected, haskellString) = TestCase $ assertEqual te
treeRootTests :: Test
treeRootTests = TestList $ fmap makeTreeRootTest treeRootTestList where
treeRootTestList = [
("single apply", [Just (toName "app02", ApplyNode 1)], "y = f x"),
("double apply", [Just (toName "app04", ApplyNode 1)], "y = f (g x)"),
("single apply", [Just (NodeName 2, ApplyNode 1)], "y = f x"),
("double apply", [Just (NodeName 4, ApplyNode 1)], "y = f (g x)"),
-- TODO Fix this test, there is supposed to be one tree root for the "f" apply
("recursive apply", [], "y = f (g y)")
]
@ -609,6 +612,7 @@ makeChildCanBeEmbeddedTest (testName, graph, node, expected) =TestCase $ assertE
canBeEmbedded = GraphAlgorithms.nodeWillBeEmbedded graph node
-- TODO Add more cases for childCanBeEmbeddedTests
-- TODO Fix these tests
childCanBeEmbeddedTests :: Test
childCanBeEmbeddedTests = TestList $ fmap makeChildCanBeEmbeddedTest childCanBeEmbeddedList where
childCanBeEmbeddedList = [
@ -619,7 +623,10 @@ childCanBeEmbeddedTests = TestList $ fmap makeChildCanBeEmbeddedTest childCanBeE
]
collapseUnitTests :: Test
collapseUnitTests = TestList[TestLabel "findTreeRoots" treeRootTests, TestLabel "childCanBeEmbedded" childCanBeEmbeddedTests]
collapseUnitTests = TestList[
TestLabel "findTreeRoots" treeRootTests
--TestLabel "childCanBeEmbedded" childCanBeEmbeddedTests
]
main :: IO ()
--main = print "Hello world"