imports { import Common.CommonTypes hiding (Dirty (..)) import Presentation.PresLayerTypes hiding (Edge) import Presentation.PresLayerUtils import Presentation.XprezLib import Presentation.XLatex hiding (bold) import Evaluation.DocumentEdit import List import Maybe import qualified Data.Map as Map import Data.Map (Map) import Control.Monad import Evaluation.DocTypes (DocumentLevel (..)) import DocTypes_Generated import DocUtils_Generated import DocumentEdit_Generated import Reducer } INCLUDE "PresentationAG_Generated.ag" { vLine'' = empty `withWidth` 2 `withVStretch` True `withbgColor` red labelYellow = (236, 236, 169) nodeBlue = (200, 255, 255) presLabel isDefined label = row [ hSpace 1, move 0 (-6) $ scaleFont (squiggle red (not isDefined) $ parsing (text label) `withbgColor` lightBlue) 60 ] } SEM EnrichedDoc | RootEnr loc.pres = structural $ @root.pres SEM Root | Root loc.pres = structural $ row [ text " " , col $ [ row [ parsing $ text @title, empty `withHStretch` True ] `withFontSize_` (percent 160) `addPopupItems` [ ("Add Section", docUpd $ insertAtHeadSection @sections.path) ] `withWidth` 800 -- , structural $ col @sections.tocPress , col [ @graph.pres , hAlignCenter $ row [ text $ "Figuur 1: " , row [ parsing $ text @caption , presLabel True @label ] ] ] , text "" , @sections.pres ] , empty `withHStretch` True ] `withFont'` ("Times New Roman", 12) -- `withWidth` 800 { divide n [] = [] divide n xs = let (h,t) = splitAt n xs in h : divide n t } SEM List_Section | List_Section loc.pres = structural $ col @elts.press SEM Section [||tocPres : Presentation_ ] | Section loc.numberStr = show @sectionNr loc.pres = structural $ (col [ vSpace 40 , col [ row [ text (@numberStr++" ") , parsing $ text @title ] `withFontSize_` (percent 150) `addPopupItems` [ ("Add Graph", docUpd $ insertAtHeadSubgraphPara @paragraphs.path) , ("Add Probtable", docUpd $ insertElementAtHead newProbtablePara @paragraphs.path) ] `withHStretch` True , @paragraphs.pres ] `addPopupItems` [ ("Add Subsection", docUpd $ insertAtHeadSubsection @subsections.path) ] , @subsections.pres `withHStretch` True -- withStretch is necessary when subsections == [] ]) `addPopupItems` [ ("Delete Section", docUpd $ deleteAtPath @lhs.path) , ("Add Section", docUpd $ addSection @lhs.path) ] lhs.tocPres = loc (Node_Section @self @lhs.path) $ structural $ presentFocus @lhs.focusD @lhs.path $ row [text (@numberStr++"."), parsing $ formatter [text @title]] `withFontSize_` (percent 130) -- don't use formatter here SEM List_Subsection | List_Subsection loc.pres = structural $ col @elts.press SEM Subsection [||] --tocPres : Presentation_ ] | Subsection loc.numberStr = show @lhs.sectionNr ++ "." ++ show @subsectionNr loc.pres = structural $ (col $ [ col [ vSpace 32 , row [ text (@numberStr++" ") , parsing $ text @title, empty `withHStretch` True ] `withFontSize_` (percent 130) `addPopupItems` [ ("Add Graph", docUpd $ insertAtHeadSubgraphPara @paragraphs.path) , ("Add Probtable", docUpd $ insertElementAtHead newProbtablePara @paragraphs.path) ] , @paragraphs.pres ] `addPopupItems` [ ("Add Subsubsection", docUpd $ insertAtHeadSubsubsection @subsubsections.path) ] , @subsubsections.pres `withHStretch` True -- withStretch is necessary when subsubsections == [] ]) `addPopupItems` [ ("Delete Subsection", docUpd $ deleteAtPath @lhs.path) , ("Add Subsection", docUpd $ addSubsection @lhs.path) ] --lhs.tocPres = loc (Node_Subsection @self @lhs.path) $ structural $ presentFocus @lhs.focusD @lhs.path $ -- row [text (@numberStr++"."), parsing $ formatter [@title.pres]] `withFontSize_` (percent 130) -- don't use formatter here SEM List_Subsubsection | List_Subsubsection loc.pres = structural $ col @elts.press SEM Subsubsection [||] --tocPres : Presentation_ ] | Subsubsection loc.numberStr = show @lhs.sectionNr ++ "." ++ show @lhs.subsectionNr ++ "."++ show @subsubsectionNr ++ ". " loc.pres = structural $ (col $ [ vSpace 25 , row [ text (@numberStr++" ") , parsing $ text @title, empty `withHStretch` True ] `withFontSize_` (percent 130) `addPopupItems` [ ("Add Graph", docUpd $ insertAtHeadSubgraphPara @paragraphs.path) , ("Add Probtable", docUpd $ insertElementAtHead newProbtablePara @paragraphs.path) ] , @paragraphs.pres ]) `addPopupItems` [ ("Delete Subsubsection", docUpd $ deleteAtPath @lhs.path) , ("Add Subsubsection", docUpd $ addSubsubsection @lhs.path) ] --lhs.tocPres = loc (Node_Subsubsection @self @lhs.path) $ structural $ presentFocus @lhs.focusD @lhs.path $ -- row [text (@numberStr++"."), text ". ", parsing $ formatter [@title.pres]] `withFontSize_` (percent 130) -- don't use formatter here SEM List_Paragraph | List_Paragraph loc.pres = parsing $ col $ if null (fromList_Paragraph @self) then [formatter [text ""]] else @elts.press -- if paragraph list is empty, we add a dummy text "" to prevent the presentation from getting height 0 -- this dummy is parsed as an empty paragraph SEM Paragraph | Paragraph loc.pres = parsing $ @words.pres `addPopupItems` [ ("Add Graph", docUpd $ addSubgraphPara @lhs.path) , ("Add Probtable", docUpd $ addElementAfter newProbtablePara @lhs.path) ] | SubgraphPara loc.pres = structural $ row [ hSpace 200, col [ @subgraph.pres , hAlignCenter $ row [ text $ "Figuur " ++ show @lhs.figureCounter ++ ": " , row [ parsing $ text @caption , presLabel True @label ] ] , vSpace 20 ] , empty `withHStretch` True ] `addPopupItems` [ ("Delete Graph", docUpd $ deleteAtPath @lhs.path) , ("Add Graph", docUpd $ addSubgraphPara @lhs.path) , ("Add Probtable", docUpd $ addElementAfter newProbtablePara @lhs.path) , ("Add Paragraph", docUpd $ addParagraph @lhs.path) ] | ProbtablePara loc.pres = structural $ row [ @probtable.pres, empty `withHStretch` True ] `addPopupItems` [ ("Delete Probtable", docUpd $ deleteAtPath @lhs.path) , ("Add Graph", docUpd $ addSubgraphPara @lhs.path) , ("Add Probtable", docUpd $ addElementAfter newProbtablePara @lhs.path) , ("Add Paragraph", docUpd $ addParagraph @lhs.path) ] SEM List_Word | List_Word loc.pres = parsing $ formatter (if null @elts.press then [text ""] else @elts.press ) `withWidth` 800 -- for an empty paragraph, we add a dummy word "" so its presentation does not get height 0 SEM Word [ || ] | Word loc.pres = parsing $ row [ StringP @idp @word, text " " ] | NodeRef loc.pres = parsing $ row [ structural $ boxed $ @nodeName.pres `withbgColor` labelYellow , text " " ] {- parsing $ row [ text "\\node{" `withColor` blue , @nodeName.pres , text "}" `withColor` blue , text " " ] -} | Label loc.pres = parsing $ row [ text ("\\label{" ++ @label++"}") `withColor` blue , text " " ] | LabelRef loc.pres = structural $ let mLabelNr = lookup @label @lhs.allLabels in row [ case mLabelNr of Nothing -> text "?" `withColor` red Just nr -> text nr `withColor` blue , presLabel (isJust mLabelNr) @label ] {- parsing $ let mLabelNr = lookup @label @lhs.allLabels in row [ text "\\ref{" `withColor` blue , case mLabelNr of Nothing -> squiggly red $ text @label Just _ -> text @label , text "}{" `withColor` blue , case mLabelNr of Nothing -> text "undefined" `withColor` red Just nr -> text nr `withColor` green , text "}" `withColor` blue , text " " ] -} SEM NodeName | NodeName loc.pres = parsing $ squiggle red (@name `notElem` @lhs.vertexNames) $ text @name `withFont'` ("Arial", 8) SEM Graph | Graph loc.pres = structural $ row [ text " " , boxed $ graph 950 650 @edges.edges @vertices.press , empty `withHStretch` True ] SEM Vertex [ || ] | Vertex loc.pres = let (nodePres,nodeOutline) = case @shape.self of Circle -> ( ellipse 18 18 Solid `withRef` (9,9) `withfColor` nodeBlue , \a -> (round $ 9*cos a , round $ -9*sin a ) ) _ -> ( rect 18 18 Solid `withRef` (9,9) `withfColor` nodeBlue , squareOutline 9 ) in structural $ (vertex @id @x @y nodeOutline $ col [ rowR 1 [glue, hRefHalf $ nodePres, glue] , vSpace 4 `withHStretch` True , rowR 1 [glue, hRefHalf $ boxed (row [ hSpace 3 , parsing $ text @name , hSpace 3 ]) `withFont'` ("Arial", 6) `withbgColor` labelYellow , glue] ]) `addPopupItems` ([ ("Circle", docUpd $ setShape @lhs.path Circle @self) , ("Square", docUpd $ setShape @lhs.path Square @self) ]) { -- probably can do without self by using select setShape :: Path -> Shape -> Vertex -> UpdateDoc Document ClipDoc setShape pth shape (Vertex name _ id x y) = pasteAt (Clip_Vertex (Vertex name shape id x y)) pth squareOutline :: Int -> Double -> (Int, Int) squareOutline r a | a < pi / 4 || a >= 7 * pi / 4 = (r-1, round $ - tan a * fromIntegral r) | a >= pi / 4 && a < 3 * pi / 4 = (round $ - tan (a - pi/2) * fromIntegral r, -r+1) | a >= 3 * pi / 4 && a < 5 * pi / 4 = (-r+1, round $ tan a * fromIntegral r) | a >= 5 * pi / 4 && a < 7 * pi / 4 = (round $ tan (a - pi/2) * fromIntegral r, r-1) } SEM Subgraph [||] | Subgraph loc.pres = let subVertices = filter (`elem` @lhs.vertexIDs) (fst . unzip $ @vertices.vertexIDNames) -- only present vertices that are in the supergraph subEdges = [ (fromV,toV) | (fromV, toV) <- @lhs.edges, fromV `elem` subVertices && toV `elem` subVertices] in structural $ (boxed $ graph 375 177 subEdges @vertices.press `addPopupItems` [ ("Add node " ++ show name, docUpd $ pasteInSubgraph @lhs.path id name @self) | (name,id) <- zip @lhs.vertexNames @lhs.vertexIDs , id `notElem` (fst . unzip $ @vertices.vertexIDNames) ]) SEM Probtable [ | | ] | Probtable loc.name = getVertexName @lhs.vertexIDs @lhs.vertexNames @id loc.pres = structural $ case lookup @id (zip @lhs.vertexIDs @lhs.vertexNames) of Nothing -> col [ row [text "Probability table for ", text "{select node}" `withbgColor` yellow] , text "" ] Just name -> col [ row [ text $ "Kanstabel voor \"" ++ @name ++"\" met waarden: " , @values.pres ] , text "" , @table.pres , text "" ] `addLocalPopupItems` [ ( "Show probtable for "++show name , docUpd $ setProbtableID @lhs.path id @self) | (name,id) <- zip @lhs.vertexNames @lhs.vertexIDs ] table.nrOfValues = length $ fromList_Value @values.self { getVertexName :: [Int] -> [String] -> Int -> String getVertexName ids names id = case lookup id (zip ids names) of Nothing -> "not found" Just name -> name setProbtableID :: Path -> Int -> Probtable -> UpdateDoc Document ClipDoc setProbtableID pth id (Probtable _ vals probs) = pasteAt (Clip_Probtable $ Probtable id vals probs) pth pasteAt :: ClipDoc -> Path -> UpdateDoc Document ClipDoc pasteAt clip pth = \(DocumentLevel d path cl) -> let (DocumentLevel d' _ _) = editPasteD (DocumentLevel d (PathD pth) clip) in (DocumentLevel d' path cl) } SEM Table [ name : String nrOfValues : Int | | ] | Table loc.groupSize = length @probs.press `div` (@lhs.nrOfValues `max` 1) loc.pres = let axesStrings = [ [ str | Value str <- fromList_Value list_Val ] | Axis list_Val <- fromList_Axis @axes.self ] valueColsFields = transpose $ products axesStrings groupedValueColsFields = map (groups @groupSize) valueColsFields groupedProbsPress = groups @groupSize @probs.press headerRow = @lhs.name : map (getVertexName @lhs.vertexIDs @lhs.vertexNames) @parents valueCols = [ (col $ hPad (text header) : hSepDouble : (concat $ intersperse [hSepDouble] $ map (\group -> intersperse hSep $ map (hPad . text) group) groups) ) | (header,groups) <- zip headerRow groupedValueColsFields ] probsCol = (col $ hPad (text "Expertschatting") : hSepDouble : (concat $ intersperse [hSepDouble] $ map (\group -> intersperse hSep $ group) groupedProbsPress) ) in structural $ boxed $ row $ (intersperse vSep $ valueCols) ++ [ vSepDouble , probsCol ] probs.totals = concat . replicate @lhs.nrOfValues . transpose . groups @groupSize $ @probs.mDoubleVals { hPad pres = row [ hSpace 4, pres, hSpace 4 ] hSep = col [ vSpace 2, hLine, vSpace 2] hSepDouble = col [ vSpace 2, hLine, vSpace 1, hLine, vSpace 2] vSep = row [ vLine ] vSepDouble = row [ vLine, vLine ] -- | return a list of all cartesian products for a list of lists -- e.g. products [[1,2],[3,4]] = [[1,3],[1,4],[2,3],[2,4]] products :: [[a]] -> [[a]] products [] = [[]] products (xs:xss) = [ x:prod | x <- xs, prod <- products xss] -- | groups splits a list into groups of given length. The -- last group might be shorter. -- Example: groups 3 [1..10] ==> [[1,2,3],[4,5,6],[7,8,9],[10]] groups :: Int -> [a] -> [[a]] groups _ [] = [] groups n xs = let (col, rest) = splitAt n xs in col: groups n rest mReadDouble :: String -> Maybe Double mReadDouble str = case reads str of [(val,"")] -> Just val _ -> Nothing } ATTR List_Probability ConsList_Probability Probability [ | | mDoubleVals USE {++} {[]} : {[Maybe Double]} ] SEM List_Probability [ totals : {[[Maybe Double]]} | | ] SEM ConsList_Probability [ totals : {[[Maybe Double]]} | | ] | Cons_Probability (head.total, tail.totals) = let (h:t) = @lhs.totals in (h,t) | Nil_Probability SEM Probability [ total : {[Maybe Double]} | | ] | Probability lhs.mDoubleVals = [@mDoubleVal] loc.mDoubleVal = mReadDouble @prob loc.pres = let totalIsOne mDoubles = case fmap sum $ sequence mDoubles of Nothing -> False Just v -> v > 0.9999 && v < 1.0001 -- True if no Nothings, and values add up to 1 squiggle = case @mDoubleVal of Nothing -> squiggly red -- Proxima parser should take care of this, -- but then we need special scanning for probs -- Alex scanner can handle this, but it hasn't been implemented Just _ -> if totalIsOne @lhs.total then id else squiggly green in parsing $ hPad $ squiggle $ text @prob `addPopupItems` case fmap sum $ sequence $ delete @mDoubleVal @lhs.total of Nothing -> [] Just v -> if v <= 1.0 then [( "Fix probability" , docUpd $ reduceDoc . pasteAt (Clip_Probability $ Probability $ show $ 1-v) @lhs.path )] else [] SEM List_Value | List_Value loc.pres = structural $ row $ [text "[" `addPopupItems` [ ("Insert value" , docUpd $ reduceDoc . insertElementAtHead newValue (@lhs.path) ) ]] ++ intersperse (text ",") (map incFail @elts.press) ++ [text "]"] { incFail pres = pres {- col [ row [ text "x", empty `withHeight` 10 `withHStretch` True, text "x" ] , pres ] -} } SEM Value | Value loc.pres = parsing $ text @val `addPopupItems` [ ("Delete value", docUpd $ reduceDoc . deleteAtPath @lhs.path) , ("Insert value after", docUpd $ reduceDoc . addElementAfter newValue @lhs.path) ] -- not used SEM List_Axis | List_Axis loc.pres = structural $ row $ [ text "[" ] ++ intersperse (text ",") @elts.press ++ [ text "]" ] -- not used SEM Axis | Axis loc.pres = structural $ @values.pres -- not used SEM List_Probability | List_Probability loc.pres = structural $ col [ hLine , row $ [vLine] ++ intersperse vLine @elts.press ++ [vLine] , hLine ] {- Graph synthesizes vertexIDNames and edges. At Root, vertexIDNames is unzipped, and inherited attributes vertexIDs, vertexNames, and edges are copied down to the subgraphs. -} SEM Root | Root (sections.vertexIDs, sections.vertexNames) = unzip @graph.vertexIDNames (probtables.vertexIDs, probtables.vertexNames) = unzip @graph.vertexIDNames sections.edges = @graph.edges -- attributes come from vertices and edges by copy rule ATTR List_Section ConsList_Section Section List_Subsection ConsList_Subsection Subsection List_Subsubsection ConsList_Subsubsection Subsubsection List_Paragraph ConsList_Paragraph Paragraph List_Word ConsList_Word Word NodeName List_Probtable ConsList_Probtable Probtable Table [ vertexIDs : {[Int]} vertexNames : {[String]} edges : {[(Int, Int)]} || ] ATTR Subgraph [ vertexIDs : {[Int]} vertexNames : {[String]} edges : {[(Int, Int)]} || ] ATTR Graph List_Edge ConsList_Edge Edge [ | | edges USE {++} {[]} : {[(Int,Int)]} ] SEM Edge | Edge lhs.edges = [(@from, @to)] ATTR Graph List_Vertex ConsList_Vertex Vertex [ | | vertexIDNames USE {++} {[]} : {[(Int,String)]} ] SEM Vertex | Vertex lhs.vertexIDNames = [(@id, @name)] { deleteAtPath :: Path -> UpdateDoc Document ClipDoc deleteAtPath pth = \(DocumentLevel d _ cl) -> editCutD (DocumentLevel d (PathD pth) cl) newParagraph = Clip_Paragraph $ Paragraph $ List_Word Nil_Word newSubgraphPara = Clip_Paragraph $ (SubgraphPara (Subgraph Dirty (toList_Vertex []) (toList_Edge [])) "caption" "label" ) newProbtablePara = Clip_Paragraph $ ProbtablePara $ Probtable (-1) (toList_Value []) $ Table [] (toList_Axis []) (toList_Probability []) newSection = Clip_Section $ Section "new" (List_Paragraph Nil_Paragraph) (List_Subsection Nil_Subsection) newSubsection = Clip_Subsection $ Subsection "new" (List_Paragraph Nil_Paragraph) (List_Subsubsection Nil_Subsubsection) newSubsubsection = Clip_Subsubsection $ Subsubsection "new" (List_Paragraph Nil_Paragraph) newValue = Clip_Value $ Value "new" addSubgraphPara path = addElementAfter newSubgraphPara path addParagraph path = addElementAfter newParagraph path addSection path = addElementAfter newSection path addSubsection path = addElementAfter newSubsection path addSubsubsection path = addElementAfter newSubsubsection path insertAtHeadSubgraphPara listPath = insertElementAtHead newSubgraphPara listPath insertAtHeadSection listPath = insertElementAtHead newSection listPath insertAtHeadSubsection listPath = insertElementAtHead newSubsection listPath insertAtHeadSubsubsection listPath = insertElementAtHead newSubsubsection listPath -- PRECONDITION: path points to a list element of the same type as clip addElementAfter :: ClipDoc -> Path -> UpdateDoc Document ClipDoc addElementAfter clip path = \(DocumentLevel d pth cl) -> (DocumentLevel (insertListD (init path) (last path+1) clip d) pth cl) -- PRECONDITION: path points to a list of elements of the same type as clip -- NB path points to the list, rather than to an element. insertElementAtHead :: ClipDoc -> Path -> UpdateDoc Document ClipDoc insertElementAtHead clip listPath = \(DocumentLevel d pth cl) -> (DocumentLevel (insertListD listPath 0 clip d) pth cl) pasteInSubgraph :: Path -> Int -> String -> Subgraph -> UpdateDoc Document clip pasteInSubgraph pth id name subgraph = let subgraph' = case subgraph of Subgraph d vs es -> Subgraph d (toList_Vertex $ Vertex name Circle id 20 20 : fromList_Vertex vs) es _ -> subgraph in \(DocumentLevel d path cl) -> let (DocumentLevel d' _ _) = editPasteD (DocumentLevel d (PathD pth) (Clip_Subgraph subgraph') ) in (DocumentLevel d' path cl) } -- Counters SEM Section [ || ] | Section loc.sectionNr = @lhs.ix + 1 SEM Subsection [ || ] | Subsection loc.subsectionNr = @lhs.ix + 1 SEM Subsubsection [ || ] | Subsubsection loc.subsubsectionNr = @lhs.ix + 1 -- counters are inherited so sub- and subsubsection titles can refer to them. ATTR List_Subsection ConsList_Subsection Subsection List_Subsubsection ConsList_Subsubsection Subsubsection [ sectionNr : Int || ] ATTR List_Subsubsection ConsList_Subsubsection Subsubsection [ subsectionNr : Int || ] -- figure counting & refs is now hard coded for graph in root. Should be done more general. -- (also see computation of @sections.allLabels) ATTR List_Section ConsList_Section Section List_Subsection ConsList_Subsection Subsection List_Subsubsection ConsList_Subsubsection Subsubsection List_Paragraph ConsList_Paragraph Paragraph [ | figureCounter : Int | ] SEM Root | Root sections.figureCounter = 2 SEM Paragraph | SubgraphPara lhs.figureCounter = @lhs.figureCounter + 1 -- labels and refs -- copy upward, taking the first label that is not Nothing SEM Word [ | | myLabel USE {use} {Nothing} : {Maybe String} ] | Label lhs.myLabel = Just @label SEM ConsList_Word List_Word Paragraph ConsList_Paragraph List_Paragraph [ | | myLabel USE {`takeFirst`} {Nothing} : {Maybe String} ] { takeFirst :: Maybe x -> Maybe x -> Maybe x takeFirst left right = case left of Just x -> Just x Nothing -> right } -- collect all labels SEM List_Section ConsList_Section Section List_Subsection ConsList_Subsection Subsection List_Subsubsection ConsList_Subsubsection Subsubsection List_Paragraph ConsList_Paragraph Paragraph [ | | labels USE {++} {[]} : {[(String,String)]} ] SEM Section | Section lhs.labels = @paragraphs.labels ++ case @paragraphs.myLabel of Just label -> (label, @numberStr) : @subsections.labels Nothing -> @subsections.labels SEM Subsection | Subsection lhs.labels = @paragraphs.labels ++ case @paragraphs.myLabel of Just label -> (label, @numberStr) : @subsubsections.labels Nothing -> @subsubsections.labels SEM Subsubsection | Subsubsection lhs.labels = @paragraphs.labels ++ case @paragraphs.myLabel of Just label -> [(label, @numberStr)] Nothing -> [] SEM Paragraph | SubgraphPara lhs.labels = [(@label, show @lhs.figureCounter)] -- the inherited attribute is allLabels, to prevent the copy rule from threading the attribute. ATTR List_Section ConsList_Section Section List_Subsection ConsList_Subsection Subsection List_Subsubsection ConsList_Subsubsection Subsubsection List_Paragraph ConsList_Paragraph Paragraph List_Word ConsList_Word Word [ allLabels : {[(String,String)]} | | ] SEM Root | Root sections.allLabels = (@label, "1") : @sections.labels -- hard-coded, not nice -- annoying bits, since we don't have any default behaviour for pres attributes: SEM Section | HoleSection lhs.tocPres = presHole @lhs.focusD "Section" (Node_HoleSection @self @lhs.path) @lhs.path | ParseErrSection lhs.tocPres = presParseErr (Node_Section @self @lhs.path) @error SEM List_Section [||tocPress: {[Presentation_]}] | List_Section lhs.tocPress = map ( loc (Node_List_Section @self @lhs.path) . presentFocus @lhs.focusD @lhs.path ) @elts.tocPress -- parent is reponsible for setting parsing/structural | HoleList_Section lhs.tocPress = [] | ParseErrList_Section lhs.tocPress = [ presParseErr (Node_List_Section @self @lhs.path) @error ] -- probably can use a USE here SEM ConsList_Section [|| tocPress:{[Presentation_]}] | Cons_Section lhs.tocPress = @head.tocPres : @tail.tocPress | Nil_Section lhs.tocPress = [] SEM Edge | Edge loc.pres = empty SEM Shape | Circle loc.pres = empty | Square loc.pres = empty SEM Dirty | Dirty loc.pres = empty | Clean loc.pres = empty SEM List_Edge | List_Edge loc.pres = empty SEM List_Vertex | List_Vertex loc.pres = empty SEM List_Probtable | List_Probtable loc.pres = empty