-
Notifications
You must be signed in to change notification settings - Fork 42
Description
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'])