symantic-grammar 0.2.0.20170709 → 0.3.0.20180213
raw patch · 11 files changed
+244/−214 lines, 11 filesdep ~megaparsecdep ~tasty-hunitdep ~textPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: megaparsec, tasty-hunit, text, transformers
API changes (from Hackage documentation)
- Language.Symantic.Grammar.ContextFree: comment_block :: Gram_Comment g => CF g String -> Reg lr g String -> CF g String
- Language.Symantic.Grammar.ContextFree: comment_line :: Gram_Comment g => CF g String -> CF g String
- Language.Symantic.Grammar.ContextFree: instance Language.Symantic.Grammar.Terminal.Gram_Terminal g => Language.Symantic.Grammar.Terminal.Gram_Terminal (Language.Symantic.Grammar.ContextFree.CF g)
- Language.Symantic.Grammar.Regular: instance Language.Symantic.Grammar.Terminal.Gram_Terminal g => Language.Symantic.Grammar.Terminal.Gram_Terminal (Language.Symantic.Grammar.Regular.Reg lr g)
- Language.Symantic.Grammar.Terminal: class Gram_Terminal g
- Language.Symantic.Grammar.Terminal: instance Language.Symantic.Grammar.Terminal.Gram_Terminal Language.Symantic.Grammar.EBNF.EBNF
- Language.Symantic.Grammar.Terminal: instance Language.Symantic.Grammar.Terminal.Gram_Terminal Language.Symantic.Grammar.EBNF.RuleEBNF
- Language.Symantic.Grammar.Terminal: instance Language.Symantic.Grammar.Terminal.Gram_Terminal g => Language.Symantic.Grammar.Terminal.Gram_Terminal (Language.Symantic.Grammar.Terminal.Terminal g)
+ Language.Symantic.Grammar.ContextFree: commentBlock :: Gram_Comment g => CF g String -> Reg lr g String -> CF g String
+ Language.Symantic.Grammar.ContextFree: commentLine :: Gram_Comment g => CF g String -> CF g String
+ Language.Symantic.Grammar.ContextFree: instance Language.Symantic.Grammar.Terminal.Gram_Char g => Language.Symantic.Grammar.Terminal.Gram_Char (Language.Symantic.Grammar.ContextFree.CF g)
+ Language.Symantic.Grammar.ContextFree: instance Language.Symantic.Grammar.Terminal.Gram_String g => Language.Symantic.Grammar.Terminal.Gram_String (Language.Symantic.Grammar.ContextFree.CF g)
+ Language.Symantic.Grammar.Regular: instance Language.Symantic.Grammar.Terminal.Gram_Char g => Language.Symantic.Grammar.Terminal.Gram_Char (Language.Symantic.Grammar.Regular.Reg lr g)
+ Language.Symantic.Grammar.Regular: instance Language.Symantic.Grammar.Terminal.Gram_String g => Language.Symantic.Grammar.Terminal.Gram_String (Language.Symantic.Grammar.Regular.Reg lr g)
+ Language.Symantic.Grammar.Terminal: class Gram_Rule g => Gram_Char g
+ Language.Symantic.Grammar.Terminal: class Functor g => Gram_String g
+ Language.Symantic.Grammar.Terminal: eol :: Gram_Char g => g Char
+ Language.Symantic.Grammar.Terminal: instance Language.Symantic.Grammar.Terminal.Gram_Char Language.Symantic.Grammar.EBNF.EBNF
+ Language.Symantic.Grammar.Terminal: instance Language.Symantic.Grammar.Terminal.Gram_Char Language.Symantic.Grammar.EBNF.RuleEBNF
+ Language.Symantic.Grammar.Terminal: instance Language.Symantic.Grammar.Terminal.Gram_Char g => Language.Symantic.Grammar.Terminal.Gram_Char (Language.Symantic.Grammar.Terminal.Terminal g)
+ Language.Symantic.Grammar.Terminal: instance Language.Symantic.Grammar.Terminal.Gram_String Language.Symantic.Grammar.EBNF.EBNF
+ Language.Symantic.Grammar.Terminal: instance Language.Symantic.Grammar.Terminal.Gram_String Language.Symantic.Grammar.EBNF.RuleEBNF
+ Language.Symantic.Grammar.Terminal: instance Language.Symantic.Grammar.Terminal.Gram_String g => Language.Symantic.Grammar.Terminal.Gram_String (Language.Symantic.Grammar.Terminal.Terminal g)
+ Language.Symantic.Grammar.Terminal: space :: Gram_Char g => g Char
+ Language.Symantic.Grammar.Terminal: text :: Gram_String g => Text -> g Text
+ Language.Symantic.Grammar.Terminal: textLazy :: Gram_String g => Text -> g Text
- Language.Symantic.Grammar.ContextFree: class (Gram_Alt g, Gram_App g) => Gram_AltApp g where option x g = g <+> pure x optional v = Just <$> v <+> pure Nothing manyFoldL e f a = someFoldL e f a <+> pure e someFoldL e f a = f <$> a <*> manyFoldL e f a many = fmap reverse . manyFoldL [] (:) some = fmap reverse . someFoldL [] (:) manySkip = void . many someSkip = void . some inside f begin in_ end next = (f <$ begin <*> in_ <* end) <+> next
+ Language.Symantic.Grammar.ContextFree: class (Gram_Alt g, Gram_App g) => Gram_AltApp g
- Language.Symantic.Grammar.ContextFree: class Applicative g => Gram_App g where between open close g = open *> g <* close
+ Language.Symantic.Grammar.ContextFree: class Applicative g => Gram_App g
- Language.Symantic.Grammar.ContextFree: class (Gram_Terminal g, Gram_Rule g, Gram_Alt g, Gram_App g, Gram_AltApp g, Gram_CF g) => Gram_Comment g where commentable = rule3 "commentable" $ \ space line block -> manySkip $ choice [space, line, block] comment_line prefix = rule "comment_line" $ prefix *> many (any `minus` (void (char '\n') <+> eoi)) comment_block begin end = rule "comment_block" $ begin *> many (any `minus` end) <* cfOf end lexeme = rule1 "lexeme" $ \ g -> g <* commentable (void $ string " " <+> string "\n\ \ ") (void $ comment_line (string "--")) (void $ comment_block (string "{-") (string "-}")) parens = rule1 "parens" $ between (lexeme $ char '(') (lexeme $ char ')') symbol = lexeme . string
+ Language.Symantic.Grammar.ContextFree: class (Gram_Char g, Gram_String g, Gram_Rule g, Gram_Alt g, Gram_App g, Gram_AltApp g, Gram_CF g) => Gram_Comment g
- Language.Symantic.Grammar.EBNF: class Gram_Rule g where rule _n = id rule1 _n g = g rule2 _n g = g rule3 _n g = g rule4 _n g = g
+ Language.Symantic.Grammar.EBNF: class Gram_Rule g
- Language.Symantic.Grammar.Meta: class (Gram_Reader (Source_Input src) g, SourceInj (Span (Source_Input src)) src) => Gram_Source src g where source g = askAfter $ askBefore $ (\ f (beg :: Source_Input src) (end :: Source_Input src) -> f (sourceInj $ Span beg end :: src)) <$> g
+ Language.Symantic.Grammar.Meta: class (Gram_Reader (Source_Input src) g, SourceInj (Span (Source_Input src)) src) => Gram_Source src g
- Language.Symantic.Grammar.Meta: class Gram_State st g where getBefore g = stateBefore ((\ f st -> (st, f st)) <$> g) getAfter g = stateAfter ((\ f st -> (st, f st)) <$> g) put g = stateAfter ((\ (st, a) -> const (st, a)) <$> g)
+ Language.Symantic.Grammar.Meta: class Gram_State st g
- Language.Symantic.Grammar.Operators: class (Gram_Terminal g, Gram_Rule g, Gram_Alt g, Gram_Try g, Gram_App g, Gram_AltApp g, Gram_CF g) => Gram_Op g where operators g prefixG infixG postfixG = (evalOpTree <$>) <$> go g prefixG infixG postfixG where go :: CF g a -> CF g (Unifix, a -> a) -> CF g (Infix, a -> a -> a) -> CF g (Unifix, a -> a) -> CF g (Either Error_Fixity (OpTree a)) go = rule4 "operators" $ \ aG preG inG postG -> (\ pres a posts -> let nod_a = foldr insertUnifix (foldl' (flip insertUnifix) (OpTree0 a) posts) pres in \case { Just (in_, b) -> insertInfix nod_a in_ b Nothing -> Right nod_a }) <$> many (try preG) <*> aG <*> many (try postG) <*> option Nothing (curry Just <$> try inG <*> go aG preG inG postG) infixrG = rule2 "infixr" $ \ g opG -> (\ a -> \case { Just (op, b) -> a `op` b Nothing -> a }) <$> g <*> option Nothing (try $ curry Just <$> opG <*> infixrG g opG) infixlG = rule2 "infixl" $ \ g opG -> ($ id) <$> go g opG where go :: CF g a -> CF g (a -> a -> a) -> CF g ((a -> a) -> a) go g opG = (\ a -> \case { Just (op, kb) -> \ k -> kb (k a `op`) Nothing -> ($ a) }) <$> g <*> option Nothing (try $ curry Just <$> opG <*> go g opG)
+ Language.Symantic.Grammar.Operators: class (Gram_Char g, Gram_String g, Gram_Rule g, Gram_Alt g, Gram_Try g, Gram_App g, Gram_AltApp g, Gram_CF g) => Gram_Op g
- Language.Symantic.Grammar.Regular: class Gram_Alt g where choice = foldr (<+>) empty
+ Language.Symantic.Grammar.Regular: class Gram_Alt g
- Language.Symantic.Grammar.Regular: class (Functor g, Gram_Alt g) => Gram_RegL g where manyL g' = reverse <$> go g' where go g = flip (:) <$> go g <*. g <+> empty someL g = (\ cs c -> cs ++ [c]) <$> manyL g <*. g
+ Language.Symantic.Grammar.Regular: class (Functor g, Gram_Alt g) => Gram_RegL g
- Language.Symantic.Grammar.Regular: class (Functor g, Gram_Alt g) => Gram_RegR g where manyR g = (:) <$> g .*> manyR g <+> empty someR g = (:) <$> g .*> manyR g
+ Language.Symantic.Grammar.Regular: class (Functor g, Gram_Alt g) => Gram_RegR g
- Language.Symantic.Grammar.Regular: type RegL = Reg SideL
+ Language.Symantic.Grammar.Regular: type RegL = Reg 'SideL
- Language.Symantic.Grammar.Regular: type RegR = Reg SideR
+ Language.Symantic.Grammar.Regular: type RegR = Reg 'SideR
- Language.Symantic.Grammar.Terminal: any :: Gram_Terminal g => g Char
+ Language.Symantic.Grammar.Terminal: any :: Gram_Char g => g Char
- Language.Symantic.Grammar.Terminal: but :: Gram_Terminal g => Terminal g Char -> Terminal g Char -> Terminal g Char
+ Language.Symantic.Grammar.Terminal: but :: Gram_Char g => Terminal g Char -> Terminal g Char -> Terminal g Char
- Language.Symantic.Grammar.Terminal: char :: Gram_Terminal g => Char -> g Char
+ Language.Symantic.Grammar.Terminal: char :: Gram_Char g => Char -> g Char
- Language.Symantic.Grammar.Terminal: eoi :: Gram_Terminal g => g ()
+ Language.Symantic.Grammar.Terminal: eoi :: Gram_Char g => g ()
- Language.Symantic.Grammar.Terminal: range :: Gram_Terminal g => (Char, Char) -> g Char
+ Language.Symantic.Grammar.Terminal: range :: Gram_Char g => (Char, Char) -> g Char
- Language.Symantic.Grammar.Terminal: string :: Gram_Terminal g => String -> g String
+ Language.Symantic.Grammar.Terminal: string :: Gram_String g => String -> g String
- Language.Symantic.Grammar.Terminal: unicat :: Gram_Terminal g => Unicat -> g Char
+ Language.Symantic.Grammar.Terminal: unicat :: Gram_Char g => Unicat -> g Char
Files
- Language/Symantic/Grammar/ContextFree.hs +17/−16
- Language/Symantic/Grammar/EBNF.hs +1/−3
- Language/Symantic/Grammar/Fixity.hs +1/−2
- Language/Symantic/Grammar/Operators.hs +3/−3
- Language/Symantic/Grammar/Regular.hs +1/−1
- Language/Symantic/Grammar/Terminal.hs +40/−24
- Language/Symantic/Grammar/Test.hs +0/−113
- stack.yaml +3/−0
- symantic-grammar.cabal +60/−52
- test/HUnit.hs +108/−0
- test/Main.hs +10/−0
Language/Symantic/Grammar/ContextFree.hs view
@@ -17,7 +17,7 @@ -- * Type 'CF' -- | Context-free grammar. newtype CF g a = CF { unCF :: g a }- deriving (IsString, Functor, Gram_Terminal, Applicative, Gram_App)+ deriving (IsString, Functor, Gram_Char, Gram_String, Applicative, Gram_App) deriving instance Gram_Error err g => Gram_Error err (CF g) deriving instance Gram_Reader st g => Gram_Reader st (CF g) deriving instance Gram_State st g => Gram_State st (CF g)@@ -111,7 +111,8 @@ -- * Class 'Gram_Comment' -- | Symantics for handling comments after each 'lexeme'. class- ( Gram_Terminal g+ ( Gram_Char g+ , Gram_String g , Gram_Rule g , Gram_Alt g , Gram_App g@@ -119,22 +120,22 @@ , Gram_CF g ) => Gram_Comment g where commentable :: g () -> g () -> g () -> g ()- commentable = rule3 "commentable" $ \space line block ->- manySkip $ choice [space, line, block]- comment_line :: CF g String -> CF g String- comment_line prefix = rule "comment_line" $- prefix *> many (any `minus` (void (char '\n') <+> eoi))- comment_block :: CF g String -> Reg lr g String -> CF g String- comment_block begin end = rule "comment_block" $+ commentable = rule3 "Commentable" $ \sp line block ->+ manySkip $ choice [sp, line, block]+ commentLine :: CF g String -> CF g String+ commentLine prefix = rule "CommentLine" $+ prefix *> many (any `minus` (void eol <+> eoi))+ commentBlock :: CF g String -> Reg lr g String -> CF g String+ commentBlock begin end = rule "CommentBlock" $ begin *> many (any `minus` end) <* cfOf end lexeme :: CF g a -> CF g a- lexeme = rule1 "lexeme" $ \g ->+ lexeme = rule1 "Lexeme" $ \g -> g <* commentable- (void $ string " " <+> string "\n ")- (void $ comment_line (string "--"))- (void $ comment_block (string "{-") (string "-}"))+ (void $ space <+> (eol *> space))+ (void $ commentLine (string "--"))+ (void $ commentBlock (string "{-") (string "-}")) parens :: CF g a -> CF g a- parens = rule1 "parens" $+ parens = rule1 "Parens" $ between (lexeme $ char '(') (lexeme $ char ')')@@ -147,8 +148,8 @@ gram_comment :: forall g. (Gram_Comment g, Gram_RuleEBNF g) => [CF g ()] gram_comment = [ void $ commentable (void $ argEBNF "space") (void $ argEBNF "line") (void $ argEBNF "block")- , void $ comment_line (argEBNF "prefix")- , void $ comment_block (argEBNF "begin") (argEBNF "end" :: RegL g String)+ , void $ commentLine (argEBNF "prefix")+ , void $ commentBlock (argEBNF "begin") (argEBNF "end" :: RegL g String) , void $ lexeme (argEBNF "g") , void $ parens (argEBNF "g") , void $ inside id (argEBNF "begin") (argEBNF "in") (argEBNF "end") (argEBNF "next")
Language/Symantic/Grammar/EBNF.hs view
@@ -1,10 +1,8 @@ module Language.Symantic.Grammar.EBNF where import Control.Applicative (Applicative(..))-import Control.Monad-import Data.Semigroup hiding (option)+import Data.Semigroup import Data.Text (Text)-import Prelude hiding (any) import qualified Data.Text as Text import Language.Symantic.Grammar.Meta
Language/Symantic/Grammar/Fixity.hs view
@@ -1,9 +1,8 @@ module Language.Symantic.Grammar.Fixity where import Data.Bool as Bool-import Data.Semigroup hiding (option)+import Data.Semigroup import Data.String (IsString(..))-import Prelude hiding (any) -- * Type 'Fixity' data Fixity
Language/Symantic/Grammar/Operators.hs view
@@ -4,8 +4,7 @@ import Control.Applicative (Applicative(..)) import Control.Monad (void)-import Data.Foldable hiding (any)-import Prelude hiding (any)+import Data.Foldable import Language.Symantic.Grammar.Fixity import Language.Symantic.Grammar.EBNF@@ -16,7 +15,8 @@ -- * Class 'Gram_Op' -- | Symantics for operators. class- ( Gram_Terminal g+ ( Gram_Char g+ , Gram_String g , Gram_Rule g , Gram_Alt g , Gram_Try g
Language/Symantic/Grammar/Regular.hs view
@@ -13,7 +13,7 @@ -- * Type 'Reg' -- | Left or right regular grammar. newtype Reg (lr::Side) g a = Reg { unReg :: g a }- deriving (IsString, Functor, Gram_Terminal)+ deriving (IsString, Functor, Gram_Char, Gram_String) deriving instance Gram_Alt g => Gram_Alt (Reg lr g) deriving instance Gram_Try g => Gram_Try (Reg lr g) deriving instance Gram_Rule g => Gram_Rule (Reg lr g)
Language/Symantic/Grammar/Terminal.hs view
@@ -2,14 +2,13 @@ -- | Symantics for terminal grammars. module Language.Symantic.Grammar.Terminal where -import Control.Monad import Data.Semigroup (Semigroup(..)) import Data.String (IsString(..))-import Prelude hiding (any) import qualified Data.Bool as Bool import qualified Data.Char as Char import qualified Data.List as List import qualified Data.Text as Text+import qualified Data.Text.Lazy as TL import Language.Symantic.Grammar.Fixity import Language.Symantic.Grammar.EBNF@@ -18,51 +17,42 @@ -- | Terminal grammar. newtype Terminal g a = Terminal { unTerminal :: g a }- deriving (Functor, Gram_Terminal)+ deriving (Functor, Gram_Char, Gram_String) deriving instance Gram_Rule g => Gram_Rule (Terminal g) --- ** Class 'Gram_Terminal'+-- ** Class 'Gram_Char' -- | Symantics for terminal grammars.-class Gram_Terminal g where+class Gram_Rule g => Gram_Char g where any :: g Char but :: Terminal g Char -> Terminal g Char -> Terminal g Char eoi :: g ()+ eol :: g Char+ space :: g Char char :: Char -> g Char- string :: String -> g String unicat :: Unicat -> g Char range :: (Char, Char) -> g Char- -- string = foldr (\c -> (<*>) ((:) <$> char c)) (pure "")- -- string [] = pure []- -- string (c:cs) = (:) <$> char c <*> string cs-deriving instance Gram_Terminal RuleEBNF-instance Gram_Terminal EBNF where+ eol = rule "NewLine" $ char '\n'+ space = rule "Space" $ char ' '+deriving instance Gram_Char RuleEBNF+instance Gram_Char EBNF where any = ebnf_const "_" Terminal (EBNF f) `but` Terminal (EBNF g) = Terminal $ EBNF $ \bo po -> parenInfix po op $ f bo (op, SideL) <> " - " <> g bo (op, SideR) where op = infixL 6- eoi = ebnf_const "eoi"- char = ebnf_const . escape+ eoi = ebnf_const "eoi"+ eol = ebnf_const "↵"+ space = ebnf_const "␣"+ char = ebnf_const . escape where escape c | Char.isPrint c && c /= '"' = Text.concat $ ["\"", Text.singleton c, "\""] escape c = Text.concat ["U+", Text.pack $ show $ Char.ord c]- string s =- case List.break (\c -> Bool.not (Char.isPrint c) || c == '"') s of- (ps, "") -> raw ps- ("", [c]) -> "" <$ char c- (ps, [c]) -> "" <$ raw ps <* char c- ("", c:rs) -> "" <$ char c <* string rs- (ps, c:rs) -> "" <$ raw ps <* char c <* string rs- where- raw cs = ebnf_const $ Text.concat $ ["\"", Text.pack cs, "\""] unicat = ebnf_const . Text.pack . show range (l, h) = ebnf_const $ Text.concat [ runEBNF $ char l , "…" , runEBNF $ char h ]-instance IsString (EBNF String) where- fromString = string -- *** Type 'Unicat' -- | Unicode category.@@ -109,3 +99,29 @@ , Char.OtherSymbol ] Unicat cat -> [cat]++-- ** Class 'Gram_String'+class Functor g => Gram_String g where+ string :: String -> g String+ {-+ string = foldr (\c -> (<*>) ((:) <$> char c)) (pure "")+ string [] = pure []+ string (c:cs) = (:) <$> char c <*> string cs+ -}+ text :: Text.Text -> g Text.Text+ textLazy :: TL.Text -> g TL.Text+ text t = Text.pack <$> string (Text.unpack t)+ textLazy t = TL.pack <$> string (TL.unpack t)+deriving instance Gram_String RuleEBNF+instance Gram_String EBNF where+ string s =+ case List.break (\c -> Bool.not (Char.isPrint c) || c == '"') s of+ (ps, "") -> raw ps+ ("", [c]) -> "" <$ char c+ (ps, [c]) -> "" <$ raw ps <* char c+ ("", c:rs) -> "" <$ char c <* string rs+ (ps, c:rs) -> "" <$ raw ps <* char c <* string rs+ where+ raw cs = ebnf_const $ Text.concat $ ["\"", Text.pack cs, "\""]+instance IsString (EBNF String) where+ fromString = string
− Language/Symantic/Grammar/Test.hs
@@ -1,113 +0,0 @@-{-# LANGUAGE ConstraintKinds #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}-module Test where--import Test.Tasty-import Test.Tasty.HUnit--import Control.Applicative (Applicative(..))-import Control.Monad-import Data.Semigroup ((<>))-import Data.String (IsString(..))-import Prelude hiding (any, (^), exp)-import qualified Control.Applicative as Gram_AltApp-import qualified Data.Char as Char-import qualified Data.Text as Text-import qualified Text.Megaparsec as P--import Language.Symantic.Grammar---- * Type 'ParsecT'-type ParsecC e s = (P.Token s ~ Char, P.Stream s, P.ErrorComponent e)-instance ParsecC e s => IsString (P.ParsecT e s m [Char]) where- fromString = P.string-instance ParsecC e s => Gram_Rule (P.ParsecT e s m) where- rule = P.label . Text.unpack-instance ParsecC e s => Gram_Terminal (P.ParsecT e s m) where- any = P.anyChar- eoi = P.eof- char = P.char- string = P.string- unicat cat = P.satisfy $ (`elem` cats) . Char.generalCategory- where cats = unicode_categories cat- range (l, h) = P.satisfy $ \c -> l <= c && c <= h- but (Terminal f) (Terminal p) = Terminal $ P.notFollowedBy (P.try p) *> f-instance ParsecC e s => Gram_Alt (P.ParsecT e s m) where- empty = Gram_AltApp.empty- (<+>) = (Gram_AltApp.<|>)- choice = P.choice-instance ParsecC e s => Gram_Try (P.ParsecT e s m) where- try = P.try-instance ParsecC e s => Gram_RegR (P.ParsecT e s m) where- Terminal f .*> Reg x = Reg $ f <*> x-instance ParsecC e s => Gram_RegL (P.ParsecT e s m) where- Reg f <*. Terminal x = Reg $ f <*> x-instance ParsecC e s => Gram_App (P.ParsecT e s m)-instance ParsecC e s => Gram_AltApp (P.ParsecT e s m)-instance ParsecC e s => Gram_CF (P.ParsecT e s m) where- CF f <& Reg p = CF $ P.lookAhead f <*> p- Reg f &> CF p = CF $ P.lookAhead f <*> p- CF f `minus` Reg p = CF $ P.notFollowedBy (P.try p) *> f-instance ParsecC e s => Gram_Comment (P.ParsecT e s m)--elide :: Text.Text -> String-elide s | Text.length s > 42 = take 42 (Text.unpack s) <> ['…']-elide s = Text.unpack s--tests :: TestTree-tests = testGroup "Grammar"- [ testGroup "Terminal" $- let (==>) inp exp =- testCase (elide exp) $- runEBNF (unTerminal (void inp)) @?= exp- ; infix 1 ==> in- [ string "" ==> "\"\""- , string "abé\"to" ==> "\"abé\", U+34, \"to\""- , string "\"" ==> "U+34"- , range ('a', 'z') ==> "\"a\"…\"z\""- , unicat Unicat_Letter ==> "Unicat_Letter"- , unicat (Unicat Char.LowercaseLetter) ==> "Unicat LowercaseLetter"- ]- , testGroup "Reg" $- let (==>) inp exp =- testCase (elide exp) $- runEBNF (unReg (void inp)) @?= exp- ; infix 1 ==> in- [ (<>) <$> string "0" .*> someR (char '1') ==> "\"0\", {\"1\"}-"- , (<>) <$> someL (char '1') <*. string "0" ==> "{\"1\"}-, \"0\""- ]- , testGroup "CF" $- let (==>) inp exp =- testCase (elide exp) $- runEBNF (unCF (void inp)) @?= exp- ; infix 1 ==> in- [ (<>) <$> string "0" <*> string "1" ==> "\"0\", \"1\""- , (<>) <$> string "0" <* string "X" <*> string "1" ==> "\"0\", \"X\", \"1\""- , (<>) <$> (string "0" <+> string "1") <*> string "2" ==> "(\"0\" | \"1\"), \"2\""- , (<>) <$> string "0" <*> (string "1" <+> string "2") ==> "\"0\", (\"1\" | \"2\")"- , string "0" <+> string "1" <+> string "2" ==> "\"0\" | \"1\" | \"2\""- , choice [string "0", string "1", string "2"] ==> "\"0\" | \"1\" | \"2\""- , (<>) <$> choice- [ (<>) <$> string "0" <*> string "1"- , string "2" <+> string "3"- , string "4"- ] <*> string "5" ==> "(\"0\", \"1\" | \"2\" | \"3\" | \"4\"), \"5\""- , concat <$> many (string "0") ==> "{\"0\"}"- , () <$ char 'a' <* char 'b' <* char 'c' ==> "\"a\", \"b\", \"c\""- ,let g0 = (<>) <$> string "0" .*> someR (char '1') in- (<>) <$> string "0" <& g0 ==> "\"0\" & \"0\", {\"1\"}-"- ,let g0 = (<>) <$> string "0" .*> someR (char '1') in- let g1 = (<>) <$> someL (char '1') <*. string "0" in- string "0" `minus` g0 `minus` g1 ==>- "\"0\" - \"0\", {\"1\"}- - {\"1\"}-, \"0\""- , (<>)- <$> many (string "0" <+> string "1")- <*> some (string "2") ==> "{\"0\" | \"1\"}, {\"2\"}-"- ]- ]--main :: IO ()-main =- defaultMain $- testGroup "Language.Symantic"- [tests]
+ stack.yaml view
@@ -0,0 +1,3 @@+resolver: lts-10.5+packages:+- '.'
symantic-grammar.cabal view
@@ -1,50 +1,36 @@-author: Julien Moutinho <julm+symantic@autogeree.net>+name: symantic-grammar+-- PVP: +-+------- breaking API changes+-- | | +----- non-breaking API additions+-- | | | +--- code changes with no API change+version: 0.3.0.20180213+category: Language+synopsis: Library for symantic grammars.+description: This library defines an embedded DSL for regular or context-free grammars,+ in the <http://okmij.org/ftp/tagless-final/ Tagless-Final> way (aka. the /symantic/ way).+ .+ See @Test.hs@ or source code of <https://hackage.haskell.org/package/symantic symantic>+ and <https://hackage.haskell.org/package/symantic-lib symantic-lib> for examples of use.+extra-doc-files:+license: GPL-3+license-file: COPYING+stability: experimental+author: Julien Moutinho <julm+symantic@autogeree.net>+maintainer: Julien Moutinho <julm+symantic@autogeree.net> bug-reports: Julien Moutinho <julm+symantic@autogeree.net>+-- homepage:+ build-type: Simple cabal-version: >= 1.24-category: Language-description:- This library defines an embedded DSL for regular or context-free grammars,- in the <http://okmij.org/ftp/tagless-final/ Tagless-Final> way (aka. the /symantic/ way).- .- See @Test.hs@ or source code of <https://hackage.haskell.org/package/symantic symantic>- and <https://hackage.haskell.org/package/symantic-lib symantic-lib> for examples of use.+tested-with: GHC==8.2.2 extra-source-files:+ stack.yaml extra-tmp-files:--- homepage: -license: GPL-3-license-file: COPYING-maintainer: Julien Moutinho <julm+symantic@autogeree.net>-name: symantic-grammar-stability: experimental-synopsis: Library for symantic grammars.-tested-with: GHC==8.0.2--- PVP: +-+------- breaking API changes--- | | +----- non-breaking API additions--- | | | +--- code changes with no API change-version: 0.2.0.20170709 Source-Repository head location: git://git.autogeree.net/symantic type: git Library- default-extensions:- DataKinds- FlexibleContexts- FlexibleInstances- GeneralizedNewtypeDeriving- KindSignatures- LambdaCase- MultiParamTypeClasses- OverloadedStrings- ScopedTypeVariables- StandaloneDeriving- ghc-options: -Wall- -fwarn-incomplete-patterns- -fno-warn-tabs- -fprint-explicit-kinds- default-language: Haskell2010 exposed-modules: Language.Symantic.Grammar Language.Symantic.Grammar.BinTree@@ -57,12 +43,35 @@ Language.Symantic.Grammar.Terminal Language.Symantic.Grammar.Source Language.Symantic.Grammar.Error+ default-language: Haskell2010+ default-extensions:+ DataKinds+ FlexibleContexts+ FlexibleInstances+ GeneralizedNewtypeDeriving+ KindSignatures+ LambdaCase+ MultiParamTypeClasses+ OverloadedStrings+ ScopedTypeVariables+ StandaloneDeriving+ ghc-options:+ -Wall+ -Wincomplete-uni-patterns+ -Wincomplete-record-updates+ -fno-warn-tabs+ -fhide-source-paths build-depends:- base >= 4.6 && < 5- , text+ base >= 4.6 && < 5+ , text >= 1.2 Test-Suite symantic-grammar-test type: exitcode-stdio-1.0+ hs-source-dirs: test+ main-is: Main.hs+ other-modules:+ HUnit+ default-language: Haskell2010 default-extensions: FlexibleContexts FlexibleInstances@@ -70,18 +79,17 @@ OverloadedStrings ScopedTypeVariables TypeFamilies- default-language: Haskell2010- ghc-options: -Wall- -fno-warn-tabs- -main-is Test- hs-source-dirs: Language/Symantic- main-is: Grammar/Test.hs- other-modules:+ ghc-options:+ -Wall+ -Wincomplete-uni-patterns+ -Wincomplete-record-updates+ -fno-warn-tabs+ -fhide-source-paths build-depends:- base >= 4.6 && < 5- , megaparsec- , symantic-grammar- , tasty >= 0.11- , tasty-hunit- , text- , transformers+ symantic-grammar+ , base >= 4.6 && < 5+ , megaparsec >= 6.3+ , tasty >= 0.11+ , tasty-hunit >= 0.9+ , text >= 1.2+ , transformers >= 0.5
+ test/HUnit.hs view
@@ -0,0 +1,108 @@+{-# LANGUAGE ConstraintKinds #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+module HUnit where++import Test.Tasty+import Test.Tasty.HUnit++import Control.Applicative (Applicative(..))+import Control.Monad+import Data.Semigroup ((<>))+import Data.String (IsString(..))+import qualified Control.Applicative as Applicative+import qualified Data.Char as Char+import qualified Data.Text as Text+import qualified Text.Megaparsec as P+import qualified Text.Megaparsec.Char as P++import Language.Symantic.Grammar++-- * Type 'ParsecT'+type ParsecC e s = (P.Token s ~ Char, P.Stream s, Ord e)+instance (ParsecC e s, Gram_String (P.ParsecT e s m)) => IsString (P.ParsecT e s m String) where+ fromString = string+instance ParsecC e s => Gram_Rule (P.ParsecT e s m) where+ rule = P.label . Text.unpack+instance ParsecC e s => Gram_Char (P.ParsecT e s m) where+ any = P.anyChar+ eoi = P.eof+ char = P.char+ unicat cat = P.satisfy $ (`elem` cats) . Char.generalCategory+ where cats = unicode_categories cat+ range (l, h) = P.satisfy $ \c -> l <= c && c <= h+ but (Terminal f) (Terminal p) = Terminal $ P.notFollowedBy (P.try p) *> f+instance ParsecC e String => Gram_String (P.ParsecT e String m) where+ string = P.string+instance ParsecC e s => Gram_Alt (P.ParsecT e s m) where+ empty = Applicative.empty+ (<+>) = (Applicative.<|>)+ choice = P.choice+instance ParsecC e s => Gram_Try (P.ParsecT e s m) where+ try = P.try+instance ParsecC e s => Gram_RegR (P.ParsecT e s m) where+ Terminal f .*> Reg x = Reg $ f <*> x+instance ParsecC e s => Gram_RegL (P.ParsecT e s m) where+ Reg f <*. Terminal x = Reg $ f <*> x+instance ParsecC e s => Gram_App (P.ParsecT e s m)+instance ParsecC e s => Gram_AltApp (P.ParsecT e s m)+instance ParsecC e s => Gram_CF (P.ParsecT e s m) where+ CF f <& Reg p = CF $ P.lookAhead f <*> p+ Reg f &> CF p = CF $ P.lookAhead f <*> p+ CF f `minus` Reg p = CF $ P.notFollowedBy (P.try p) *> f+instance ParsecC e String => Gram_Comment (P.ParsecT e String m)++elide :: Text.Text -> String+elide s | Text.length s > 42 = take 42 (Text.unpack s) <> ['…']+elide s = Text.unpack s++hunits :: TestTree+hunits = testGroup "Grammar"+ [ testGroup "Terminal" $+ let (==>) input expected =+ testCase (elide expected) $+ runEBNF (unTerminal (void input)) @?= expected+ ; infix 1 ==> in+ [ string "" ==> "\"\""+ , string "abé\"to" ==> "\"abé\", U+34, \"to\""+ , string "\"" ==> "U+34"+ , range ('a', 'z') ==> "\"a\"…\"z\""+ , unicat Unicat_Letter ==> "Unicat_Letter"+ , unicat (Unicat Char.LowercaseLetter) ==> "Unicat LowercaseLetter"+ ]+ , testGroup "Reg" $+ let (==>) input expected =+ testCase (elide expected) $+ runEBNF (unReg (void input)) @?= expected+ ; infix 1 ==> in+ [ (<>) <$> string "0" .*> someR (char '1') ==> "\"0\", {\"1\"}-"+ , (<>) <$> someL (char '1') <*. string "0" ==> "{\"1\"}-, \"0\""+ ]+ , testGroup "CF" $+ let (==>) input expected =+ testCase (elide expected) $+ runEBNF (unCF (void input)) @?= expected+ ; infix 1 ==> in+ [ (<>) <$> string "0" <*> string "1" ==> "\"0\", \"1\""+ , (<>) <$> string "0" <* string "X" <*> string "1" ==> "\"0\", \"X\", \"1\""+ , (<>) <$> (string "0" <+> string "1") <*> string "2" ==> "(\"0\" | \"1\"), \"2\""+ , (<>) <$> string "0" <*> (string "1" <+> string "2") ==> "\"0\", (\"1\" | \"2\")"+ , string "0" <+> string "1" <+> string "2" ==> "\"0\" | \"1\" | \"2\""+ , choice [string "0", string "1", string "2"] ==> "\"0\" | \"1\" | \"2\""+ , (<>) <$> choice+ [ (<>) <$> string "0" <*> string "1"+ , string "2" <+> string "3"+ , string "4"+ ] <*> string "5" ==> "(\"0\", \"1\" | \"2\" | \"3\" | \"4\"), \"5\""+ , concat <$> many (string "0") ==> "{\"0\"}"+ , () <$ char 'a' <* char 'b' <* char 'c' ==> "\"a\", \"b\", \"c\""+ ,let g0 = (<>) <$> string "0" .*> someR (char '1') in+ (<>) <$> string "0" <& g0 ==> "\"0\" & \"0\", {\"1\"}-"+ ,let g0 = (<>) <$> string "0" .*> someR (char '1') in+ let g1 = (<>) <$> someL (char '1') <*. string "0" in+ string "0" `minus` g0 `minus` g1 ==>+ "\"0\" - \"0\", {\"1\"}- - {\"1\"}-, \"0\""+ , (<>)+ <$> many (string "0" <+> string "1")+ <*> some (string "2") ==> "{\"0\" | \"1\"}, {\"2\"}-"+ ]+ ]
+ test/Main.hs view
@@ -0,0 +1,10 @@+module Main where++import Test.Tasty+import HUnit++main :: IO ()+main =+ defaultMain $+ testGroup "Language.Symantic"+ [hunits]