def parse_Or(self, expr): """ Execute multiple subexpressions, returning the result of the first one that succeeds. """ errors = [] i = self.input for subexpr in expr.args: try: for x in self._eval(subexpr): if x is _feed_me: yield x val, p = x errors.append(p) self.currentError = joinErrors(errors) yield x return except ParseError as err: errors.append(err) self.input = i raise self.err(joinErrors(errors))
i = run.input try: return self._eval(run, args[0]) except ParseError: run.input = i return (None, run.input.nullError()) elif name == "Or": errors = [] for e in args[0].args: try: m = run.input x = self._eval(run, e) ret, err = x errors.append(err) return ret, joinErrors(errors) except ParseError, err: errors.append(err) run.input = m raise joinErrors(errors) elif name == "Not": m = run.input try: self._eval(run, args[0]) except ParseError, err: run.input = m return True, run.input.nullError() else: raise run.input.nullError()
def _eval(self, run, expr): name = expr.tag.name args = expr.args if name == "Apply": ruleName = args[0].data return self._apply(run, ruleName, args[2].args) elif name == "Exactly": return run.exactly(args[0].data) elif name == "Label": label = args[1].data try: val, err = self._eval(run, args[0]) return val, err.withMessage([("Custom Exception:", label, None)]) except ParseError as err: e=err raise e.withMessage([("Custom Exception:", label, None)]) elif name == "Token": if run.tree: return run._apply(run.rule_exactly, "exactly", [args[0].data]) else: return run._apply(run.rule_token, "token", [args[0].data]) elif name in ("Many", "Many1"): ans = [self._eval(run, args[0])[0]] if name == "Many1" else [] err = None while True: try: m = run.input v, _ = self._eval(run, args[0]) ans.append(v) except ParseError as e: err = e run.input = m break return ans, err elif name == "Repeat": if args[0].tag.name == '.int.': min = args[0].data else: min = self._localsStack[-1][args[0].data] if args[1].tag.name == '.int.': max = args[1].data elif args[1].tag.name == 'null': max = None else: max = self._localsStack[-1][args[1].data] if min == max == 0: return "", None ans = [] e = None for i in range(min): v, e = self._eval(run, args[2]) ans.append(v) for i in range(min, max): try: m = run.input v, e = self._eval(run, args[2]) ans.append(v) except ParseError as err: e = err run.input = m break return ans, e elif name == "Optional": i = run.input try: return self._eval(run, args[0]) except ParseError: run.input = i return (None, run.input.nullError()) elif name == "Or": errors = [] for e in args[0].args: try: m = run.input x = self._eval(run, e) ret, err = x errors.append(err) return ret, joinErrors(errors) except ParseError as err: errors.append(err) run.input = m raise joinErrors(errors) elif name == "Not": m = run.input try: self._eval(run, args[0]) except ParseError as err: run.input = m return True, run.input.nullError() else: raise run.input.nullError() elif name == "Lookahead": try: m = run.input return self._eval(run, args[0]) finally: run.input = m elif name == "And": v = None, run.input.nullError() for e in args[0].args: v = self._eval(run, e) return v elif name == "Bind": v, err = self._eval(run, args[1]) if args[0].data: self._localsStack[-1][args[0].data] = v else: for n, val in zip(args[0].args, v): self._localsStack[-1][n.data] = val return v, err elif name == "Predicate": val, err = self._eval(run, args[0]) if not val: raise err else: return True, err elif name == "List": v, e = run.rule_anything() oldInput = run.input try: run.input = InputStream.fromIterable(v) except TypeError: raise e.withMessage(expected("an iterable")) self._eval(run, args[0]) run.end() run.input = oldInput return v, e elif name in ("Action", "Python"): lo = self._localsStack[-1] val = eval(args[0].data, self._globals, lo) return (val, run.input.nullError()) elif name == "ConsumedBy": oldInput = run.input _, err = self._eval(run, args[0]) slice = oldInput.data[oldInput.position:run.input.position] return slice, err else: raise ValueError("Unrecognized term: %r" % (name,))
class TrampolinedGrammarInterpreter(object): """ An interpreter for OMeta grammars that processes input incrementally. """ def __init__(self, grammar, ruleName, callback=None, globals=None): self.grammar = grammar self.position = 0 self.callback = callback self.globals = globals or {} self.rules = decomposeGrammar(grammar) self.next = self.apply(ruleName, None, ()) self._localsStack = [] self.currentResult = None self.input = InputStream([], 0) self.ended = False def receive(self, buf): """ Feed data to the parser. """ if not buf: # No data. Nothing to do. return if self.ended: raise ValueError("Can't feed a parser that's been ended.") self.input.data.extend(buf) x = None for x in self.next: if x is _feed_me: return x if self.callback: self.callback(*x) self.ended = True def end(self): """ Close the input stream, indicating to the grammar that no more input will arrive. """ if self.ended: return self.ended = True x = None for x in self.next: pass if self.callback: self.callback(*x) def error(self, typ, val, trail=None): raise ParseError(''.join(self.input.data), typ, val, trail=trail) ## Implementation note: each method, instead of being a function ## returning a value, is a generator that will yield '_feed_me' an ## arbitrary number of times, then finally yield the value of the ## expression being evaluated. def _apply(self, rule, ruleName, args): """ Apply a rule method to some args. @param rule: A method of this object. @param ruleName: The name of the rule invoked. @param args: A sequence of arguments to it. """ if args: if ((not getattr(rule, 'func_code', None)) or rule.func_code.co_argcount - 1 != len(args)): for arg in args[::-1]: self.input = ArgInput(arg, self.input) g = rule() else: g = rule(*args) for x in g: if x is _feed_me: yield x yield x return memoRec = self.input.getMemo(ruleName) if memoRec is None: oldPosition = self.input lr = LeftRecursion() memoRec = self.input.setMemo(ruleName, lr) try: inp = self.input for x in rule(): if x is _feed_me: yield x memoRec = inp.setMemo(ruleName, [x, self.input]) except ParseError: raise if lr.detected: sentinel = self.input while True: try: self.input = oldPosition for x in rule(): if x is _feed_me: yield x ans = x if (self.input == sentinel): break memoRec = oldPosition.setMemo(ruleName, [ans, self.input]) except ParseError: break self.input = oldPosition elif isinstance(memoRec, LeftRecursion): memoRec.detected = True self.error(None, None) self.input = memoRec[1] yield memoRec[0] def _eval(self, expr): """ Dispatch to a parse_<term name> method for the given grammar expression. """ return getattr(self, "parse_" + expr.tag.name)(*expr.args) def parse_Apply(self, ruleName, codeName, args): for x in self.apply(ruleName.data, codeName.data, args.args): if x is _feed_me: yield x yield x def apply(self, ruleName, codeName, args): """ Invoke a rule, optionally with arguments. """ argvals = [] for a in args: for x in self._eval(a): if x is _feed_me: yield x argvals.append(x[0]) _locals = {} self._localsStack.append(_locals) try: #XXX super rul = self.rules.get(ruleName) if rul: def f(): return self._eval(rul) else: #ruleName may be a Twine, so gotta call str() f = getattr(self, str('rule_' + ruleName)) for x in self._apply(f, ruleName, argvals): if x is _feed_me: yield x yield x finally: self._localsStack.pop() def parse_Exactly(self, spec): """ Accept a one or more characters that equal the given spec. """ wanted = spec.data result = [] for c in wanted: try: val, p = self.input.head() except EOFError: yield _feed_me val, p = self.input.head() result.append(val) if val == c: self.input = self.input.tail() else: self.error(''.join(result), expected(None, wanted)) yield ''.join(result), p def parse_Token(self, spec): """ Consume leading whitespace then the given string. """ val = ' ' while val.isspace(): try: val, p = self.input.head() except EOFError: yield _feed_me val, p = self.input.head() if val.isspace(): self.input = self.input.tail() wanted = spec.data result = [] for c in wanted: try: val, p = self.input.head() except EOFError: yield _feed_me val, p = self.input.head() result.append(val) if val == c: self.input = self.input.tail() else: self.error(''.join(result), expected(None, wanted)) yield ''.join(result), p def parse_And(self, expr): """ Execute multiple subexpressions in order, returning the result of the last one. """ seq = expr.args x = None, self.input.nullError() for subexpr in seq: for x in self._eval(subexpr): if x is _feed_me: yield x self.currentError = x[1] yield x def parse_Or(self, expr): """ Execute multiple subexpressions, returning the result of the first one that succeeds. """ errors = [] i = self.input for subexpr in expr.args: try: for x in self._eval(subexpr): if x is _feed_me: yield x val, p = x errors.append(p) self.currentError = joinErrors(errors) yield x return except ParseError, err: errors.append(err) self.input = i self.error(*joinErrors(errors))
def _eval(self, run, expr): name = expr.tag.name args = expr.args if name == "Apply": ruleName = args[0].data return self._apply(run, ruleName, args[2].args) elif name == "Exactly": return run.exactly(args[0].data) elif name == "Label": label = args[1].data try: val, err = self._eval(run, args[0]) return val, err.withMessage([("Custom Exception:", label, None) ]) except ParseError as err: e = err raise e.withMessage([("Custom Exception:", label, None)]) elif name == "Token": if run.tree: return run._apply(run.rule_exactly, "exactly", [args[0].data]) else: return run._apply(run.rule_token, "token", [args[0].data]) elif name in ("Many", "Many1"): ans = [self._eval(run, args[0])[0]] if name == "Many1" else [] err = None while True: try: m = run.input v, _ = self._eval(run, args[0]) ans.append(v) except ParseError as e: err = e run.input = m break return ans, err elif name == "Repeat": if args[0].tag.name == '.int.': min = args[0].data else: min = self._localsStack[-1][args[0].data] if args[1].tag.name == '.int.': max = args[1].data elif args[1].tag.name == 'null': max = None else: max = self._localsStack[-1][args[1].data] if min == max == 0: return "", None ans = [] e = None for i in range(min): v, e = self._eval(run, args[2]) ans.append(v) for i in range(min, max): try: m = run.input v, e = self._eval(run, args[2]) ans.append(v) except ParseError as err: e = err run.input = m break return ans, e elif name == "Optional": i = run.input try: return self._eval(run, args[0]) except ParseError: run.input = i return (None, run.input.nullError()) elif name == "Or": errors = [] for e in args[0].args: try: m = run.input x = self._eval(run, e) ret, err = x errors.append(err) return ret, joinErrors(errors) except ParseError as err: errors.append(err) run.input = m raise joinErrors(errors) elif name == "Not": m = run.input try: self._eval(run, args[0]) except ParseError as err: run.input = m return True, run.input.nullError() else: raise run.input.nullError() elif name == "Lookahead": try: m = run.input return self._eval(run, args[0]) finally: run.input = m elif name == "And": v = None, run.input.nullError() for e in args[0].args: v = self._eval(run, e) return v elif name == "Bind": v, err = self._eval(run, args[1]) if args[0].data: self._localsStack[-1][args[0].data] = v else: for n, val in zip(args[0].args, v): self._localsStack[-1][n.data] = val return v, err elif name == "Predicate": val, err = self._eval(run, args[0]) if not val: raise err else: return True, err elif name == "List": v, e = run.rule_anything() oldInput = run.input try: run.input = InputStream.fromIterable(v) except TypeError: raise e.withMessage(expected("an iterable")) self._eval(run, args[0]) run.end() run.input = oldInput return v, e elif name in ("Action", "Python"): lo = self._localsStack[-1] val = eval(args[0].data, self._globals, lo) return (val, run.input.nullError()) elif name == "ConsumedBy": oldInput = run.input _, err = self._eval(run, args[0]) slice = oldInput.data[oldInput.position:run.input.position] return slice, err else: raise ValueError("Unrecognized term: %r" % (name, ))