adds tests
This commit is contained in:
parent
23529950e9
commit
d93ab67edc
11 changed files with 276 additions and 27 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
from dataclasses import dataclass
|
||||||
from typing import Generic, Optional, TypeVar
|
from typing import Generic, Optional, TypeVar
|
||||||
|
|
||||||
from .transformer import Transformer
|
from .transformer import Transformer
|
||||||
|
@ -6,6 +7,7 @@ from .parser import Parser
|
||||||
|
|
||||||
|
|
||||||
P = TypeVar("P")
|
P = TypeVar("P")
|
||||||
|
@dataclass
|
||||||
class FutureTransform(Transformer[P]):
|
class FutureTransform(Transformer[P]):
|
||||||
actual: Optional[Transformer[P]]
|
actual: Optional[Transformer[P]]
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
|
@ -24,16 +26,16 @@ class FutureTransform(Transformer[P]):
|
||||||
|
|
||||||
P = TypeVar("P")
|
P = TypeVar("P")
|
||||||
class Declare(Generic[P]):
|
class Declare(Generic[P]):
|
||||||
parser: Parser[P]
|
parser_: Parser[P]
|
||||||
transform: FutureTransform[P]
|
transform: FutureTransform[P]
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
transform = FutureTransform[P]()
|
transform = FutureTransform[P]()
|
||||||
self.parser = Parser(transform)
|
self.parser_ = Parser(transform)
|
||||||
self.transform = transform
|
self.transform = transform
|
||||||
|
|
||||||
def p(self):
|
def parser(self):
|
||||||
return self.parser
|
return self.parser_
|
||||||
|
|
||||||
def define(self, parser: Parser[P]):
|
def define(self, parser: Parser[P]):
|
||||||
self.transform.define(parser.inner)
|
self.transform.define(parser.inner)
|
||||||
|
|
|
@ -9,9 +9,8 @@ L = TypeVar("L")
|
||||||
R = TypeVar("R")
|
R = TypeVar("R")
|
||||||
@dataclass
|
@dataclass
|
||||||
class AndTransform(Transformer[tuple[L, R]]):
|
class AndTransform(Transformer[tuple[L, R]]):
|
||||||
def __init__(self, left: Transformer[L], right: Transformer[R]):
|
left: Transformer[L]
|
||||||
self.left = left
|
right: Transformer[R]
|
||||||
self.right = right
|
|
||||||
|
|
||||||
def parse(self, stream: str, at_index: int) -> Result[tuple[L, R]]:
|
def parse(self, stream: str, at_index: int) -> Result[tuple[L, R]]:
|
||||||
result_left = self.left.parse(stream, at_index)
|
result_left = self.left.parse(stream, at_index)
|
||||||
|
@ -21,3 +20,26 @@ class AndTransform(Transformer[tuple[L, R]]):
|
||||||
if isinstance(result_right, Failure):
|
if isinstance(result_right, Failure):
|
||||||
return result_right
|
return result_right
|
||||||
return Success((result_left.value, result_right.value), result_right.next_index)
|
return Success((result_left.value, result_right.value), result_right.next_index)
|
||||||
|
|
||||||
|
|
||||||
|
from okipy.lib import test
|
||||||
|
from .just import JustTransform
|
||||||
|
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_and_simple(ctx):
|
||||||
|
parser = AndTransform(JustTransform("ar"), JustTransform("bre"))
|
||||||
|
input = "arbre"
|
||||||
|
assert parser.parse(input, 0) == Success(("ar", "bre"), 5)
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_and_shifted(ctx):
|
||||||
|
parser = AndTransform(JustTransform("ar"), JustTransform("bre"))
|
||||||
|
input = "..arbre..."
|
||||||
|
assert parser.parse(input, 2) == Success(("ar", "bre"), 7)
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_and_none(ctx):
|
||||||
|
parser = AndTransform(JustTransform("ar"), JustTransform("bre"))
|
||||||
|
input = "......"
|
||||||
|
assert parser.parse(input, 2) == Failure(2, set(["ar"]))
|
||||||
|
|
|
@ -12,4 +12,26 @@ class EndTransform(Transformer[None]):
|
||||||
def parse(self, stream: str, at_index: int) -> Result[None]:
|
def parse(self, stream: str, at_index: int) -> Result[None]:
|
||||||
if len(stream) == at_index:
|
if len(stream) == at_index:
|
||||||
return Success(None, at_index)
|
return Success(None, at_index)
|
||||||
return Failure(at_index, set("<end>"))
|
return Failure(at_index, set(["<end>"]))
|
||||||
|
|
||||||
|
|
||||||
|
from okipy.lib import test
|
||||||
|
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_end_simple(ctx):
|
||||||
|
parser = EndTransform()
|
||||||
|
input = ""
|
||||||
|
assert parser.parse(input, 0) == Success(None, 0)
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_end_shifted(ctx):
|
||||||
|
parser = EndTransform()
|
||||||
|
input = ".."
|
||||||
|
assert parser.parse(input, 2) == Success(None, 2)
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_end_fails(ctx):
|
||||||
|
parser = EndTransform()
|
||||||
|
input = "arbre......"
|
||||||
|
assert parser.parse(input, 2) == Failure(2, set(["<end>"]))
|
||||||
|
|
|
@ -6,14 +6,33 @@ from ..transformer import Transformer
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class JustTransform(Transformer[str]):
|
class JustTransform(Transformer[str]):
|
||||||
def __init__(self, word: str):
|
word: str
|
||||||
self.word = word
|
|
||||||
self.word_len = len(self.word)
|
|
||||||
|
|
||||||
def parse(self, stream: str, at_index: int) -> Result[str]:
|
def parse(self, stream: str, at_index: int) -> Result[str]:
|
||||||
end_index = at_index + self.word_len
|
end_index = at_index + len(self.word)
|
||||||
prefix = stream[at_index:end_index]
|
prefix = stream[at_index:end_index]
|
||||||
if prefix == self.word:
|
if prefix == self.word:
|
||||||
return Success(self.word, end_index)
|
return Success(self.word, end_index)
|
||||||
return Failure(at_index, set([self.word]))
|
return Failure(at_index, set([self.word]))
|
||||||
|
|
||||||
|
|
||||||
|
from okipy.lib import test
|
||||||
|
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_just_simple(ctx):
|
||||||
|
parser = JustTransform("arbre")
|
||||||
|
input = "arbre"
|
||||||
|
assert parser.parse(input, 0) == Success("arbre", 5)
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_just_shifted(ctx):
|
||||||
|
parser = JustTransform("arbre")
|
||||||
|
input = "..arbre..."
|
||||||
|
assert parser.parse(input, 2) == Success("arbre", 7)
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_just_fails(ctx):
|
||||||
|
parser = JustTransform("arbre")
|
||||||
|
input = "arbre......"
|
||||||
|
assert parser.parse(input, 2) == Failure(2, set(["arbre"]))
|
||||||
|
|
|
@ -8,8 +8,7 @@ from ..transformer import Transformer
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
@dataclass
|
@dataclass
|
||||||
class ListTransform(Transformer[list[T]]):
|
class ListTransform(Transformer[list[T]]):
|
||||||
def __init__(self, item: Transformer[T]):
|
item: Transformer[T]
|
||||||
self.item = item
|
|
||||||
|
|
||||||
def parse(self, stream: str, at_index: int) -> Result[list[T]]:
|
def parse(self, stream: str, at_index: int) -> Result[list[T]]:
|
||||||
values = list[T]()
|
values = list[T]()
|
||||||
|
@ -22,3 +21,26 @@ class ListTransform(Transformer[list[T]]):
|
||||||
raise Exception("Parsing empty patterns repeatedly.")
|
raise Exception("Parsing empty patterns repeatedly.")
|
||||||
at_index = result.next_index
|
at_index = result.next_index
|
||||||
return Success(values, at_index)
|
return Success(values, at_index)
|
||||||
|
|
||||||
|
|
||||||
|
from okipy.lib import test
|
||||||
|
from .just import JustTransform
|
||||||
|
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_list_simple(ctx):
|
||||||
|
parser = ListTransform(JustTransform("arbre"))
|
||||||
|
input = "arbrearbrearbre"
|
||||||
|
assert parser.parse(input, 0) == Success(["arbre", "arbre", "arbre"], 15)
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_list_shifted(ctx):
|
||||||
|
parser = ListTransform(JustTransform("arbre"))
|
||||||
|
input = "..arbrearbre"
|
||||||
|
assert parser.parse(input, 2) == Success(["arbre", "arbre"], 12)
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_list_none(ctx):
|
||||||
|
parser = ListTransform(JustTransform("arbre"))
|
||||||
|
input = "......"
|
||||||
|
assert parser.parse(input, 2) == Success([], 2)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Callable, TypeVar
|
from typing import Callable, Generic, TypeVar
|
||||||
|
|
||||||
from ..result import Result, Success, Failure
|
from ..result import Result, Success, Failure
|
||||||
from ..transformer import Transformer
|
from ..transformer import Transformer
|
||||||
|
@ -8,8 +8,10 @@ from ..transformer import Transformer
|
||||||
I = TypeVar("I")
|
I = TypeVar("I")
|
||||||
O = TypeVar("O")
|
O = TypeVar("O")
|
||||||
@dataclass
|
@dataclass
|
||||||
class MapTransform(Transformer[O]):
|
class MapTransform(Generic[I, O], Transformer[O]):
|
||||||
def __init__(self, value: Transformer[I], transform: Callable[[I], O]):
|
value: Transformer[I]
|
||||||
|
|
||||||
|
def __init__(self, value: Transformer[I], transform: Callable[[I], O]) -> None:
|
||||||
self.value = value
|
self.value = value
|
||||||
self.transform = transform
|
self.transform = transform
|
||||||
|
|
||||||
|
@ -19,3 +21,26 @@ class MapTransform(Transformer[O]):
|
||||||
return result
|
return result
|
||||||
transformed = self.transform(result.value)
|
transformed = self.transform(result.value)
|
||||||
return Success(transformed, result.next_index)
|
return Success(transformed, result.next_index)
|
||||||
|
|
||||||
|
|
||||||
|
from okipy.lib import test
|
||||||
|
from .just import JustTransform
|
||||||
|
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_map_simple(ctx):
|
||||||
|
parser = MapTransform(JustTransform("arbre"), lambda a: (9, a))
|
||||||
|
input = "arbre"
|
||||||
|
assert parser.parse(input, 0) == Success((9, "arbre"), 5)
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_map_shifted(ctx):
|
||||||
|
parser = MapTransform(JustTransform("arbre"), lambda a: (9, a))
|
||||||
|
input = "..arbre....."
|
||||||
|
assert parser.parse(input, 2) == Success((9, "arbre"), 7)
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_map_failure(ctx):
|
||||||
|
parser = MapTransform(JustTransform("arbre"), lambda a: (9, a))
|
||||||
|
input = "......"
|
||||||
|
assert parser.parse(input, 2) == Failure(2, set(["arbre"]))
|
||||||
|
|
|
@ -8,11 +8,39 @@ from ..transformer import Transformer
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
@dataclass
|
@dataclass
|
||||||
class OptionTransform(Transformer[Optional[T]]):
|
class OptionTransform(Transformer[Optional[T]]):
|
||||||
def __init__(self, value: Transformer[T]):
|
value: Transformer[T]
|
||||||
self.value = value
|
|
||||||
|
|
||||||
def parse(self, stream: str, at_index: int) -> Result[Optional[T]]:
|
def parse(self, stream: str, at_index: int) -> Result[Optional[T]]:
|
||||||
result = self.value.parse(stream, at_index)
|
result = self.value.parse(stream, at_index)
|
||||||
if isinstance(result, Success):
|
if isinstance(result, Success):
|
||||||
return Success(result.value, result.next_index)
|
return Success(result.value, result.next_index)
|
||||||
return Success(None, at_index)
|
return Success(None, at_index)
|
||||||
|
|
||||||
|
|
||||||
|
from okipy.lib import test
|
||||||
|
from .just import JustTransform
|
||||||
|
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_opt_simple(ctx):
|
||||||
|
parser = OptionTransform(JustTransform("arbre"))
|
||||||
|
input = "arbre"
|
||||||
|
assert parser.parse(input, 0) == Success("arbre", 5)
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_opt_none(ctx):
|
||||||
|
parser = OptionTransform(JustTransform("arbre"))
|
||||||
|
input = "brear"
|
||||||
|
assert parser.parse(input, 0) == Success(None, 0)
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_opt_shifted(ctx):
|
||||||
|
parser = OptionTransform(JustTransform("arbre"))
|
||||||
|
input = "..arbre..."
|
||||||
|
assert parser.parse(input, 2) == Success("arbre", 7)
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_opt_none_shifted(ctx):
|
||||||
|
parser = OptionTransform(JustTransform("arbre"))
|
||||||
|
input = "..rbrea..."
|
||||||
|
assert parser.parse(input, 2) == Success(None, 2)
|
||||||
|
|
|
@ -9,9 +9,8 @@ L = TypeVar("L")
|
||||||
R = TypeVar("R")
|
R = TypeVar("R")
|
||||||
@dataclass
|
@dataclass
|
||||||
class OrTransform(Transformer[Union[L, R]]):
|
class OrTransform(Transformer[Union[L, R]]):
|
||||||
def __init__(self, left: Transformer[L], right: Transformer[R]):
|
left: Transformer[L]
|
||||||
self.left = left
|
right: Transformer[R]
|
||||||
self.right = right
|
|
||||||
|
|
||||||
def parse(self, stream: str, at_index: int) -> Result[Union[L, R]]:
|
def parse(self, stream: str, at_index: int) -> Result[Union[L, R]]:
|
||||||
result_left = self.left.parse(stream, at_index)
|
result_left = self.left.parse(stream, at_index)
|
||||||
|
@ -21,3 +20,32 @@ class OrTransform(Transformer[Union[L, R]]):
|
||||||
if isinstance(result_right, Success):
|
if isinstance(result_right, Success):
|
||||||
return Success(result_right.value, result_right.next_index)
|
return Success(result_right.value, result_right.next_index)
|
||||||
return Failure(at_index, result_left.expected.union(result_right.expected))
|
return Failure(at_index, result_left.expected.union(result_right.expected))
|
||||||
|
|
||||||
|
|
||||||
|
from okipy.lib import test
|
||||||
|
from .just import JustTransform
|
||||||
|
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_or_simple(ctx):
|
||||||
|
parser = OrTransform(JustTransform("ar"), JustTransform("bre"))
|
||||||
|
input = "arbre"
|
||||||
|
assert parser.parse(input, 0) == Success("ar", 2)
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_or_other(ctx):
|
||||||
|
parser = OrTransform(JustTransform("ar"), JustTransform("bre"))
|
||||||
|
input = "brear"
|
||||||
|
assert parser.parse(input, 0) == Success("bre", 3)
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_or_shifted(ctx):
|
||||||
|
parser = OrTransform(JustTransform("ar"), JustTransform("bre"))
|
||||||
|
input = "..arbre..."
|
||||||
|
assert parser.parse(input, 2) == Success("ar", 4)
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_or_fail(ctx):
|
||||||
|
parser = OrTransform(JustTransform("ar"), JustTransform("bre"))
|
||||||
|
input = "......"
|
||||||
|
assert parser.parse(input, 2) == Failure(2, set(["ar", "bre"]))
|
||||||
|
|
|
@ -7,13 +7,40 @@ from ..transformer import Transformer
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class RegexTransform(Transformer[str]):
|
class RegexTransform(Transformer[str]):
|
||||||
def __init__(self, pattern: str):
|
pattern: str
|
||||||
self.pattern = pattern
|
|
||||||
|
|
||||||
def parse(self, stream: str, at_index: int) -> Result[str]:
|
def parse(self, stream: str, at_index: int) -> Result[str]:
|
||||||
do_match = re.match(self.pattern, stream[at_index:])
|
do_match = re.match(self.pattern, stream[at_index:])
|
||||||
if do_match is None:
|
if do_match is None:
|
||||||
return Failure(at_index, set(f"<matching '{self.pattern}'>"))
|
return Failure(at_index, set([f"<matching '{self.pattern}'>"]))
|
||||||
else:
|
else:
|
||||||
match = do_match[0]
|
match = do_match[0]
|
||||||
return Success(match, at_index + len(match))
|
return Success(match, at_index + len(match))
|
||||||
|
|
||||||
|
|
||||||
|
from okipy.lib import test
|
||||||
|
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_regex_simple(ctx):
|
||||||
|
parser = RegexTransform("arbre")
|
||||||
|
input = "arbre"
|
||||||
|
assert parser.parse(input, 0) == Success("arbre", 5)
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_regex_shifted(ctx):
|
||||||
|
parser = RegexTransform("arbre")
|
||||||
|
input = "..arbre..."
|
||||||
|
assert parser.parse(input, 2) == Success("arbre", 7)
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_regex_fails(ctx):
|
||||||
|
parser = RegexTransform("arbre")
|
||||||
|
input = "arbre......"
|
||||||
|
assert parser.parse(input, 2) == Failure(2, set(["<matching 'arbre'>"]))
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_regex_some(ctx):
|
||||||
|
parser = RegexTransform("[0-3]+")
|
||||||
|
input = "012345"
|
||||||
|
assert parser.parse(input, 0) == Success("0123", 4)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Optional, TypeVar
|
from typing import Generic, Optional, TypeVar
|
||||||
|
|
||||||
from ..result import Result
|
from ..result import Result
|
||||||
from ..transformer import Transformer
|
from ..transformer import Transformer
|
||||||
|
@ -13,7 +13,10 @@ from .list import ListTransform
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
S = TypeVar("S")
|
S = TypeVar("S")
|
||||||
@dataclass
|
@dataclass
|
||||||
class SepListTransform(Transformer[list[T]]):
|
class SepListTransform(Generic[T, S], Transformer[list[T]]):
|
||||||
|
items: Transformer[T]
|
||||||
|
sep: Transformer[S]
|
||||||
|
|
||||||
def __init__(self, items: Transformer[T], sep: Transformer[S]):
|
def __init__(self, items: Transformer[T], sep: Transformer[S]):
|
||||||
self.items = items
|
self.items = items
|
||||||
self.sep = sep
|
self.sep = sep
|
||||||
|
@ -33,3 +36,33 @@ class SepListTransform(Transformer[list[T]]):
|
||||||
for (_sep, item) in value[1]:
|
for (_sep, item) in value[1]:
|
||||||
items.append(item)
|
items.append(item)
|
||||||
return items
|
return items
|
||||||
|
|
||||||
|
|
||||||
|
from okipy.lib import test
|
||||||
|
from .just import JustTransform
|
||||||
|
from ..result import Result, Success, Failure
|
||||||
|
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_sep_simple(ctx):
|
||||||
|
parser = SepListTransform(JustTransform("arbre"), JustTransform(","))
|
||||||
|
input = "arbre"
|
||||||
|
assert parser.parse(input, 0) == Success(["arbre"], 5)
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_sep_alt(ctx):
|
||||||
|
parser = SepListTransform(JustTransform("arbre"), JustTransform(","))
|
||||||
|
input = "arbre,arbre"
|
||||||
|
assert parser.parse(input, 0) == Success(["arbre", "arbre"], 11)
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_sep_none(ctx):
|
||||||
|
parser = SepListTransform(JustTransform("arbre"), JustTransform(","))
|
||||||
|
input = ""
|
||||||
|
assert parser.parse(input, 2) == Success([], 2)
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_sep_missing_not_failure(ctx):
|
||||||
|
parser = SepListTransform(JustTransform("arbre"), JustTransform(","))
|
||||||
|
input = "arbre,"
|
||||||
|
assert parser.parse(input, 0) == Success(['arbre'], 5)
|
||||||
|
|
|
@ -11,8 +11,29 @@ I = TypeVar("I")
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
@dataclass
|
@dataclass
|
||||||
class ValueTransform(Transformer[T]):
|
class ValueTransform(Transformer[T]):
|
||||||
|
value: T
|
||||||
|
|
||||||
def __init__(self, ignored: Transformer[I], value: T):
|
def __init__(self, ignored: Transformer[I], value: T):
|
||||||
|
self.value = value
|
||||||
self.actual = MapTransform(ignored, lambda _: value)
|
self.actual = MapTransform(ignored, lambda _: value)
|
||||||
|
|
||||||
def parse(self, stream: str, at_index: int) -> Result[T]:
|
def parse(self, stream: str, at_index: int) -> Result[T]:
|
||||||
return self.actual.parse(stream, at_index)
|
return self.actual.parse(stream, at_index)
|
||||||
|
|
||||||
|
|
||||||
|
from okipy.lib import test
|
||||||
|
from .just import JustTransform
|
||||||
|
from ..result import Result, Success, Failure
|
||||||
|
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_value_simple(ctx):
|
||||||
|
parser = ValueTransform(JustTransform("arbre"), "Feur")
|
||||||
|
input = "arbre"
|
||||||
|
assert parser.parse(input, 0) == Success("Feur", 5)
|
||||||
|
|
||||||
|
@test()
|
||||||
|
def test_value_failure(ctx):
|
||||||
|
parser = ValueTransform(JustTransform("arbre"), lambda a: (9, a))
|
||||||
|
input = "......"
|
||||||
|
assert parser.parse(input, 2) == Failure(2, set(["arbre"]))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue