summaryrefslogtreecommitdiff
path: root/projects/hackc/expressions.py
blob: 3bc83d2f44f2c721a61dab450be3a2a31028e362 (plain)
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
76
77
78
79
80
81
82
83
84
85
86
from .tokens import Token
from .utils import *

OPS = "+-*/&|<>="
UNARY_OPS = "-~"
CONSTANTS = ["true", "false", "null", "this"]


class Term:
    def __init__(self):
        pass

    @classmethod
    def from_tokens(cls, tokens: list) -> tuple:
        if not tokens:
            return (None, 0)
        if tokens[0].type in ["integer", "string"] or tokens[0] in CONSTANTS:
            return (ConstantTerm(tokens[0]), 1)
        if tokens[0].token in UNARY_OPS:
            term, dt = Term.from_tokens(tokens[1:])
            return (UnaryTerm(tokens[0], term), dt + 1)


class ConstantTerm:
    def __init__(self, term: Token):
        self.term = term

    def __str__(self):
        return self.term.token


class VarTerm:
    def __init__(self, var: Token, subscript=None):
        self.var = var
        self.subscript = subscript


class UnaryTerm:
    def __init__(self, op: Token, term: Term):
        self.op = op
        self.term = term


class SubroutineCall:
    def __init__(self, name: Token, exprs: list):
        self.name = name
        self.exprs = exprs

    @classmethod
    def from_tokens(cls, tokens: list) -> tuple:
        pass


class Expression:
    def __init__(self, lhs: Term, op=None, rhs=None):
        self.lhs = lhs
        self.op = op
        self.rhs = rhs

    @classmethod
    def from_tokens(cls, tokens: list) -> tuple:
        """Construct expression.

        Format:
        <term> (<op> <term>)?
        """
        lhs, dt = Term.from_tokens(tokens)
        t = dt

        op = tokens[t]
        if op.token not in OPS:
            return (Expression(lhs), t)

        t += 1
        rhs, dt = Term.from_tokens(tokens[t])
        if rhs is None:
            raise JSE(f"Expected other term, got `{rhs}` instead", rhs)
        t += dt

        return (Expression(lhs, op, rhs), t)

    def __str__(self):
        if self.op is not None:
            return f"({self.lhs}) {self.op} ({self.rhs})"
        else:
            return str(self.lhs)