added lazy to parser
This commit is contained in:
parent
4ca3d7d51a
commit
5abefd8dbe
2 changed files with 62 additions and 0 deletions
|
|
@ -114,6 +114,10 @@ class P(Generic[T]):
|
||||||
def surround(self, other: P[Any]) -> P[T]:
|
def surround(self, other: P[Any]) -> P[T]:
|
||||||
return P.map3(other, self, other, lambda _1, v, _2: v)
|
return P.map3(other, self, other, lambda _1, v, _2: v)
|
||||||
|
|
||||||
|
def some_lazy(self) -> P[list[T]]:
|
||||||
|
return P._fix(lambda p: self.bind(
|
||||||
|
lambda x: P.either(P.pure([]), p).fmap(lambda ys: [x] + ys)))
|
||||||
|
|
||||||
def some(self) -> P[list[T]]:
|
def some(self) -> P[list[T]]:
|
||||||
return P._fix(lambda p: self.bind(
|
return P._fix(lambda p: self.bind(
|
||||||
lambda x: P.either(p, P.pure([])).fmap(lambda ys: [x] + ys)))
|
lambda x: P.either(p, P.pure([])).fmap(lambda ys: [x] + ys)))
|
||||||
|
|
@ -121,12 +125,18 @@ class P(Generic[T]):
|
||||||
def many(self) -> P[list[T]]:
|
def many(self) -> P[list[T]]:
|
||||||
return P.either(self.some(), P.pure([]))
|
return P.either(self.some(), P.pure([]))
|
||||||
|
|
||||||
|
def many_lazy(self) -> P[list[T]]:
|
||||||
|
return P.either(P.pure([]), self.some_lazy())
|
||||||
|
|
||||||
def satisfies(self, pred: Callable[[T], bool]) -> P[T]:
|
def satisfies(self, pred: Callable[[T], bool]) -> P[T]:
|
||||||
return self.bind(lambda v: P.pure(v) if pred(v) else P.fail())
|
return self.bind(lambda v: P.pure(v) if pred(v) else P.fail())
|
||||||
|
|
||||||
def optional(self) -> P[T | None]:
|
def optional(self) -> P[T | None]:
|
||||||
return P.either(self, P.pure(None))
|
return P.either(self, P.pure(None))
|
||||||
|
|
||||||
|
def optional_lazy(self) -> P[T | None]:
|
||||||
|
return P.either(P.pure(None), self)
|
||||||
|
|
||||||
def times(self, *, max: int | None = None, min: int | None = None,
|
def times(self, *, max: int | None = None, min: int | None = None,
|
||||||
exact: int | None = None) -> P[list[T]]:
|
exact: int | None = None) -> P[list[T]]:
|
||||||
match (exact, min, max):
|
match (exact, min, max):
|
||||||
|
|
@ -139,6 +149,18 @@ class P(Generic[T]):
|
||||||
case _:
|
case _:
|
||||||
raise Exception("Choose exactly one of exact, min or max")
|
raise Exception("Choose exactly one of exact, min or max")
|
||||||
|
|
||||||
|
def times_lazy(self, *, max: int | None = None, min: int | None = None,
|
||||||
|
exact: int | None = None) -> P[list[T]]:
|
||||||
|
match (exact, min, max):
|
||||||
|
case (int(e), None, None):
|
||||||
|
return self.many_lazy().satisfies(lambda lst: len(lst) == e)
|
||||||
|
case (None, int(mn), None):
|
||||||
|
return self.many_lazy().satisfies(lambda lst: len(lst) >= mn)
|
||||||
|
case (None, None, int(mx)):
|
||||||
|
return self.many_lazy().satisfies(lambda lst: len(lst) <= mx)
|
||||||
|
case _:
|
||||||
|
raise Exception("Choose exactly one of exact, min or max")
|
||||||
|
|
||||||
def sep_by(self, sep: P[Any]) -> P[list[T]]:
|
def sep_by(self, sep: P[Any]) -> P[list[T]]:
|
||||||
return P.map2(self, P.snd(sep, self).many(), lambda f, r: [f] + r)
|
return P.map2(self, P.snd(sep, self).many(), lambda f, r: [f] + r)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -205,3 +205,43 @@ def test_times_max():
|
||||||
expected = [['a', 'a'], ['a'], []]
|
expected = [['a', 'a'], ['a'], []]
|
||||||
result = list(parser.parse_multi(input))
|
result = list(parser.parse_multi(input))
|
||||||
assert result == expected
|
assert result == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_some_lazy():
|
||||||
|
input = 'aa'
|
||||||
|
parser = P.is_char('a').some_lazy()
|
||||||
|
expected = [['a'], ['a', 'a']]
|
||||||
|
result = list(parser.parse_multi(input))
|
||||||
|
assert result == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_many_lazy():
|
||||||
|
input = 'aa'
|
||||||
|
parser = P.is_char('a').many_lazy()
|
||||||
|
expected = [[], ['a'], ['a', 'a']]
|
||||||
|
result = list(parser.parse_multi(input))
|
||||||
|
assert result == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_times_lazy_exact():
|
||||||
|
input = 'aaa'
|
||||||
|
parser = P.is_char('a').times_lazy(exact=2)
|
||||||
|
expected = [['a', 'a']]
|
||||||
|
result = list(parser.parse_multi(input))
|
||||||
|
assert result == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_times_lazy_min():
|
||||||
|
input = 'aaa'
|
||||||
|
parser = P.is_char('a').times_lazy(min=2)
|
||||||
|
expected = [['a', 'a'], ['a', 'a', 'a']]
|
||||||
|
result = list(parser.parse_multi(input))
|
||||||
|
assert result == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_times_lazy_max():
|
||||||
|
input = 'aaa'
|
||||||
|
parser = P.is_char('a').times_lazy(max=2)
|
||||||
|
expected = [[], ['a'], ['a', 'a']]
|
||||||
|
result = list(parser.parse_multi(input))
|
||||||
|
assert result == expected
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue