-
Notifications
You must be signed in to change notification settings - Fork 0
/
Resolver.py
154 lines (121 loc) · 4.81 KB
/
Resolver.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
147
148
149
150
151
152
153
154
from Stmt import *
from Expr import *
from typing import List
from Interpreter import Interpreter
from enum import Enum, auto
class FunctionType(Enum):
NONE = auto()
FUNCTION = auto()
class Resolver():
def __init__(self,jesse,source,interpreter):
self.jesse = jesse
self.lines = source.splitlines()
self.interpreter = interpreter
self.scopes:List[bool] = []
self.current_function = FunctionType.NONE
def resolve(self,statements:List[Stmt]):
for statement in statements:
self.resolve_stmt(statement)
def resolve_function(self,function:BetterCall,ftype:FunctionType):
enclosing_function = self.current_function
self.current_function = ftype
self.begin_scope()
for param in function.params:
self.declare(param)
self.define(param)
self.resolve(function.body)
self.end_scope()
self.current_function = enclosing_function
def resolve_stmt(self,stmt:Stmt):
stmt.accept(self)
def resolve_expr(self,expr:Expr):
expr.accept(self)
def begin_scope(self):
self.scopes.append({})
def end_scope(self):
self.scopes.pop()
def declare(self,name:Token):
if len(self.scopes) == 0:
return
# Get the innermost/current scope
scope = self.scopes[-1]
if name.lexeme in scope:
pos = name.pos
code = self.lines[pos[0] - 1]
self.jesse.error(code,pos,"variable with this name already declared in this scope yo")
# The variable has been declared but not initialized hence False
scope[name.lexeme] = False
def define(self,name:Token):
if len(self.scopes) == 0:
return
self.scopes[-1][name.lexeme] = True
def resolve_local(self,expr:Expr,name:Token):
for i in range(len(self.scopes)-1,-1,-1):
if name.lexeme in self.scopes[i]:
self.interpreter.resolve(expr,i)
return
def visit_block_stmt(self,stmt:Block):
self.begin_scope()
self.resolve(stmt.statements)
self.end_scope()
def visit_expression_stmt(self,stmt:Expression):
self.resolve_expr(stmt.expression)
def visit_jesseif_stmt(self,stmt:JesseIf):
self.resolve_expr(stmt.condition)
self.resolve_stmt(stmt.then_branch)
if stmt.else_branch is not None:
self.resolve_stmt(stmt.else_branch)
def visit_saymyname_stmt(self,stmt:SayMyName):
self.resolve_expr(stmt.expression)
def visit_return_stmt(self,stmt:Return):
if self.current_function == FunctionType.NONE:
pos = stmt.keyword.pos
code = self.lines[pos[0] - 1]
self.jesse.error(code,pos,"you cannot return from top-level code yo")
if stmt.value is not None:
self.resolve_expr(stmt.value)
def visit_theonewhoknocks_stmt(self,stmt:TheOneWhoKnocks):
self.resolve_expr(stmt.condition)
self.resolve_stmt(stmt.body)
def visit_bettercall_stmt(self,stmt:BetterCall):
self.declare(stmt.name)
self.define(stmt.name)
self.resolve_function(stmt, FunctionType.FUNCTION)
def visit_cook_stmt(self,stmt:Cook):
self.declare(stmt.name)
if stmt.initializer is not None:
self.resolve_expr(stmt.initializer)
self.define(stmt.name)
def visit_variable_expr(self,expr:Variable):
if len(self.scopes) != 0:
scope = self.scopes[-1]
if scope.get(expr.name.lexeme) == False:
pos = expr.name.pos
code = self.lines[pos[0] - 1]
self.jesse.error(code,pos,"cannot read local variable in its own initializer yo")
self.resolve_local(expr,expr.name)
def visit_assign_expr(self,expr:Assign):
# If the RHS contains references to other variables, we need to resolve them first
self.resolve_expr(expr.value)
# Then we resolve the LHS
self.resolve_local(expr,expr.name)
def visit_binary_expr(self,expr:Binary):
self.resolve_expr(expr.left)
self.resolve_expr(expr.right)
def visit_ternary_expr(self,expr:Ternary):
self.resolve_expr(expr.condition)
self.resolve_expr(expr.then_branch)
self.resolve_expr(expr.else_branch)
def visit_call_expr(self,expr:Call):
self.resolve_expr(expr.callee)
for arg in expr.arguments:
self.resolve_expr(arg)
def visit_grouping_expr(self,expr:Grouping):
self.resolve_expr(expr.expression)
def visit_literal_expr(self,expr:Literal):
pass
def visit_logical_expr(self,expr:Logical):
self.resolve_expr(expr.left)
self.resolve_expr(expr.right)
def visit_unary_expr(self,expr:Unary):
self.resolve_expr(expr.right)