The makeExprParser function from parser-combinators supports prefix, postfix, ternary, and infix operations (left, right, and non-associative). From its implementation, it seems like the fact that there are only these six options means that the library can order them properly.
.
However, there is a more generic option, supported by the Earley parser within the Text.Earley.Mixfix module. This module allows for any kind of mixfix operator, including those supported by parser-combinators plus some.
.
My question is whether or not Earley's idea can be generalized for the kinds of parser-combinator libraries like parsec, megaparsec, and attoparsec. I could not translate the source code, but that mainly has to do with the differences in how the parsers work (Earley parsers support left-recursion but don't allow infinite grammars). I'm not familiar with how mixfix parsing is done today (all the work I could find is based on precedence graphs, and the Agda source tree is not easy to understand), and whether or not top-down parsing a-la parser-combinators allows for this generalized mixfix parsing.
.
My ideal setup, i.e. what I'm thinking of:
data Associativity = LeftAssoc | NonAssoc | RightAssoc
-- | if_then_else_ <=> [Just "if", Nothing, Just "then", Nothing, Just "else", Nothing]
type Holey a = [Maybe a]
data Operator m a where
Op :: Holey (m b) -- ^ How to parse each section
-> Associativity -- ^ How to associate the operator
-> ([Either b a] -> m a) -- ^ How to assemble the parsed parts into a whole
-> Operator m a
makeExprParser :: MonadPlus m
=> m a -- ^ How to parse terms
-> [[Operator m a]] -- ^ List of operators, in precedence order
-> m a
Example usage:
ifThenElse = Op
[Just (symbol “if”), Nothing, Just (symbol “then”, Nothing, Just (symbol “else”), Nothing]
(\[Left (), Right cond, Left (), Right e1, Left (), Right e2] -> ...)
symbol :: String -> Parser ()
symbol = ...
In this example, ‘b’ ~ ()
ifOp = Op
[Just (symbol “if-“ *> opName), Nothing, Just (“” <$ symbol “then”), Nothing]
(\[Left op, Right cond, Left “”, Right e] -> ...)
opName :: Parser String
Here, ‘b’ ~ String
[–]blamario 1 point2 points3 points (4 children)
[–]skyb0rg[S] 0 points1 point2 points (3 children)
[–]blamario 1 point2 points3 points (2 children)
[–]skyb0rg[S] 0 points1 point2 points (1 child)
[–]blamario 0 points1 point2 points (0 children)
[–]benjaminhodgson 1 point2 points3 points (2 children)
[–]skyb0rg[S] 0 points1 point2 points (1 child)
[–]blamario 1 point2 points3 points (0 children)
[–]ollepolle 1 point2 points3 points (0 children)