summaryrefslogtreecommitdiff
path: root/src/Codec/Pesto/Graph.lhs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Codec/Pesto/Graph.lhs')
-rw-r--r--src/Codec/Pesto/Graph.lhs65
1 files changed, 57 insertions, 8 deletions
diff --git a/src/Codec/Pesto/Graph.lhs b/src/Codec/Pesto/Graph.lhs
index 4ea2886..7376c5f 100644
--- a/src/Codec/Pesto/Graph.lhs
+++ b/src/Codec/Pesto/Graph.lhs
@@ -11,18 +11,56 @@ Language semantics
> , firstNodeId
> , resolveReferences
> , test
+> , extract
> ) where
> import Data.Char (isSpace, toLower, isLetter)
> import Data.List (sort, nub)
> import Test.HUnit hiding (test)
+> import Control.Applicative ((<$>))
>
> import Codec.Pesto.Parse hiding (test)
-Pesto’s syntax drives a stack-based machine that transforms the linear stream
-of operations generated by the parser into a directed graph. Think of the stack
-as your kitchen’s workspace that is used to prepare the food’s
-components. You can add new ingredients, perform actions on them, put them
-aside and add them again.
+The parser’s output, a stream of operations, may contain multiple recipes. A
+recipe must start with the directive “pesto” and may end with “bonappetit”.
+This function extracts all recipes from the stream and removes both directives.
+
+- easily embed recipes into other documents
+
+> extract [] = []
+> extract (Directive "pesto":stream) = between:extract next
+> where
+> isEnd (Directive x) | x `elem` ["bonappetit", "pesto"] = True
+> isEnd _ = False
+> (between, next) = break isEnd stream
+> extract (x:xs) = extract xs
+
+Start and end directive are removed from the extracted operations. The
+directive “bonappetit” is optional at the end of a stream.
+
+> testExtract = [
+> extract [Directive "pesto", Directive "bonappetit"] ~?= [[]]
+> , extract [Directive "pesto", Action "foobar", Directive "bonappetit"] ~?= [[Action "foobar"]]
+> , extract [Directive "pesto"] ~?= [[]]
+> , extract [Directive "pesto", Directive "foobar"] ~?= [[Directive "foobar"]]
+
+Operations surrounding the start and end directive are removed.
+
+> , extract [Unknown "Something", Directive "pesto"] ~?= [[]]
+> , extract [Unknown "Something", Action "pour", Directive "pesto"] ~?= [[]]
+> , extract [Directive "pesto", Directive "bonappetit", Annotation "something"] ~?= [[]]
+
+The stream may contain multiple recipes. The start directive also ends the
+previous recipe and starts a new one.
+
+> , extract [Directive "pesto", Action "pour", Directive "bonappetit", Action "foobar", Directive "pesto", Annotation "something"] ~?= [[Action "pour"], [Annotation "something"]]
+> , extract [Directive "pesto", Action "heat", Directive "pesto", Annotation "something"] ~?= [[Action "heat"], [Annotation "something"]]
+> , extract [Directive "pesto", Annotation "foobar", Directive "pesto", Directive "bonappetit"] ~?= [[Annotation "foobar"], []]
+> ]
+
+Each recipe’s stream of operations drives a stack-based machine that transforms
+it into a directed graph. Think of the stack as your kitchen’s workspace that
+is used to prepare the food’s components. You can add new ingredients, perform
+actions on them, put them aside and add them again.
This function processes a list of nodes, that is operations uniquely identified
by an integer and returns the edges of the directed graph as a list of tuples.
@@ -74,6 +112,12 @@ used to provide more information about ingredients (so “hot water” becomes
> f ctx@(Nothing, s, edges) (_, Annotation _) = ctx
> f (Just prev, s, edges) (i, Annotation _) = (Just prev, s, (i, prev):edges)
+Unused directives or unknown operations are danging nodes with no connection to
+other nodes.
+
+> f ctx (_, Directive _) = ctx
+> f ctx (_, Unknown _) = ctx
+
These are helper functions:
> addToStack (_, stack:sx, edges) i = (Just i, (i:stack):sx, edges)
@@ -126,6 +170,11 @@ to the same node.
> , cmpGraph "+foobar >barbaz (C)" [(0, 1), (2, 1)]
> , cmpGraph "+foobar |barbaz (C)" [(0, 1), (2, 1)]
> , cmpGraph "*foobar (C)" [(1, 0)]
+
+Unknown directives or operations are never connected to other nodes.
+
+> , cmpGraph "%invalid" []
+> , cmpGraph "invalid" []
> ]
References
@@ -183,8 +232,8 @@ Appendix
> runGraphWith f doc expect = sort edges ~?= sort expect
> where
-> (Right op) = parse ("%pesto-1 " ++ doc)
-> nodes = (zip [firstNodeId..] . map snd . operations) op
+> (Right op) = (head . extract . snd . unzip) <$> parse ("%pesto " ++ doc)
+> nodes = zip [firstNodeId..] op
> edges = f nodes
> cmpGraph = runGraphWith toGraph
> cmpGraphRef = runGraphWith resolveReferences
@@ -202,5 +251,5 @@ Get all nodes with edges pointing towards nodeid
> outgoing edges (nodeid, _) = filter ((==) nodeid . fst) edges
-> test = ["graph" ~: testGraph, "ref" ~: testRef]
+> test = ["graph" ~: testGraph, "ref" ~: testRef, "extract" ~: testExtract]