-
Notifications
You must be signed in to change notification settings - Fork 0
/
char.py
75 lines (45 loc) · 1.7 KB
/
char.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
from .parsing import Parser, Return, Success, Failure
from .combinator import many, many1
from typing import Callable, TypeVar
from functools import partial
A = TypeVar("A")
def any() -> Parser[str]:
def parse(data: str) -> Return:
if not data:
return Failure("#any: Expected any character but got nothing", data)
return Success(data[0], data[1:])
return Parser(parse)
def eof() -> Parser[None]:
def parse(data: str) -> Return:
if not data:
return Success(None, data)
return Failure(f"#eof: Expected end of input but got [{data}]", data)
return Parser(parse)
def char(c_check: str) -> Parser[str]:
return satisfy(lambda c: c == c_check, f"#char: Failed to find [{c_check}]")
def space() -> Parser[str]:
return char(" ")
def spaces() -> Parser[list[str]]:
return many(space())
def trim(pa: Parser[A]):
return spaces() << pa >> spaces()
def whitespace() -> Parser[str]:
return satisfy(lambda c: c.isdigit, "f#whitespace: Not a whitespace char")
def whitespaces() -> Parser[list[str]]:
return many(whitespace())
def one_of(cs: list[str]) -> Parser[str]:
return satisfy(lambda c: c in cs, f"#one_of: Failed to find char in {cs}")
def none_of(cs: list[str]) -> Parser[str]:
return satisfy(lambda c: c not in cs, f"#none_of: Found char in {cs}")
def satisfy(cond: Callable[[str], bool], desc: str) -> Parser[str]:
def parse(c: str, data: str) -> Return:
return (
Success(c, data)
if cond(c)
else Failure(f"{desc}. value: [{c}], next: [{data}]", c + data)
)
return any().and_then(lambda x: Parser(partial(parse, x)))
#####
# Alias
ANY = any()
EOF = eof()