packages feed

Earley-0.13.0.1: tests/UnbalancedPars.hs

{-# LANGUAGE FlexibleContexts, RankNTypes, RecursiveDo, ScopedTypeVariables #-}
module UnbalancedPars where

import Data.Char (isAlpha)

import Control.Applicative
import Test.Tasty
import Test.Tasty.HUnit      as HU

import Text.Earley

tests :: TestTree
tests = testGroup "Unbalanced parentheses"
  [ HU.testCase "Parses balanced" $
      fst (fullParses' unbalancedPars
        "((x))") @?= [(b . b) x]
  , HU.testCase "Parses one unbalanced" $
      fst (fullParses' unbalancedPars
        "((x)") @?= [(u . b) x]
  , HU.testCase "Parses two unbalanced" $
      fst (fullParses' unbalancedPars
        "((x") @?= [(u . u) x]
  ]
  where
    -- [b]alanced
    b :: Expr -> Expr
    b e = ExprInBrackets "(" e ")"

    -- [u]nbalanced
    u :: Expr -> Expr
    u e = ExprInBrackets "(" e ""

    -- [x] variable
    x :: Expr
    x = Var 'x'

data Token = EOF | Char !Char
  deriving (Eq, Ord, Show)

fullParses'
  :: (forall r. Grammar r (Prod r e Token a))
  -> String
  -> ([a], Report e String)
fullParses' g s =
  let (res, rep) = allParses (parser $ (<* eof) <$> g) $ fmap Char s ++ repeat EOF
  in
    ( fst <$> res
    , rep { unconsumed = go $ unconsumed rep }
    )
  where
    go (Char c:xs) = c : go xs
    go _ = []

data Expr =
  Var Char | ExprInBrackets String Expr String
  deriving (Eq, Ord, Show)

eof :: Prod r e Token Token
eof = token EOF

leftPar :: Prod r e Token String
leftPar = "(" <$ token (Char '(')

rightPar :: Prod r e Token String
rightPar = ")" <$ token (Char ')')

var :: Prod r e Token Expr
var = terminal $ \t -> case t of
  Char c | isAlpha c -> Just $ Var c
  _ -> Nothing

unbalancedPars :: Grammar r (Prod r String Token Expr)
unbalancedPars = mdo
  expr <- rule $ var <|> exprInBrackets
  exprInBrackets <- rule $
    ExprInBrackets
      <$> leftPar
      <*> expr
      <*> (rightPar <|> ("" <$ eof))
      <?> "parenthesized expression"
  return expr