Mercurial > lbo > hg > pcombinators
changeset 40:e9cb1d6b12d3 draft
Use holds everywhere
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Thu, 23 May 2019 19:54:54 +0200 |
parents | 8b9c4713b049 |
children | 23a3dfc26014 |
files | pcombinators/combinators.py pcombinators/primitives.py |
diffstat | 2 files changed, 40 insertions(+), 25 deletions(-) [+] |
line wrap: on
line diff
--- a/pcombinators/combinators.py Thu May 23 19:54:44 2019 +0200 +++ b/pcombinators/combinators.py Thu May 23 19:54:54 2019 +0200 @@ -64,15 +64,17 @@ self._transform = tf def parse(self, st): - initial = st.index() + hold = st.hold() r, st2 = self._inner.parse(st) if r is None: - st.reset(initial) + st.reset(hold) return None, st try: - return self._transform(r), st2 + r2 = self._transform(r) + st2.release(hold) + return r2, st2 except Exception as e: - st.reset(initial) + st.reset(hold) raise Exception('{} (at {} (col {}))'.format(e, st, st.index())) class _Sequence(Parser): @@ -97,19 +99,21 @@ def parse(self, st): results = [] - initial = st.index() + hold = st.hold() for p in self._parsers: - before = st.index() + before = st.hold() result, st2 = p.parse(st) if result is None: + st.reset(before) if self._atomic: - st.reset(initial) + st.reset(hold) return None, st - st.reset(before) break if result is not SKIP_MARKER: results.append(result) st = st2 + st.release(before) + st.release(hold) return results, st2 @@ -144,15 +148,16 @@ def parse(self, st): results = [] - initial = st.index() + hold = st.hold() i = 0 while i < self._times or self._times < 0: r, st2 = self._parser.parse(st) if r == None: if self._strict: - st.reset(initial) + st.reset(hold) return None, st + st.release(hold) if len(results) == 0: return SKIP_MARKER, st2 return results, st2 @@ -160,6 +165,7 @@ results.append(r) st = st2 i += 1 + st.release(hold) return results, st class StrictRepeat(_Repeat): @@ -186,12 +192,16 @@ """Attempt parsers until one matches. Result is result of that parser.""" def parse(self, st): - initial = st.index() + hold = st.hold() for p in self._parsers: + before = st.hold() r, st2 = p.parse(st) if r is not None: + st.release(before) + st.release(hold) return r, st2 - st.reset(initial) + st.reset(before) + st.reset(hold) return None, st class LongestAlternative(_Alternative): @@ -199,18 +209,19 @@ def parse(self, st): matches = [] + hold = st.hold() initial = st.index() for p in self._parsers: r, st2 = p.parse(st) if r is None: - st.reset(initial) + st.reset(hold) continue matches.append((st2.index() - initial, r)) st = st2 - st.reset(initial) + st.reset(hold) if len(matches) == 0: - st.reset(initial) + st.reset(hold) return None, st # Stable sort! matches.sort(key=lambda t: t[0]) @@ -221,7 +232,8 @@ if r[0] < best[0]: break best = r - st.reset(initial + best[0]) + st.advance(best[0]) + st.release(hold) return best[1], st # Some combinators can be implemented directly.
--- a/pcombinators/primitives.py Thu May 23 19:54:44 2019 +0200 +++ b/pcombinators/primitives.py Thu May 23 19:54:54 2019 +0200 @@ -27,15 +27,16 @@ self._s = s def parse(self, st): - initial = st.index() + hold = st.hold() s = self._s i = 0 - while i < len(s) and not st.finished() and s[i] == st.peek(): + while i < len(s) and s[i] == st.peek(): st.next() i += 1 if i == len(s): + st.release(hold) return (self._s, st) - st.reset(initial) + st.reset(hold) return (None, st) class OneOf(Parser): @@ -72,7 +73,6 @@ self._rx = rx def parse(self, st): - start = st.index() match = re.match(self._rx, st.remaining()) if match is None: return None, st @@ -82,7 +82,7 @@ result = list(match.groups()) elif len(match.groups()) > 0: result = match.group(1) - st.reset(start+end) + st.advance(end) return result, st def Nothing(): @@ -135,21 +135,23 @@ _digits = CharSet('0123456789') def parse(self, st): - initial = st.index() + hold = st.hold() multiplier = 1 minus, st = String('-').parse(st) if minus is not None: multiplier = -1 big, st = self._digits.parse(st) if big is None: - st.reset(initial) + st.reset(hold) return None, st small = '' dot, st = String('.').parse(st) if dot is not None: small, st = self._digits.parse(st) if small is not None: + st.release(hold) return float(big + '.' + small) * multiplier, st + st.release(hold) return float(big) * multiplier, st class Integer(Parser): @@ -160,13 +162,14 @@ _digits = CharSet('0123456789') def parse(self, st): - initial = st.index() + hold = st.hold() multiplier = 1 minus, st = String('-').parse(st) if minus is not None: multiplier = -1 digits, st = self._digits.parse(st) if digits is not None: + st.release(hold) return int(digits)*multiplier, st - st.reset(initial) + st.reset(hold) return None, st