The journey to create combinators for parsing and pretty-pretting continues!
This post (along with the new syntax-optics
repo) combines two previous efforts:
- "Elegant AST Parsing and
Building with Prisms" declared
Prisms to parse and print ASTs, but lacking descriptive errors when the parsing fails - "Basic error reporting
for optics" declared new
lens-compatible optics that add error reporting to parse errors
The resulting combinators let us nicely declare syntax:
data Expr
= Lit Int
| Add Expr Expr
| Mul Expr Expr
deriving (Show, Eq)
makePrisms ''Expr
expr :: VerbosePrism' String String Expr
expr = tokens . takeExpr . endOfTokens
takeExpr :: VerbosePrism' String [String] (Expr, [String])
takeExpr =
infixOpLeftRecursion p "+" _Add $ -- Additions of
infixOpLeftRecursion p "*" _Mul $ -- multiplications of
tryMatchAtom p (prismFallback _Lit) _Show $ -- literals or
parens takeExpr -- expressions in parens
where
p = Proxy @Stringexpr can be used to both pretty-print and to parse:
> expr # (Lit 1 `Mul` (Lit 2 `Add` Lit 3)) `Add` Lit 4
"1 * (2 + 3) + 4"
> "1 * (2 + 3) + 4" ^? expr
Just (Add (Mul (Lit 1) (Add (Lit 2) (Lit 3))) (Lit 4))Now, to also get the syntax errors when parsing, we can use the new
^?? operator rather than lens's
^?:
> "2 + 3 * * 5" ^?? expr
Left "Unexpected \"*\""Still lacking in the library
- The errors from
syntax-opticsdo not currently report source-code locations of syntax errors. - An
AVerbosePrismtype synonym, similar in spirit toALensandAPrism, is currently missing. With it the library would not needRankNTypesnorProxyparameters which it currently requires (pin the example in this post).
I've tried to define AVerbosePrism but haven't succeeded
so far. Help and advice from lens wizards would be very
appreciated!
Notes
- Title image by Jean François WITZ.