aboutsummaryrefslogtreecommitdiff
path: root/parser.py
blob: 6acda5df5a01b58c91c026edb56eb0cad3d5b19a (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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
from lexer import TokenType

class Expr:

    def accept(self, visitor):
        raise Exception("needs to be implemented")

    class Literal:
        def __init__(self, value):
            self.value = value
        def accept(self, visitor):
            visitor.visitLiteral(self)
        def __str__(self):
            return f"{self.value}"

    class Type:
        def __init__(self, name):
            self.name = name
        def __str__(self):
            return self.name

    class Symbol:
        def __init__(self, name):
            self.name = name
        def accept(self, visitor):
            visitor.visitSymbol(self)
        def __str__(self):
            return f"'{self.name}"

    class Nary:
        def __init__(self, symbol, args):
            self.symbol = symbol
            self.args = args
        def accept(self, visitor):
            visitor.visitNary(self)
        def __str__(self):
            out = f"[{self.symbol} => ("
            first = True
            for arg in self.args:
                if first:
                    out = f"{out} {arg}"
                    first = False
                else:
                    out = f"{out}, {arg}"
            return f"{out} )]"

    class Binary:
        def __init__(self, symbol, left, right):
            self.symbol = symbol
            self.left = left
            self.right = right
        def accept(self, visitor):
            visitor.visitBinary(self)

class Visitor:
    def visitLiteral(self, literal):
        return literal.value
    def visitBinary(self, binary):
        sym = binary.symbol.text
        left = binary.left.accept(self)
        right = binary.right.accept(self)
        return "({sym} {left} {right}"
    def visitNary(self, nary):
        sym = nary.symbol.text
        args = []
        for arg in nary.args:
            args.append(arg.accept(self))
        return "({sym} {' '.join(args)})"
    def visitSymbol(self, symbol):
        return symbol.name

def parseExpression(token, prev, tokens):
    idx = 0
    args = []
    prev = token
    while tokens[idx].type_ != TokenType.CLOSE_PAREN:
        token = tokens[idx]
        inc = 1
        if token.type_ == TokenType.OPEN_PAREN:
            expr, inc = parseExpression(token, prev, tokens[idx+1:])
            args.append(expr)
        elif token.type_ in (TokenType.STRING, TokenType.TRUE, TokenType.FALSE, TokenType.INT, TokenType.FLOAT):
            expr, inc = parseLiteral(token, prev, tokens[idx+1:])
            args.append(expr)
        elif token.type_ in (TokenType.INT_TYPE, TokenType.FLOAT_TYPE, TokenType.STRING_TYPE, TokenType.ANY_TYPE):
            expr, inc = parseType(token, prev, tokens[idx+1:])
            args.append(expr)
        else:
            expr, inc = parseSymbol(token, prev, tokens[idx+1:])
            args.append(expr)
        idx += inc
        prev = token
    
    return Expr.Nary(args[0], args[1:]), idx + 2  # parens

def parseSymbol(token, prev, tokens):
    return Expr.Symbol(token.text), 1

def parseLiteral(token, prev, tokens):
    return Expr.Literal(token.value), 1

def parseType(token, prev, tokens):
    return Expr.Type(token.text), 1

def parse(tokens):
    idx = 0
    prev = None
    exprs = []
    while tokens[idx].type_ != TokenType.EOF:
        token = tokens[idx]
        counter = 1
        if token.type_ == TokenType.OPEN_PAREN:
            expr, counter = parseExpression(token, prev, tokens[idx+1:])
            exprs.append(expr)
        elif token.type_ in (TokenType.FALSE, TokenType.TRUE, TokenType.STRING, TokenType.INT, TokenType.FLOAT):
            lit, counter = parseLiteral(token, prev, tokens[idx+1:])
            exprs.append(lit)
        elif token.type_ in (TokenType.INT_TYPE, TokenType.FLOAT_TYPE, TokenType.STRING_TYPE, TokenType.ANY_TYPE):
            typ, counter = parseType(token, prev, tokens[idx+1:])
            exprs.append(typ)
        else:
            sym, counter = parseSymbol(token, prev, tokens[idx+1:])
            exprs.append(sym)
        
        idx += counter
        prev = token
    return exprs