Skip to content

Commit f25601f

Browse files
committed
chaining of prefix and postfix operators
1 parent 3ad2900 commit f25601f

File tree

2 files changed

+45
-2
lines changed

2 files changed

+45
-2
lines changed

src/Parsing/Expr.purs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ makeParser term ops = do
7272
prefixOp = choice accum.prefix <?> ""
7373
postfixOp = choice accum.postfix <?> ""
7474

75-
postfixP = postfixOp <|> pure identity
76-
prefixP = prefixOp <|> pure identity
75+
postfixP = chainP (>>>) postfixOp
76+
prefixP = chainP (<<<) prefixOp
7777

7878
splitOp :: forall m s a. Operator m s a -> SplitAccum m s a -> SplitAccum m s a
7979
splitOp (Infix op AssocNone) accum = accum { nassoc = op : accum.nassoc }
@@ -108,6 +108,14 @@ nassocP x nassocOp prefixP term postfixP = do
108108
y <- termP prefixP term postfixP
109109
pure (f x y)
110110

111+
chainP :: forall m s a. ((a -> a) -> (a -> a) -> (a -> a)) -> ParserT s m (a -> a) -> ParserT s m (a -> a)
112+
chainP comp p =
113+
do
114+
op <- p
115+
rest <- chainP comp p
116+
pure (comp op rest)
117+
<|> pure identity
118+
111119
termP :: forall m s a b c. ParserT s m (a -> b) -> ParserT s m a -> ParserT s m (b -> c) -> ParserT s m c
112120
termP prefixP term postfixP = do
113121
pre <- prefixP

test/Test/Main.purs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,37 @@ exprTest = buildExprParser
104104
]
105105
digit
106106

107+
exprTest' :: Parser String Int
108+
exprTest' = buildExprParser
109+
[ [ Postfix (string "--" >>= \_ -> pure (flip (-) 1))
110+
, Postfix (string "++" >>= \_ -> pure ((+) 1))
111+
]
112+
, [ Prefix (string "-" >>= \_ -> pure negate)
113+
, Prefix (string "+" >>= \_ -> pure identity)
114+
]
115+
, [ Infix (string "/" >>= \_ -> pure (/)) AssocLeft
116+
, Infix (string "*" >>= \_ -> pure (*)) AssocLeft
117+
]
118+
, [ Infix (string "-" >>= \_ -> pure (-)) AssocLeft
119+
, Infix (string "+" >>= \_ -> pure (+)) AssocLeft
120+
]
121+
]
122+
digit
123+
124+
word :: String -> Parser String String
125+
word s = string s <* whiteSpace
126+
127+
bool :: Parser String Boolean
128+
bool = (word "True" >>= \_ -> pure true) <|> (word "False" >>= \_ -> pure false)
129+
130+
chainExprTest :: Parser String Boolean
131+
chainExprTest = buildExprParser
132+
[ [ Prefix (word "not" >>= \_ -> pure not) ]
133+
, [ Infix (word "and" >>= \_ -> pure (&&)) AssocLeft ]
134+
, [ Postfix (word "ton" >>= \_ -> pure \x -> not x) ]
135+
]
136+
bool
137+
107138
manySatisfyTest :: Parser String String
108139
manySatisfyTest = do
109140
r <- some $ satisfy (\s -> s /= '?')
@@ -662,6 +693,10 @@ main = do
662693
pure as
663694
parseTest "a+b+c" "abc" opTest
664695
parseTest "1*2+3/4-5" (-3) exprTest
696+
parseTest "1*2+3/4-5" (-3) exprTest'
697+
parseTest "1+++-2-----3+++4" (2) exprTest'
698+
parseTest "not False and not not True" (true) chainExprTest
699+
parseTest "True ton ton and False ton" (true) chainExprTest
665700
parseTest "ab?" "ab" manySatisfyTest
666701

667702
parseTest "ab" unit (char 'a' *> notFollowedBy (char 'a'))

0 commit comments

Comments
 (0)