## ~kf5jwc/imp-parser

ref: 4a8b0d0c4a9b3e235854c13031f981f55fc7ece5 imp-parser/imp_parser/parser/arithmetic.py -rw-r--r-- 1.7 KiB
4a8b0d0c — Kyle Jones More typing! 1 year, 7 months ago
`                                                                                `
```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```
```from functools import reduce
from typing import Callable, List, Union
from ..ast import IntAexp, BinopAexp, VarAexp
from ..imp_lexer import Tags
from .combinators import (
Reserved,
Tag,
Concat,
Exp,
Alternate,
Opt,
Rep,
Process,
Lazy,
Phrase,
)

# "we use the Process combinator (actually the ^ operator, which calls
#  Process) to convert the token into an actual integer value."
NUM = Tag(Tags.Int) ^ (lambda i: int(i))
ID = Tag(Tags.ID)
AEXP_PRECEDENCE_LEVELS = [["*", "/"], ["+", "-"]]

def keyword(kw) -> Reserved:
return Reserved(kw, Tags.Reserved)

def aexp_value() -> Alternate:
# Note! The pipe is shorthand for a combinator here.
a = NUM ^ (lambda i: IntAexp(i))
b = ID ^ (lambda v: VarAexp(v))
return a | b

def process_group(parsed) -> int:
((_, p), _) = parsed
return p

def aexp_group() -> Process:
return keyword("(") + Lazy(aexp) + keyword(")") ^ process_group

def aexp_term() -> Alternate:
return aexp_value() | aexp_group()

def process_binop(op) -> Callable[[int, int], BinopAexp]:
return lambda l, r: BinopAexp(op, l, r)

def any_operator_in_list(ops) -> Reserved:
op_parsers: List[Reserved] = [keyword(op) for op in ops]
reducer: Callable[..., Reserved] = lambda l, r: l | r;
parser = reduce(reducer, op_parsers)
return parser

def precedence(value_parser, precedence_levels, combine):
def op_parser(precedence_level):
return any_operator_in_list(precedence_level) ^ combine

parser = value_parser * op_parser(precedence_levels[0])

for precedence_level in precedence_levels[1:]:
parser = parser * op_parser(precedence_level)

return parser

def aexp():
return precedence(aexp_term(), AEXP_PRECEDENCE_LEVELS, process_binop)
```