Earley 0.8.3 → 0.9.0
raw patch · 4 files changed
+179/−78 lines, 4 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Text.Earley: [Ended] :: (Report e i) -> Result s e i a
- Text.Earley: [Parsed] :: (ST s [a]) -> Int -> i -> (ST s (Result s e i a)) -> Result s e i a
- Text.Earley: [Report] :: Int -> [e] -> i -> Report e i
- Text.Earley.Grammar: [Alts] :: ![Prod r e t a] -> !(Prod r e t (a -> b)) -> Prod r e t b
- Text.Earley.Grammar: [FixBind] :: (a -> Grammar r e a) -> (a -> Grammar r e b) -> Grammar r e b
- Text.Earley.Grammar: [Many] :: !(Prod r e t a) -> !(Prod r e t ([a] -> b)) -> Prod r e t b
- Text.Earley.Grammar: [Named] :: !(Prod r e t a) -> e -> Prod r e t a
- Text.Earley.Grammar: [NonTerminal] :: !(r e t a) -> !(Prod r e t (a -> b)) -> Prod r e t b
- Text.Earley.Grammar: [Pure] :: a -> Prod r e t a
- Text.Earley.Grammar: [Return] :: a -> Grammar r e a
- Text.Earley.Grammar: [RuleBind] :: Prod r e t a -> (Prod r e t a -> Grammar r e b) -> Grammar r e b
- Text.Earley.Grammar: [Terminal] :: !(t -> Bool) -> !(Prod r e t (t -> b)) -> Prod r e t b
- Text.Earley.Grammar: instance Alternative (Prod r e t)
- Text.Earley.Grammar: instance Applicative (Grammar r e)
- Text.Earley.Grammar: instance Applicative (Prod r e t)
- Text.Earley.Grammar: instance Functor (Grammar r e)
- Text.Earley.Grammar: instance Functor (Prod r e t)
- Text.Earley.Grammar: instance Monad (Grammar r e)
- Text.Earley.Grammar: instance MonadFix (Grammar r e)
- Text.Earley.Grammar: instance Monoid (Prod r e t a)
- Text.Earley.Internal: [Cont] :: !Pos -> !(Args s a b) -> !(ProdR s r e t (b -> c)) -> !(Args s c d) -> !(Conts s r e t d e') -> Cont s r e t a e'
- Text.Earley.Internal: [Conts] :: !(STRef s [Cont s r e t a c]) -> !(STRef s (Maybe (STRef s (ST s [a])))) -> Conts s r e t a c
- Text.Earley.Internal: [Ended] :: (Report e i) -> Result s e i a
- Text.Earley.Internal: [FinalCont] :: Args s a c -> Cont s r e t a c
- Text.Earley.Internal: [Final] :: f -> Args s f a -> State s r e t a
- Text.Earley.Internal: [Parsed] :: (ST s [a]) -> Int -> i -> (ST s (Result s e i a)) -> Result s e i a
- Text.Earley.Internal: [Report] :: Int -> [e] -> i -> Report e i
- Text.Earley.Internal: [Rule] :: ProdR s r e t a -> !(STRef s (Maybe [a])) -> !(STRef s (STRef s [Cont s r e t a r])) -> Rule s r e t a
- Text.Earley.Internal: [State] :: !Pos -> !(ProdR s r e t f) -> !(Args s f b) -> !(Conts s r e t b a) -> State s r e t a
- Text.Earley.Internal: instance (Eq e, Eq i) => Eq (Report e i)
- Text.Earley.Internal: instance (Ord e, Ord i) => Ord (Report e i)
- Text.Earley.Internal: instance (Read e, Read i) => Read (Report e i)
- Text.Earley.Internal: instance (Show e, Show i) => Show (Report e i)
- Text.Earley.Internal: instance Functor (Result s e i)
- Text.Earley.Mixfix: [LeftAssoc] :: Associativity
- Text.Earley.Mixfix: [NonAssoc] :: Associativity
- Text.Earley.Mixfix: [RightAssoc] :: Associativity
- Text.Earley.Mixfix: instance Eq Associativity
- Text.Earley.Mixfix: instance Show Associativity
- Text.Earley.Parser: [Ended] :: (Report e i) -> Result s e i a
- Text.Earley.Parser: [Parsed] :: (ST s [a]) -> Int -> i -> (ST s (Result s e i a)) -> Result s e i a
- Text.Earley.Parser: [Report] :: Int -> [e] -> i -> Report e i
+ Text.Earley: Ended :: (Report e i) -> Result s e i a
+ Text.Earley: Parsed :: (ST s [a]) -> Int -> i -> (ST s (Result s e i a)) -> Result s e i a
+ Text.Earley: Report :: Int -> [e] -> i -> Report e i
+ Text.Earley.Grammar: Alts :: ![Prod r e t a] -> !(Prod r e t (a -> b)) -> Prod r e t b
+ Text.Earley.Grammar: FixBind :: (a -> Grammar r e a) -> (a -> Grammar r e b) -> Grammar r e b
+ Text.Earley.Grammar: Many :: !(Prod r e t a) -> !(Prod r e t ([a] -> b)) -> Prod r e t b
+ Text.Earley.Grammar: Named :: !(Prod r e t a) -> e -> Prod r e t a
+ Text.Earley.Grammar: NonTerminal :: !(r e t a) -> !(Prod r e t (a -> b)) -> Prod r e t b
+ Text.Earley.Grammar: Pure :: a -> Prod r e t a
+ Text.Earley.Grammar: Return :: a -> Grammar r e a
+ Text.Earley.Grammar: RuleBind :: Prod r e t a -> (Prod r e t a -> Grammar r e b) -> Grammar r e b
+ Text.Earley.Grammar: Terminal :: !(t -> Bool) -> !(Prod r e t (t -> b)) -> Prod r e t b
+ Text.Earley.Grammar: instance Control.Monad.Fix.MonadFix (Text.Earley.Grammar.Grammar r e)
+ Text.Earley.Grammar: instance GHC.Base.Alternative (Text.Earley.Grammar.Prod r e t)
+ Text.Earley.Grammar: instance GHC.Base.Applicative (Text.Earley.Grammar.Grammar r e)
+ Text.Earley.Grammar: instance GHC.Base.Applicative (Text.Earley.Grammar.Prod r e t)
+ Text.Earley.Grammar: instance GHC.Base.Functor (Text.Earley.Grammar.Grammar r e)
+ Text.Earley.Grammar: instance GHC.Base.Functor (Text.Earley.Grammar.Prod r e t)
+ Text.Earley.Grammar: instance GHC.Base.Monad (Text.Earley.Grammar.Grammar r e)
+ Text.Earley.Grammar: instance GHC.Base.Monoid (Text.Earley.Grammar.Prod r e t a)
+ Text.Earley.Internal: Cont :: !Pos -> !(Args s a b) -> !(ProdR s r e t (b -> c)) -> !(Args s c d) -> !(Conts s r e t d e') -> Cont s r e t a e'
+ Text.Earley.Internal: Conts :: !(STRef s [Cont s r e t a c]) -> !(STRef s (Maybe (STRef s (ST s [a])))) -> Conts s r e t a c
+ Text.Earley.Internal: Ended :: (Report e i) -> Result s e i a
+ Text.Earley.Internal: Final :: f -> Args s f a -> State s r e t a
+ Text.Earley.Internal: FinalCont :: Args s a c -> Cont s r e t a c
+ Text.Earley.Internal: ParseEnv :: ![ST s [a]] -> ![State s a e t a] -> !(ST s ()) -> ![e] -> !Pos -> !i -> ParseEnv s e i t a
+ Text.Earley.Internal: Parsed :: (ST s [a]) -> Int -> i -> (ST s (Result s e i a)) -> Result s e i a
+ Text.Earley.Internal: Report :: Int -> [e] -> i -> Report e i
+ Text.Earley.Internal: Rule :: ProdR s r e t a -> !(STRef s (Maybe [a])) -> !(STRef s (STRef s [Cont s r e t a r])) -> Rule s r e t a
+ Text.Earley.Internal: State :: !Pos -> !(ProdR s r e t f) -> !(Args s f b) -> !(Conts s r e t b a) -> State s r e t a
+ Text.Earley.Internal: [input] :: ParseEnv s e i t a -> !i
+ Text.Earley.Internal: [names] :: ParseEnv s e i t a -> ![e]
+ Text.Earley.Internal: [next] :: ParseEnv s e i t a -> ![State s a e t a]
+ Text.Earley.Internal: [pos] :: ParseEnv s e i t a -> !Pos
+ Text.Earley.Internal: [reset] :: ParseEnv s e i t a -> !(ST s ())
+ Text.Earley.Internal: [results] :: ParseEnv s e i t a -> ![ST s [a]]
+ Text.Earley.Internal: data ParseEnv s e i t a
+ Text.Earley.Internal: emptyParseEnv :: i -> ParseEnv s e i t a
+ Text.Earley.Internal: instance (GHC.Classes.Eq e, GHC.Classes.Eq i) => GHC.Classes.Eq (Text.Earley.Internal.Report e i)
+ Text.Earley.Internal: instance (GHC.Classes.Ord e, GHC.Classes.Ord i) => GHC.Classes.Ord (Text.Earley.Internal.Report e i)
+ Text.Earley.Internal: instance (GHC.Read.Read e, GHC.Read.Read i) => GHC.Read.Read (Text.Earley.Internal.Report e i)
+ Text.Earley.Internal: instance (GHC.Show.Show e, GHC.Show.Show i) => GHC.Show.Show (Text.Earley.Internal.Report e i)
+ Text.Earley.Internal: instance GHC.Base.Functor (Text.Earley.Internal.Result s e i)
+ Text.Earley.Internal: pureArgs :: [x] -> Args s f a -> Args s (x -> f) a
+ Text.Earley.Mixfix: LeftAssoc :: Associativity
+ Text.Earley.Mixfix: NonAssoc :: Associativity
+ Text.Earley.Mixfix: RightAssoc :: Associativity
+ Text.Earley.Mixfix: instance GHC.Classes.Eq Text.Earley.Mixfix.Associativity
+ Text.Earley.Mixfix: instance GHC.Show.Show Text.Earley.Mixfix.Associativity
+ Text.Earley.Parser: Ended :: (Report e i) -> Result s e i a
+ Text.Earley.Parser: Parsed :: (ST s [a]) -> Int -> i -> (ST s (Result s e i a)) -> Result s e i a
+ Text.Earley.Parser: Report :: Int -> [e] -> i -> Report e i
- Text.Earley.Internal: parse :: ListLike i t => [State s a e t a] -> [ST s [a]] -> [State s a e t a] -> ST s () -> [e] -> Pos -> i -> ST s (Result s e i a)
+ Text.Earley.Internal: parse :: ListLike i t => [State s a e t a] -> ParseEnv s e i t a -> ST s (Result s e i a)
Files
- Earley.cabal +3/−6
- Text/Earley/Internal.hs +71/−56
- Text/Earley/Mixfix.hs +43/−16
- tests/Tests.hs +62/−0
Earley.cabal view
@@ -1,5 +1,5 @@ name: Earley-version: 0.8.3+version: 0.9.0 synopsis: Parsing all context-free grammars using Earley's algorithm. description: See <https://www.github.com/ollef/Earley> for more information and@@ -34,7 +34,8 @@ build-depends: base >=4.7 && <4.9, ListLike >=4.1 -- hs-source-dirs: default-language: Haskell2010- ghc-options: -Wall -funbox-strict-fields+ ghc-options: -Wall+ -funbox-strict-fields executable earley-english if !flag(examples)@@ -97,10 +98,6 @@ build-depends: base, deepseq, criterion >=1.1, parsec >=3.1, ListLike default-language: Haskell2010 ghc-options: -Wall- -O2- -fmax-simplifier-iterations=10- -fdicts-cheap- -fspec-constr-count=6 test-suite tests type: exitcode-stdio-1.0
Text/Earley/Internal.hs view
@@ -66,6 +66,9 @@ pureArg :: x -> Args s f a -> Args s (x -> f) a pureArg x args = args . ($ x) +pureArgs :: [x] -> Args s f a -> Args s (x -> f) a+pureArgs xs args f = concat <$> mapM (args . f) xs+ impureArgs :: ST s [x] -> Args s f a -> Args s (x -> f) a impureArgs mxs args f = fmap concat . mapM (args . f) =<< mxs @@ -108,13 +111,13 @@ newConts r = Conts r <$> newSTRef Nothing contraMapCont :: Args s b a -> Cont s r e t a c -> Cont s r e t b c-contraMapCont f (Cont pos g p args cs) = Cont pos (composeArgs f g) p args cs+contraMapCont f (Cont cpos g p args cs) = Cont cpos (composeArgs f g) p args cs contraMapCont f (FinalCont args) = FinalCont (composeArgs f args) contToState :: ST s [a] -> Cont s r e t a c -> State s r e t c-contToState r (Cont pos g p args cs) = +contToState r (Cont cpos g p args cs) = let mb = fmap concat . mapM g =<< r in- State pos p (impureArgs mb args) cs+ State cpos p (impureArgs mb args) cs contToState r (FinalCont args) = Final id (impureArgs r args) -- | Strings of non-ambiguous continuations can be optimised by removing@@ -189,94 +192,106 @@ | ListLike.null ts = ts | otherwise = ListLike.tail ts +data ParseEnv s e i t a = ParseEnv+ { results :: ![ST s [a]]+ -- ^ Results ready to be reported (when this position has been processed)+ , next :: ![State s a e t a]+ -- ^ States to process at the next position+ , reset :: !(ST s ())+ -- ^ Computation that resets the continuation refs of productions+ , names :: ![e]+ -- ^ Named productions encountered at this position+ , pos :: !Pos+ -- ^ The current position in the input string+ , input :: !i+ -- ^ The input string+ }++{-# INLINE emptyParseEnv #-}+emptyParseEnv :: i -> ParseEnv s e i t a+emptyParseEnv i = ParseEnv+ { results = mempty+ , next = mempty+ , reset = return ()+ , names = mempty+ , pos = 0+ , input = i+ }+ {-# SPECIALISE parse :: [State s a e t a]- -> [ST s [a]]- -> [State s a e t a]- -> ST s ()- -> [e]- -> Pos- -> [t]+ -> ParseEnv s e [t] t a -> ST s (Result s e [t] a) #-} -- | The internal parsing routine parse :: ListLike i t => [State s a e t a] -- ^ States to process at this position- -> [ST s [a]] -- ^ Results ready to be reported (when this position has been processed)- -> [State s a e t a] -- ^ States to process at the next position- -> ST s () -- ^ Computation that resets the continuation refs of productions- -> [e] -- ^ Named productions encountered at this position- -> Pos -- ^ The current position in the input string- -> i -- ^ The input string+ -> ParseEnv s e i t a -> ST s (Result s e i a)-parse [] [] [] reset names !pos ts = do- reset- return $ Ended Report {position = pos, expected = names, unconsumed = ts}-parse [] [] next reset _ !pos ts = do- reset- parse next [] [] (return ()) [] (pos + 1) $ safeTail ts-parse [] results next reset names !pos ts = do- reset- return $ Parsed (concat <$> sequence results) pos ts- $ parse [] [] next (return ()) names pos ts-parse (st:ss) results next reset names !pos ts = case st of- Final f args -> parse ss (args f : results) next reset names pos ts+parse [] env@ParseEnv {results = [], next = []} = do+ reset env+ return $ Ended Report+ { position = pos env+ , expected = names env+ , unconsumed = input env+ }+parse [] env@ParseEnv {results = []} = do+ reset env+ parse (next env) (emptyParseEnv $ safeTail $ input env) {pos = pos env + 1}+parse [] env = do+ reset env+ return $ Parsed (concat <$> sequence (results env)) (pos env) (input env)+ $ parse [] env {results = [], reset = return ()}+parse (st:ss) env = case st of+ Final f args -> parse ss env {results = args f : results env} State spos pr args scont -> case pr of- Terminal f p -> case safeHead ts of- Just t | f t ->- parse ss results (State spos p (pureArg t args) scont : next) reset names pos ts- _ -> parse ss results next reset names pos ts+ Terminal f p -> case safeHead $ input env of+ Just t | f t -> parse ss env {next = State spos p (pureArg t args) scont+ : next env}+ _ -> parse ss env NonTerminal r p -> do rkref <- readSTRef $ ruleConts r ks <- readSTRef rkref writeSTRef rkref (Cont spos noArgs p args scont : ks) nulls <- nullable r- let nullStates = [State spos p (pureArg a args) scont | a <- nulls]+ let nullStates | null nulls = mempty+ | otherwise = pure $ State spos p (pureArgs nulls args) scont if null ks then do -- The rule has not been expanded at this position.- st' <- State pos (ruleProd r) noArgs <$> newConts rkref+ st' <- State (pos env) (ruleProd r) noArgs <$> newConts rkref parse (st' : nullStates ++ ss)- results- next- (resetConts r >> reset)- names- pos- ts+ env {reset = resetConts r >> reset env} else -- The rule has already been expanded at this position.- parse (nullStates ++ ss) results next reset names pos ts- Pure a | spos /= pos -> do+ parse (nullStates ++ ss) env+ Pure a | spos /= pos env -> do let argsRef = contsArgs scont masref <- readSTRef argsRef case masref of Just asref -> do -- The continuation has already been followed at this position. modifySTRef asref (((++) <$> args a) <*>)- parse ss results next reset names pos ts+ parse ss env Nothing -> do -- It hasn't. asref <- newSTRef $ args a writeSTRef argsRef $ Just asref ks <- simplifyCont scont let kstates = map (contToState $ join $ readSTRef asref) ks parse (kstates ++ ss)- results- next- (writeSTRef argsRef Nothing >> reset)- names- pos- ts- | otherwise -> parse ss results next reset names pos ts+ env {reset = writeSTRef argsRef Nothing >> reset env}+ | otherwise -> parse ss env Alts as (Pure f) -> do let args' = funArg f `composeArgs` args sts = [State spos a args' scont | a <- as]- parse (sts ++ ss) results next reset names pos ts+ parse (sts ++ ss) env Alts as p -> do scont' <- newConts =<< newSTRef [Cont spos noArgs p args scont] -- State is (-1) so that nullable alts are expanded correctly let sts = [State (-1) a noArgs scont' | a <- as]- parse (sts ++ ss) results next reset names pos ts+ parse (sts ++ ss) env Many p q -> do c <- newSTRef =<< newSTRef mempty nr <- newSTRef Nothing let r = Rule (pure [] <|> (:) <$> p <*> NonTerminal r (Pure id)) nr c st' = State spos (NonTerminal r q) args scont- parse (st' : ss) results next reset names pos ts- Named pr' n -> parse (State spos pr' args scont : ss) results next reset (n : names) pos ts+ parse (st' : ss) env+ Named pr' n -> parse (State spos pr' args scont : ss)+ env {names = n : names env} {-# INLINE parser #-} -- | Create a parser from the given grammar.@@ -286,7 +301,7 @@ -> ST s (Result s e i a) parser g xs = do s <- initialState =<< grammar g- parse [s] [] [] (return ()) [] 0 xs+ parse [s] $ emptyParseEnv xs -- | Return all parses from the result of a given parser. The result may -- contain partial parses. The 'Int's are the position at which a result was@@ -297,9 +312,9 @@ go :: Result s e i a -> ST s ([(a, Int)], Report e i) go r = case r of Ended rep -> return ([], rep)- Parsed mas pos _ k -> do+ Parsed mas cpos _ k -> do as <- mas- fmap (first (zip as (repeat pos) ++)) $ go =<< k+ fmap (first (zip as (repeat cpos) ++)) $ go =<< k {-# INLINE fullParses #-} -- | Return all parses that reached the end of the input from the result of a
Text/Earley/Mixfix.hs view
@@ -1,13 +1,24 @@ {-# LANGUAGE CPP, RecursiveDo #-}-module Text.Earley.Mixfix where+module Text.Earley.Mixfix+ ( Associativity(..)+ , Holey+ , mixfixExpression+ ) where #if !MIN_VERSION_base(4,8,0) import Control.Applicative #endif import Data.Either import Data.Foldable(asum, foldrM)+import Data.Traversable(sequenceA) import Text.Earley +replicateA :: Applicative f => Int -> f a -> f [a]+replicateA n = sequenceA . replicate n++consA :: Applicative f => f a -> f [a] -> f [a]+consA p q = (:) <$> p <*> q+ data Associativity = LeftAssoc | NonAssoc@@ -28,9 +39,12 @@ -- The identifiers should be in groups of precedence levels listed from -- binding the least to the most tightly. --- -- The associativity is taken into account when an identifier starts or- -- ends with a hole, or both. Internal holes (e.g. after "if" in- -- "if_then_else_") start from the beginning of the table.+ -- The associativity is taken into account when an identifier starts or ends+ -- with holes, or both. Internal holes (e.g. after "if" in "if_then_else_")+ -- start from the beginning of the table.+ --+ -- Note that this rule also applies to identifiers with multiple consecutive+ -- holes, e.g. "if__" --- the associativity then applies to both holes. -> Prod r e t expr -- ^ An atom, i.e. what is parsed at the lowest level. This will -- commonly be a (non-mixfix) identifier or a parenthesised expression.@@ -42,24 +56,37 @@ expr <- foldrM ($) atom $ map (level expr) table return expr where- app' xs = app (either (const Nothing) Just <$> xs) $ lefts xs+ app' xs = app (concatMap (either (map $ const Nothing) $ map Just) xs)+ $ concat $ lefts xs level expr idents next = mdo same <- rule $ asum $ next : map (mixfixIdent same) idents return same where- cons p q = (:) <$> p <*> q- mixfixIdent same (ps, a) = app' <$> go ps+ -- Group consecutive holes and ident parts.+ grp [] = []+ grp (Nothing:ps) = case grp ps of+ Left n:rest -> (Left $! (n + 1)) : rest+ rest -> Left 1 : rest+ grp (Just p:ps) = case grp ps of+ Right ps':rest -> Right (consA p ps') : rest+ rest -> Right (consA p $ pure []) : rest++ mixfixIdent same (ps, a) = app' <$> go (grp ps) where go ps' = case ps' of [] -> pure []- [Just p] -> pure . Right <$> p- Nothing:rest -> cons (Left <$> if a == RightAssoc then next- else same)+ [Right p] -> pure . Right <$> p+ Left n:rest -> consA+ (Left <$> replicateA n (if a == RightAssoc then next+ else same)) $ go rest- [Just p, Nothing] -> cons (Right <$> p)- $ pure . Left <$> if a == LeftAssoc then next else same- Just p:Nothing:rest -> cons (Right <$> p)- $ cons (Left <$> expr)+ [Right p, Left n] -> consA+ (Right <$> p)+ $ pure . Left <$> replicateA n (if a == LeftAssoc then next+ else same)+ Right p:Left n:rest -> consA (Right <$> p)+ $ consA (Left <$> replicateA n expr) $ go rest- Just p:rest@(Just _:_) -> cons (Right <$> p) $ go rest-+ Right _:Right _:_ -> error+ $ "Earley.mixfixExpression: The impossible happened. "+ ++ "Please report this as a bug."
tests/Tests.hs view
@@ -95,6 +95,50 @@ let x = Ident [Just "x"] in fullParses (parser mixfixGrammar $ words "[ x ]") @?= (,) [App closed [x]] Report {position = 3, expected = [], unconsumed = []}++ , let x = words "+ + 5 6 7" in+ HU.testCase "Mixfix issue #11 1" $+ fullParses (parser (issue11 LeftAssoc) x)+ @?= (,) [] Report {position = 1, expected = [], unconsumed = drop 1 x}+ , let x = words "+ 5 + 6 7" in+ HU.testCase "Mixfix issue #11 2" $+ fullParses (parser (issue11 LeftAssoc) x)+ @?= (,) [] Report {position = 2, expected = [], unconsumed = drop 2 x}+ , let x = words "+ 5 6" in+ HU.testCase "Mixfix issue #11 3" $+ fullParses (parser (issue11 LeftAssoc) x)+ @?= (,) [Plus11 (Var11 "5") (Var11 "6")]+ Report {position = 3, expected = [], unconsumed = []}+ , let x = words "+ + 5 6 7" in+ HU.testCase "Mixfix issue #11 4" $+ fullParses (parser (issue11 RightAssoc) x)+ @?= (,) [Plus11 (Plus11 (Var11 "5") (Var11 "6")) (Var11 "7")]+ Report {position = 5, expected = [], unconsumed = []}+ , let x = words "+ 5 + 6 7" in+ HU.testCase "Mixfix issue #11 5" $+ fullParses (parser (issue11 RightAssoc) x)+ @?= (,) [Plus11 (Var11 "5") (Plus11 (Var11 "6") (Var11 "7"))]+ Report {position = 5, expected = [], unconsumed = []}+ , let x = words "+ 5 6" in+ HU.testCase "Mixfix issue #11 6" $+ fullParses (parser (issue11 RightAssoc) x)+ @?= (,) [Plus11 (Var11 "5") (Var11 "6")]+ Report {position = 3, expected = [], unconsumed = []}+ , let x = words "+ + 5 6 7" in+ HU.testCase "Mixfix issue #11 7" $+ fullParses (parser (issue11 NonAssoc) x)+ @?= (,) [Plus11 (Plus11 (Var11 "5") (Var11 "6")) (Var11 "7")]+ Report {position = 5, expected = [], unconsumed = []}+ , let x = words "+ 5 + 6 7" in+ HU.testCase "Mixfix issue #11 8" $+ fullParses (parser (issue11 NonAssoc) x)+ @?= (,) [Plus11 (Var11 "5") (Plus11 (Var11 "6") (Var11 "7"))]+ Report {position = 5, expected = [], unconsumed = []}+ , let x = words "+ 5 6" in+ HU.testCase "Mixfix issue #11 9" $+ fullParses (parser (issue11 NonAssoc) x)+ @?= (,) [Plus11 (Var11 "5") (Var11 "6")]+ Report {position = 3, expected = [], unconsumed = []} ] optional_ :: Prod r Char Char (Maybe Char, Char)@@ -230,3 +274,21 @@ infix2 = [Nothing, Just "infix2", Nothing] closed = [Just "[", Nothing, Just "]"] +-- Adapted from issue #11+data Mixfix11+ = Var11 String+ | Plus11 Mixfix11 Mixfix11+ deriving (Eq, Ord, Show)++issue11 :: Associativity -> Grammar r String (Prod r String String Mixfix11)+issue11 a = mdo+ atomicExpr <- rule $ Var11 <$> satisfy (/= "+")++ expr <- mixfixExpression+ [[([Just (symbol "+"), Nothing, Nothing], a)]]+ atomicExpr+ (\x y -> case (x,y) of+ ([Just "+", Nothing, Nothing], [e1,e2]) -> Plus11 e1 e2+ _ -> undefined)++ return expr