~kf5jwc/imp-parser

ref: 9a694fa0d8b73f01beb051b54cdab8a2b000be09 imp-parser/imp_parser/parser/arithmetic.py -rw-r--r-- 1.8 KiB View raw
9a694fa0 — Kyle Jones I've done more type annotating, which.... helped? 1 year, 6 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 Aexp, 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: str) -> 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[[Aexp, Aexp], 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)