Skip to content

Commit 3f9e7b9

Browse files
committed
added expression parser (ported from parsec); needs reworking due to mutually recursive functions in let bindings
1 parent efc9858 commit 3f9e7b9

File tree

1 file changed

+81
-0
lines changed

1 file changed

+81
-0
lines changed

src/Text/Parsing/Parser.purs.hs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module Text.Parsing.Parser where
22

33
import Prelude
4+
import Control.Monad
45
import Data.Array
56
import Data.Either
67
import Data.Maybe
@@ -151,6 +152,11 @@ chainr1' p f a = (do f' <- f
151152
a' <- chainr1 p f
152153
return $ f' a a') <|> return a
153154

155+
choice :: forall s a. [Parser s a] -> Parser s a
156+
choice [] = fail "Nothing to parse"
157+
choice [x] = x
158+
choice (x:xs) = x <|> choice xs
159+
154160
-- String Parsers
155161

156162
eof :: Parser String {}
@@ -167,3 +173,78 @@ char :: Parser String String
167173
char = Parser $ \s -> case s of
168174
"" -> failureResult s false $ parseError "Unexpected EOF"
169175
_ -> successResult (substring 1 (lengthS s) s) true (substr 0 1 s)
176+
177+
-- Expressions
178+
179+
data Assoc = AssocNone | AssocLeft | AssocRight
180+
181+
data Operator s a = Infix (Parser s (a -> a -> a)) Assoc |
182+
Prefix (Parser s (a -> a)) |
183+
Postfix (Parser s (a -> a))
184+
185+
type OperatorTable s a = [[Operator s a]]
186+
187+
type SplitAccum s a = { rassoc :: [Parser s (a -> a -> a)], lassoc :: [Parser s (a -> a -> a)], nassoc :: [Parser s (a -> a -> a)], prefix :: [Parser s (a -> a)], postfix :: [Parser s (a -> a)] }
188+
189+
splitOp :: forall s a. SplitAccum s a -> Operator s a -> SplitAccum s a
190+
splitOp accum (Infix op AssocNone) = accum { nassoc = op:accum.nassoc }
191+
splitOp accum (Infix op AssocLeft) = accum { lassoc = op:accum.lassoc }
192+
splitOp accum (Infix op AssocRight) = accum { rassoc = op:accum.rassoc }
193+
splitOp accum (Prefix op) = accum { prefix = op:accum.prefix }
194+
splitOp accum (Postfix op) = accum { postfix = op:accum.postfix }
195+
196+
buildExprParser :: forall s a. OperatorTable s a -> Parser s a -> Parser s a
197+
buildExprParser operators simpleExpr =
198+
let
199+
makeParser = \term ops ->
200+
let accum = foldr splitOp { rassoc: [], lassoc: [], nassoc: [], prefix: [], postfix: [] } ops in
201+
202+
let rassocOp = choice accum.rassoc in
203+
let lassocOp = choice accum.lassoc in
204+
let nassocOp = choice accum.nassoc in
205+
let prefixOp = choice accum.prefix <?> "" in
206+
let postfixOp = choice accum.postfix <?> "" in
207+
208+
let ambigious = \assoc op -> try $ op >>= \_ -> fail ("ambiguous use of a " ++ assoc ++ " associative operator") in
209+
210+
let ambigiousRight = ambigious "right" rassocOp in
211+
let ambigiousLeft = ambigious "left" lassocOp in
212+
let ambigiousNon = ambigious "non" nassocOp in
213+
214+
let postfixP = postfixOp <|> return id in
215+
216+
let prefixP = prefixOp <|> return id in
217+
218+
let termP = do
219+
pre <- prefixP
220+
x <- term
221+
post <- postfixP
222+
return (post (pre x)) in
223+
224+
let rassocP = \x -> (do
225+
f <- rassocOp
226+
y <- do
227+
z <- termP
228+
rassocP1 z
229+
return (f x y)) <|> ambigiousLeft <|> ambigiousNon in
230+
231+
let rassocP1 = \x -> rassocP x <|> return x in
232+
233+
let lassocP = \x -> (do
234+
f <- lassocOp
235+
y <- termP
236+
lassocP1 (f x y)) <|> ambigiousRight <|> ambigiousNon in
237+
238+
let lassocP1 = \x -> lassocP x <|> return x in
239+
240+
let nassocP = \x -> do
241+
f <- nassocOp
242+
y <- termP
243+
ambigiousRight <|> ambigiousLeft <|> ambigiousNon <|> return (f x y)
244+
245+
in do
246+
x <- termP
247+
rassocP x <|> lassocP x <|> nassocP x <|> return x <?> "operator"
248+
249+
in foldl (makeParser) simpleExpr operators
250+

0 commit comments

Comments
 (0)