示例#1
0
 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))
示例#2
0
 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))
示例#3
0
            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()
示例#4
0
    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,))
示例#5
0
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))
示例#6
0
            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()
示例#7
0
    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, ))