Skip to content

Strange peek behaviour/generator exception handling? #34

@deliciouslytyped

Description

@deliciouslytyped

I've been staring at this for two days and haven't been able to figure it out: I'm pretty sure at this point the problem is as described in the later paragraphs, and I rubber-ducked myself.

Disregarding my weird function naming, why does block_lex_transformer keep trying to parse past the end of the input? I figured peek() would yield a ParseError if I tried to do that, but it doesn't seem to be the case?

peek(any_char).parse_partial("") gives a ParseError.

I don't know much about how coroutines/generators work, my suspicions are that this isn't working because a GeneratorExit exception seems to come from yield peek(seq(sideToken, line(id))) , but I don't know how to deal with it.

I think that happens because googling suggests an exception in a generator will stop the generator, I didn't immediately see anything explaining how to have it continue and catch the exception?

# some context for the following snippets
from dataclasses import dataclass
from parsy import *

@dataclass
class Neutral:
    depth: int

@generate
def neutral():
    return (yield test_item(lambda i: isinstance(i, Neutral), "neutral"))

sideToken = neutral

take = test_item(lambda x: True, "any nested")

def wrap(fn):
    def thing(res):
        try:
            result = fn.parse(res)
            return success(result)
        except ParseError as e:
            return fail("idk, failure '%s'" % e)
    return thing


def line(fn):
    return take.bind(wrap(fn))

@generate
def id():
    return (yield any_char.many().concat())

@generate
def block_lex_transformer():
    token = yield sideToken  # TODO ok?
    curDepth = token.depth

    res = [Neutral(0), (yield line(id))]
    while True:
        try:
            side, ln = yield peek(seq(sideToken, line(id)))  # go to except branch if fail
        except ParseError as e:  # todo havent actually tested this explicitly
            if not e.stream:
                return res
            else:
                raise e
        if side.depth >= curDepth or ln == "":  # as deep or deeper or empty line
            (yield sideToken), (yield line(id))  # actually consume the two tokens we just peeked
            res += [side.__class__(max(side.depth - curDepth, 0)), ln]
        else:
            return res
    return res

block_lex_transformer.parse([Neutral(depth=0), 'test'])

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions