Mercurial > lbo > hg > pcombinators
changeset 23:c7ebd52fe5cb draft
Document list merging behavior of combinators and add inverse OneOf primitives
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Tue, 21 May 2019 00:55:46 +0200 |
parents | 9fe660fc8efe |
children | 4e31b0326501 |
files | pcombinators/combinators.py pcombinators/primitives.py |
diffstat | 2 files changed, 25 insertions(+), 5 deletions(-) [+] |
line wrap: on
line diff
--- a/pcombinators/combinators.py Tue May 21 00:03:40 2019 +0200 +++ b/pcombinators/combinators.py Tue May 21 00:55:46 2019 +0200 @@ -162,12 +162,23 @@ class AtomicSequence(_Sequence): - """Execute a series of parsers after each other. All must succeed. Result is list of results of the parsers.""" + """Execute a series of parsers after each other. All must succeed. Result + is a merged list of results of the parsers. + + This means that if your parser returns a list and you want to not merge it with the results of other + parsers in the repetition, you should wrap the list inside another list. E.g.: + + (List() >> (lambda l: [l])) + Skip(String("<separator>")) + (List() >> (lambda l: [l]))""" _atomic = True class OptimisticSequence(_Sequence): """Execute a series of parsers after each other, as far as possible - (until the first parser fails). Result is list of results of the parsers.""" + (until the first parser fails). Result is a merged list of results of the parsers. + + This means that if your parser returns a list and you want to not merge it with the results of other + parsers in the repetition, you should wrap the list inside another list. E.g.: + + (List() >> (lambda l: [l])) + Skip(String("<separator>")) + (List() >> (lambda l: [l]))""" _atomic = False class _Repeat(Parser): @@ -202,7 +213,7 @@ class Repeat(_Repeat): """Expect up to `repeat` matches of a parser. -1 means indefinitely many matches. - Result is list of results of the parsers.""" + Result is a merged list of results of the parsers.""" _strict = False def Maybe(p):
--- a/pcombinators/primitives.py Tue May 21 00:03:40 2019 +0200 +++ b/pcombinators/primitives.py Tue May 21 00:55:46 2019 +0200 @@ -39,8 +39,9 @@ return (None, st) class OneOf(Parser): - """Parse characters in the given set. Result is string or None, if none were parsed.""" + """Parse a character in the given set. Result is string or None, if none were parsed.""" _set = None + _inverse = False def __init__(self, s): """ @@ -51,11 +52,15 @@ self._set = set(s) def parse(self, st): - if not st.finished() and st.peek() in self._set: + if not st.finished() and (self._inverse ^ (st.peek() in self._set)): return st.next(), st else: return None, st +class NoneOf(OneOf): + """Parse a character not in the set. Result is string.""" + _inverse = True + class Regex(Parser): """Parse a string using a regular expression. The result is either the string or a tuple with all matched groups. Result is string.""" @@ -89,6 +94,10 @@ Result is string.""" return ConcatenateResults(Repeat(OneOf(s), -1)) +def NoneInSet(s): + """Inverse of CharSet (parse as long as character is not in set). Result is string.""" + return ConcatenateResults(Repeat(NoneOf(s), -1)) + # See section below for optimized versions of the following parsers. def CanonicalInteger():