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