Skip to content

Commit f35bd5e

Browse files
committed
Avoid backtracking in pattern parsers by requiring negative numbers to be wrapped in parens
1 parent bdcf81a commit f35bd5e

3 files changed

Lines changed: 37 additions & 30 deletions

File tree

src/Compiler/Parse/Number.gren

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ module Compiler.Parse.Number exposing
22
( Outcome (..)
33
, Error (..)
44
, parser
5+
, zeroOrHigher
56
, hexParser
67
, errorToString
78
)
@@ -56,8 +57,8 @@ parser =
5657
Hex (negate hex)
5758
)
5859
|> Parser.skip (Parser.token "-" NotANumber)
59-
|> Parser.keep numParser
60-
, numParser
60+
|> Parser.keep zeroOrHigher
61+
, zeroOrHigher
6162
]
6263
|> Parser.andThen
6364
(\successCase ->
@@ -69,8 +70,8 @@ parser =
6970
)
7071

7172

72-
numParser : Parser Context Error Outcome
73-
numParser =
73+
zeroOrHigher : Parser Context Error Outcome
74+
zeroOrHigher =
7475
Parser.oneOf
7576
[ Parser.chompChar '0' NotANumber
7677
|> Parser.andThen

src/Compiler/Parse/Pattern.gren

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,12 @@ parenthesized =
172172
Parser.succeed identity
173173
|> Parser.skip (Parser.chompChar '(' (ExpectedChar '('))
174174
-- When parens are used, allow `as` pattern
175-
|> Parser.keep (Parser.lazy (\_ -> parser))
175+
|> Parser.keep
176+
(Parser.oneOf
177+
[ SourcePosition.parser (numberBy Number.parser)
178+
, Parser.lazy (\_ -> parser)
179+
]
180+
)
176181
|> Parser.skip (Parser.chompChar ')' (ExpectedChar ')'))
177182

178183

@@ -192,18 +197,13 @@ term =
192197
)
193198
, lowerCaseVariable
194199
|> Parser.map AST.PVar
195-
, Parser.succeed (\start var end arg -> { ctor = SourcePosition.at start end var, arg = arg })
196-
|> Parser.keep Parser.getPosition
197-
|> Parser.keep Variable.foreignUpper
198-
|> Parser.mapError VariableError
199-
|> Parser.keep Parser.getPosition
200+
, Parser.succeed (\var arg -> { ctor = var, arg = arg })
201+
|> Parser.keep (SourcePosition.parser (Parser.mapError VariableError Variable.foreignUpper))
200202
|> Parser.skip spaceParser
201203
|> Parser.keep
202204
(Parser.oneOf
203-
[ Parser.lazy (\_ -> parserNoAlias)
204-
-- TODO: why backtrackable?
205-
|> Parser.backtrackable
206-
|> Parser.map Just
205+
[ Parser.succeed Just
206+
|> Parser.keep (Parser.lazy (\_ -> parserNoAlias))
207207
, Parser.succeed Nothing
208208
]
209209
)
@@ -224,20 +224,7 @@ term =
224224
, arg = arg
225225
}
226226
)
227-
, Number.parser
228-
|> Parser.mapError NumberError
229-
|> Parser.andThen
230-
(\num ->
231-
when num is
232-
Number.Integer int ->
233-
Parser.succeed <| AST.PInt { isHex = False, value = int }
234-
235-
Number.Hex int ->
236-
Parser.succeed <| AST.PInt { isHex = True, value = int }
237-
238-
Number.FloatingPoint _ ->
239-
Parser.problem FloatNotSupported
240-
)
227+
, numberBy Number.zeroOrHigher
241228
, String.string
242229
|> Parser.mapError StringError
243230
|> Parser.map AST.PStr
@@ -280,3 +267,21 @@ spaceParser =
280267
lowerCaseVariable : Parser Context Error String
281268
lowerCaseVariable =
282269
Parser.mapError VariableError Variable.lowerCase
270+
271+
272+
numberBy : Parser Context Number.Error Number.Outcome -> Parser Context Error AST.Pattern_
273+
numberBy numParser =
274+
numParser
275+
|> Parser.mapError NumberError
276+
|> Parser.andThen
277+
(\num ->
278+
when num is
279+
Number.Integer int ->
280+
Parser.succeed <| AST.PInt { isHex = False, value = int }
281+
282+
Number.Hex int ->
283+
Parser.succeed <| AST.PInt { isHex = True, value = int }
284+
285+
Number.FloatingPoint _ ->
286+
Parser.problem FloatNotSupported
287+
)

tests/src/Test/Compiler/Parse/Pattern.gren

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,9 @@ tests =
143143
Parser.run PT.parser Context.empty "160"
144144
|> expectPattern
145145
(AST.PInt { isHex = False, value = 160 })
146-
, test "neagtive int" <| \_ ->
147-
Parser.run PT.parser Context.empty "-10"
146+
, test "negative int" <| \_ ->
147+
-- Has to be wrapped in parens in case of '->'
148+
Parser.run PT.parser Context.empty "(-10)"
148149
|> expectPattern
149150
(AST.PInt { isHex = False, value = -10 })
150151
, test "ints (hex)" <| \_ ->

0 commit comments

Comments
 (0)