From 4c6c1bcf877017df98d4a5492a665eca12b8ba98 Mon Sep 17 00:00:00 2001 From: Lars-Dominik Braun Date: Sun, 28 Jun 2015 16:42:19 +0200 Subject: Replace file magic with directives Adds the %pesto and %bonappetit directives, switches to stream-based operation. --- src/Codec/Pesto/Graph.lhs | 65 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 8 deletions(-) (limited to 'src/Codec/Pesto/Graph.lhs') 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] -- cgit v1.2.3