-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparser_.py
146 lines (119 loc) · 4.24 KB
/
parser_.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
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
from token_ import Token, TokenType
from expr import Binary, Expr, Grouping, Literal, Unary
class ParseError(RuntimeError):
pass
class Parser:
current = 0
def __init__(self, tokens: [Token]):
self.tokens = tokens
def _expression(self) -> Expr:
return self._equality()
#Rule- equality → comparison ( ( "!=" | "==" ) comparison )*
def _equality(self) -> Expr:
expr = self._comparison()
while self._match('BANG_EQUAL', 'EQUAL_EQUAL'):
operator: Token = self._previous(
) #Since match() advances the parser
right: Expr = self._comparison()
expr = Binary(expr, operator, right)
return expr
def _match(self, *types) -> bool:
for type_ in types:
if self._check(type_):
self._advance()
return True
return False
def _check(self, type_: TokenType) -> bool:
if self._is_at_end():
return False
return self._peek().token_type_repr == type_
def _advance(self) -> Token:
if not self._is_at_end():
self.current += 1
return self._previous()
def _is_at_end(self):
return self._peek().token_type_repr == 'EOF'
def _peek(self) -> Token:
return self.tokens[self.current]
def _previous(self) -> Token:
return self.tokens[self.current - 1]
#Rule- comparison → addition ( ( ">" | ">=" | "<" | "<=" ) addition )*
def _comparison(self) -> Expr:
expr = self._addition()
while self._match('LESS', 'LESS_EQUAL', 'GREATER', 'GREATER_EQUAL'):
operator = self._previous()
right = self._addition()
expr = Binary(expr, operator, right)
return expr
def _addition(self):
expr = self._multiplication()
while self._match('MINUS', 'PLUS'):
operator = self._previous()
right = self._multiplication()
expr = Binary(expr, operator, right)
return expr
def _multiplication(self):
expr = self._unary()
while self._match('SLASH', 'STAR'):
operator = self._previous()
right = self._unary()
expr = Binary(expr, operator, right)
return expr
#Rule- unary → ( "!" | "-" ) unary | primary
def _unary(self):
if self._match('BANG', 'MINUS'):
operator = self._previous()
right = self._unary()
return Unary(operator, right)
return self._primary()
#Rule- primary → NUMBER | STRING | "false" | "true" | "nil" | "(" expression ")"
def _primary(self):
if self._match('FALSE'):
return Literal(False)
if self._match('TRUE'):
return Literal(True)
if self._match('nil'):
return Literal(None)
if self._match('NUMBER', 'STRING'):
return Literal(self._previous().literal)
if self._match('LEFT_PAREN'):
expr = self._expression()
self._consume('RIGHT_PAREN', "Expected ')' after expression.")
return Grouping(expr)
raise self._error(self._peek(), "Expected an expression.")
def _consume(self, msg: str):
if self._check():
return self._advance()
raise self._error(self._peek(), msg)
def _error(self, token, msg):
from lox import Lox
Lox.error_token(token, msg)
return ParseError()
def _synchronize(self):
self._advance()
while not self._is_at_end():
if self._previous().token_type_repr == 'SEMICOLON':
return
curr_token = self._peek().token_type_repr
if curr_token == 'CLASS':
pass
elif curr_token == 'FUN':
pass
elif curr_token == 'VAR':
pass
elif curr_token == 'FOR':
pass
elif curr_token == 'IF':
pass
elif curr_token == 'WHILE':
pass
elif curr_token == 'PRINT':
pass
elif curr_token == 'RETURN':
pass
self._advance()
def parse(self):
try:
return self._expression()
except ParseError:
return None