@@ -44,7 +44,13 @@ def _in(reference):
4444 return lambda token : token in reference
4545
4646def _ctx (start ):
47- return {"norm" : "" , "start" : start }
47+ """Creates a context, which is state for parsing (or sub-parsing)."""
48+ return {
49+ # The result value from parsing
50+ "norm" : "" ,
51+ # Where in the parser's input string this context starts.
52+ "start" : start ,
53+ }
4854
4955def _open_context (self ):
5056 """Open an new parsing ctx.
@@ -60,7 +66,16 @@ def _open_context(self):
6066 return self .contexts [- 1 ]
6167
6268def _accept (self , key = None ):
63- """Close the current ctx successfully and merge the results."""
69+ """Close the current ctx successfully and merge the results.
70+
71+ Args:
72+ self: {type}`Parser}
73+ key: {type}`str | None` the key to store the result in
74+ the most recent context. If not set, the key is "norm".
75+
76+ Returns:
77+ {type}`bool` always True
78+ """
6479 finished = self .contexts .pop ()
6580 self .contexts [- 1 ]["norm" ] += finished ["norm" ]
6681 if key :
@@ -79,7 +94,14 @@ def _discard(self, key = None):
7994 return False
8095
8196def _new (input ):
82- """Create a new normalizer"""
97+ """Create a new parser
98+
99+ Args:
100+ input: {type}`str` input to parse
101+
102+ Returns:
103+ {type}`Parser` a struct for a parser object.
104+ """
83105 self = struct (
84106 input = input ,
85107 contexts = [_ctx (0 )],
@@ -167,7 +189,7 @@ def accept_placeholder(parser):
167189 return parser .accept ()
168190
169191def accept_digits (parser ):
170- """Accept multiple digits (or placeholders).
192+ """Accept multiple digits (or placeholders), up to a non-digit/placeholder .
171193
172194 Args:
173195 parser: The normalizer.
@@ -275,7 +297,24 @@ def accept_separator_alnum(parser):
275297 Returns:
276298 whether a separator and an alphanumeric string were accepted.
277299 """
278- parser .open_context ()
300+
301+ # Input is "0.1.0+brt.9e"
302+ ctx = parser .open_context ()
303+
304+ if not accept (parser , _in (["." , "-" , "_" ]), "." ):
305+ return parser .discard ()
306+
307+ if accept_alnum (parser ):
308+ # First character is separator; skip it.
309+ value = ctx ["norm" ][1 :]
310+
311+ # PEP 440: Integer Normalization
312+ if value .isdigit ():
313+ value = str (int (value ))
314+ ctx ["norm" ] = ctx ["norm" ][0 ] + value
315+ return parser .accept ()
316+
317+ return parser .discard ()
279318
280319 # PEP 440: Local version segments
281320 if (
0 commit comments