Commits

Anonymous committed 58b6a30 Draft

add xor operator
---
pymeta/builder.py | 14 ++++++++++++++
pymeta/grammar.py | 2 ++
pymeta/runtime.py | 33 +++++++++++++++++++++++++++++++++
3 files changed, 49 insertions(+), 0 deletions(-)

Comments (0)

Files changed (3)

pymeta/builder.py

     def _not(self, expr):
         return ["Not", expr]
 
+    def _xor(self, exprs):
+        return ["Xor", exprs]
+
     def lookahead(self, expr):
         return ["Lookahead", expr]
 
         else:
             return self._generateNode(exprs[0])
 
+    def generate_Xor(self, exprs):
+        """
+        Create a call to
+        self._xor([lambda: expr1, lambda: expr2, ... , lambda: exprN]).
+        """
+        if len(exprs) > 1:
+            fnames = [self._newThunkFor("xor", expr) for expr in exprs]
+            return self._expr('xor', 'self._xor([%s])' % (', '.join(fnames)))
+        else:
+            return self._generateNode(exprs[0])
+
 
     def generate_Not(self, expr):
         """

pymeta/grammar.py

 
 expr = expr5(True):e (token('|') expr5(True))+:es !(es.insert(0, e))
           -> self.builder._or(es)
+      | expr5(True):e (token('||') expr5(True))+:es !(es.insert(0, e))
+          -> self.builder._xor(es)
       | expr5(False)
 
 ruleValue = token("->") -> self.ruleValueExpr()

pymeta/runtime.py

                 self.input = m
         raise _MaybeParseError(*joinErrors(errors))
 
+    def _xor(self, fns):
+        """
+        Call each of a list of functions in sequence until one succeeds,
+        then continue to verify no other succeed.
+
+        @param fns: A list of no-argument callables.
+        """
+        errors = []
+        ok = False
+        m = self.input
+        import pdb
+        pdb.set_trace()
+        for f in fns:
+            try:
+                self.input = m
+                ret, err = f()
+            except _MaybeParseError, e:
+                errors.append(e)
+            else:
+                errors.append(err)
+                if ok:
+                    self.input = m
+                    raise _MaybeParseError(m.position, [('message', 'xor rule matched %s and %s' % (result, ret))])
+                result = ret
+                result_input = self.input
+                ok = True
+        if not ok:
+            self.input = m
+            raise _MaybeParseError(*joinErrors(errors))
+        else:
+            self.input = result_input
+            return result, joinErrors(errors)
+
 
     def _not(self, fn):
         """