indentation-parsec-0.0: src/Text/Parsec/Indentation/Examples/ISWIM.hs
module Text.Parsec.Indentation.Examples.ISWIM where
-- Encodes example TODO from the paper TODO.
-- Note that because Parsec doesn't support full backtracking
-- this
--
import Control.Applicative ((<$>))
import Text.Parsec
import Text.Parsec.Indentation
import Text.Parsec.Indentation.Char
data ID = ID String deriving (Show, Eq)
data Expr
= Where Expr ID Expr -- expr -> expr 'where' ID '=' |expr|>=
| Plus Expr Expr -- expr -> expr '+' expr
| Minus Expr -- expr -> '-' expr
| Parens Expr -- expr -> '(' expr* ')'
| Var ID -- expr -> ID
deriving (Show, Eq)
runParse :: String -> Either ParseError Expr
runParse input
= case runParser expr () "" (mkIndentStream 0 infIndentation True Ge (mkCharIndentStream input)) of
Left err -> Left err
Right a -> Right a
-- Note that this grammar DOES NOT WORK as written because it contains
-- a left recursion. (It diverges.) However, it provides a good
-- first example to see how to use the combinators in
-- Text.Parsec.Indentation.
tok s = string s >> localTokenMode (const Any) (ignoreAbsoluteIndentation (many (char ' ' <|> char '\n')))
ident = choice (map f ["v", "w", "x", "y", "z"])
where f x = tok x >> return (ID x)
expr = choice $ map try
[ do e1 <- expr_nonrec
tok "where"
i <- ident
tok "="
e2 <- localIndentation Ge (absoluteIndentation expr)
return (Where e1 i e2)
, do e1 <- expr_nonrec
tok "+"
e2 <- expr
return (Plus e1 e2)
, expr_nonrec
]
expr_nonrec = choice
[ tok "-" >> (Minus <$> expr)
, Parens <$> between (tok "(") (tok ")") (localIndentation Any expr)
, Var <$> ident
]
input1 = "x + v where\n\
\ x = -(\n\
\y + z) + w"
output1 = runParse input1