easycoder 251104.1__py2.py3-none-any.whl → 260108.1__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of easycoder might be problematic. Click here for more details.
- easycoder/__init__.py +6 -3
- easycoder/debugger/__init__.py +5 -0
- easycoder/debugger/ec_dbg_value_display copy.py +195 -0
- easycoder/debugger/ec_dbg_value_display.py +24 -0
- easycoder/debugger/ec_dbg_watch_list copy.py +219 -0
- easycoder/debugger/ec_dbg_watchlist.py +293 -0
- easycoder/debugger/ec_debug.py +1025 -0
- easycoder/ec_border.py +15 -11
- easycoder/ec_classes.py +494 -7
- easycoder/ec_compiler.py +82 -44
- easycoder/ec_condition.py +1 -1
- easycoder/ec_core.py +1043 -1089
- easycoder/ec_gclasses.py +236 -0
- easycoder/ec_graphics.py +1683 -0
- easycoder/ec_handler.py +18 -13
- easycoder/ec_keyboard.py +50 -50
- easycoder/ec_mqtt.py +249 -0
- easycoder/ec_program.py +313 -152
- easycoder/ec_psutil.py +48 -0
- easycoder/ec_timestamp.py +2 -1
- easycoder/ec_value.py +65 -47
- easycoder/icons/exit.png +0 -0
- easycoder/icons/run.png +0 -0
- easycoder/icons/step.png +0 -0
- easycoder/icons/stop.png +0 -0
- easycoder/pre/README.md +3 -0
- easycoder/pre/__init__.py +17 -0
- easycoder/pre/debugger/__init__.py +5 -0
- easycoder/pre/debugger/ec_dbg_value_display copy.py +195 -0
- easycoder/pre/debugger/ec_dbg_value_display.py +24 -0
- easycoder/pre/debugger/ec_dbg_watch_list copy.py +219 -0
- easycoder/pre/debugger/ec_dbg_watchlist.py +293 -0
- easycoder/pre/debugger/ec_debug.py +1014 -0
- easycoder/pre/ec_border.py +67 -0
- easycoder/pre/ec_classes.py +470 -0
- easycoder/pre/ec_compiler.py +291 -0
- easycoder/pre/ec_condition.py +27 -0
- easycoder/pre/ec_core.py +2772 -0
- easycoder/pre/ec_gclasses.py +230 -0
- easycoder/{ec_pyside.py → pre/ec_graphics.py} +631 -494
- easycoder/pre/ec_handler.py +79 -0
- easycoder/pre/ec_keyboard.py +439 -0
- easycoder/pre/ec_program.py +557 -0
- easycoder/pre/ec_psutil.py +48 -0
- easycoder/pre/ec_timestamp.py +11 -0
- easycoder/pre/ec_value.py +124 -0
- easycoder/pre/icons/close.png +0 -0
- easycoder/pre/icons/exit.png +0 -0
- easycoder/pre/icons/run.png +0 -0
- easycoder/pre/icons/step.png +0 -0
- easycoder/pre/icons/stop.png +0 -0
- easycoder/pre/icons/tick.png +0 -0
- {easycoder-251104.1.dist-info → easycoder-260108.1.dist-info}/METADATA +11 -1
- easycoder-260108.1.dist-info/RECORD +59 -0
- easycoder-251104.1.dist-info/RECORD +0 -19
- /easycoder/{close.png → icons/close.png} +0 -0
- /easycoder/{tick.png → icons/tick.png} +0 -0
- {easycoder-251104.1.dist-info → easycoder-260108.1.dist-info}/WHEEL +0 -0
- {easycoder-251104.1.dist-info → easycoder-260108.1.dist-info}/entry_points.txt +0 -0
- {easycoder-251104.1.dist-info → easycoder-260108.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from .ec_classes import FatalError
|
|
3
|
+
from .ec_value import Value
|
|
4
|
+
from .ec_condition import Condition
|
|
5
|
+
|
|
6
|
+
class Compiler:
|
|
7
|
+
|
|
8
|
+
def __init__(self, program):
|
|
9
|
+
self.program = program
|
|
10
|
+
self.value = Value(self)
|
|
11
|
+
self.condition = Condition(self)
|
|
12
|
+
self.marker = 0
|
|
13
|
+
self.script = self.program.script
|
|
14
|
+
self.tokens = self.script.tokens
|
|
15
|
+
self.symbols = self.program.symbols
|
|
16
|
+
self.code = self.program.code
|
|
17
|
+
self.program.compiler = self
|
|
18
|
+
self.compileConstant = self.value.compileConstant
|
|
19
|
+
self.debugCompile = False
|
|
20
|
+
self.valueTypes = {}
|
|
21
|
+
|
|
22
|
+
# Get the current code size. Used during compilation
|
|
23
|
+
def getCodeSize(self):
|
|
24
|
+
return len(self.program.code)
|
|
25
|
+
|
|
26
|
+
# Get the current index (the program counter)
|
|
27
|
+
def getIndex(self):
|
|
28
|
+
return self.index
|
|
29
|
+
|
|
30
|
+
# Move the index along
|
|
31
|
+
def next(self):
|
|
32
|
+
self.index += 1
|
|
33
|
+
|
|
34
|
+
# Get the current token
|
|
35
|
+
def getToken(self):
|
|
36
|
+
if self.index >= len(self.tokens):
|
|
37
|
+
FatalError(self, 'Premature end of script')
|
|
38
|
+
return self.tokens[self.index].token
|
|
39
|
+
|
|
40
|
+
# Get the next token
|
|
41
|
+
def nextToken(self):
|
|
42
|
+
self.index += 1
|
|
43
|
+
return self.getToken()
|
|
44
|
+
|
|
45
|
+
# Peek ahead to see the next token without advancing the index
|
|
46
|
+
def peek(self):
|
|
47
|
+
try:
|
|
48
|
+
return self.tokens[self.index + 1].token
|
|
49
|
+
except:
|
|
50
|
+
return None
|
|
51
|
+
|
|
52
|
+
# Get a constant
|
|
53
|
+
def getConstant(self, token):
|
|
54
|
+
self.index += 1
|
|
55
|
+
return self.compileConstant(token)
|
|
56
|
+
|
|
57
|
+
# Get a value
|
|
58
|
+
def getValue(self):
|
|
59
|
+
self.program.ensureNotRunning()
|
|
60
|
+
return self.value.compileValue()
|
|
61
|
+
|
|
62
|
+
# Get the next value
|
|
63
|
+
def nextValue(self):
|
|
64
|
+
self.program.ensureNotRunning()
|
|
65
|
+
self.index += 1
|
|
66
|
+
return self.value.compileValue()
|
|
67
|
+
|
|
68
|
+
# Get a condition
|
|
69
|
+
def getCondition(self):
|
|
70
|
+
return self.condition.compileCondition()
|
|
71
|
+
|
|
72
|
+
# Get the next condition
|
|
73
|
+
def nextCondition(self):
|
|
74
|
+
self.index += 1
|
|
75
|
+
return self.condition.compileCondition()
|
|
76
|
+
|
|
77
|
+
# Test if the current token has a specified value
|
|
78
|
+
def tokenIs(self, value):
|
|
79
|
+
return self.getToken() == value
|
|
80
|
+
|
|
81
|
+
# Test if the next token has the specified value
|
|
82
|
+
def nextIs(self, value):
|
|
83
|
+
return self.nextToken() == value
|
|
84
|
+
|
|
85
|
+
# Get the command at a given pc in the code list
|
|
86
|
+
def getCommandAt(self, pc):
|
|
87
|
+
return self.program.code[pc]
|
|
88
|
+
|
|
89
|
+
# Add a command to the code list
|
|
90
|
+
def addCommand(self, command, debug=True):
|
|
91
|
+
command['debug'] = debug
|
|
92
|
+
command['bp'] = False
|
|
93
|
+
self.code.append(command)
|
|
94
|
+
|
|
95
|
+
# Test if the current token is a symbol
|
|
96
|
+
def isSymbol(self):
|
|
97
|
+
token = self.getToken()
|
|
98
|
+
try:
|
|
99
|
+
self.symbols[token]
|
|
100
|
+
except:
|
|
101
|
+
return False
|
|
102
|
+
return True
|
|
103
|
+
|
|
104
|
+
# Test if the next token is a symbol
|
|
105
|
+
def nextIsSymbol(self):
|
|
106
|
+
self.next()
|
|
107
|
+
return self.isSymbol()
|
|
108
|
+
|
|
109
|
+
# Skip the next token if it matches the value given
|
|
110
|
+
def skip(self, token):
|
|
111
|
+
next = self.peek()
|
|
112
|
+
if type(token) == list:
|
|
113
|
+
for item in token:
|
|
114
|
+
if next == item:
|
|
115
|
+
self.nextToken()
|
|
116
|
+
return
|
|
117
|
+
elif next == token:
|
|
118
|
+
self.nextToken()
|
|
119
|
+
|
|
120
|
+
# Skip common articles (optional syntactic noise for readability/disambiguation)
|
|
121
|
+
# Consumes leading articles ('the', 'a', 'an') at the next position
|
|
122
|
+
def skipArticles(self):
|
|
123
|
+
# Consume leading articles at next position(s) — like skip() but for multiple
|
|
124
|
+
while True:
|
|
125
|
+
next_tok = self.peek()
|
|
126
|
+
if next_tok in ['the', 'a', 'an']:
|
|
127
|
+
self.nextToken()
|
|
128
|
+
else:
|
|
129
|
+
break
|
|
130
|
+
|
|
131
|
+
# Rewind to a given position in the code list
|
|
132
|
+
def rewindTo(self, index):
|
|
133
|
+
self.index = index
|
|
134
|
+
|
|
135
|
+
# Get source line number containing the current token
|
|
136
|
+
def getLino(self):
|
|
137
|
+
if self.index >= len(self.tokens):
|
|
138
|
+
return 0
|
|
139
|
+
return self.tokens[self.index].lino
|
|
140
|
+
|
|
141
|
+
# Issue a warning
|
|
142
|
+
def warning(self, message):
|
|
143
|
+
self.warnings.append(f'Warning at line {self.getLino() + 1} of {self.program.name}: {message}')
|
|
144
|
+
|
|
145
|
+
# Print all warnings
|
|
146
|
+
def showWarnings(self):
|
|
147
|
+
for warning in self.warnings:
|
|
148
|
+
print(warning)
|
|
149
|
+
|
|
150
|
+
# Get the symbol record for the current token (assumes it is a symbol name)
|
|
151
|
+
def getSymbolRecord(self, name=None):
|
|
152
|
+
self.program.ensureNotRunning()
|
|
153
|
+
if name == None: name = self.getToken()
|
|
154
|
+
if not name in self.symbols:
|
|
155
|
+
FatalError(self, f'Undefined symbol name "{name}"')
|
|
156
|
+
return None
|
|
157
|
+
symbol = self.symbols[name]
|
|
158
|
+
if symbol == None: return None
|
|
159
|
+
record = self.code[symbol]
|
|
160
|
+
record['used'] = True
|
|
161
|
+
return record
|
|
162
|
+
|
|
163
|
+
# Add a value type
|
|
164
|
+
def addValueType(self):
|
|
165
|
+
name = self.peek()
|
|
166
|
+
record = None
|
|
167
|
+
try:
|
|
168
|
+
record = self.symbols[name]
|
|
169
|
+
except:
|
|
170
|
+
pass
|
|
171
|
+
if record != None:
|
|
172
|
+
raise FatalError(self, f'Duplicate symbol name "{name}"')
|
|
173
|
+
self.valueTypes[name] = True
|
|
174
|
+
|
|
175
|
+
# Test if a given value is in the value types list
|
|
176
|
+
def hasValue(self, type):
|
|
177
|
+
return type in self.valueTypes
|
|
178
|
+
|
|
179
|
+
# Instantiate an object of the given class name
|
|
180
|
+
def instantiate(self, classname):
|
|
181
|
+
# Search through all loaded modules for the class
|
|
182
|
+
items = sys.modules.items()
|
|
183
|
+
for module_name, module in items:
|
|
184
|
+
if module is None:
|
|
185
|
+
continue
|
|
186
|
+
try:
|
|
187
|
+
if hasattr(module, classname):
|
|
188
|
+
cls = getattr(module, classname)
|
|
189
|
+
# Verify it's actually a class
|
|
190
|
+
if isinstance(cls, type):
|
|
191
|
+
# Attempt to instantiate
|
|
192
|
+
try:
|
|
193
|
+
return cls()
|
|
194
|
+
except TypeError as ex:
|
|
195
|
+
raise FatalError(self, f"Object instantiation error: {ex}")
|
|
196
|
+
except Exception:
|
|
197
|
+
continue
|
|
198
|
+
return None
|
|
199
|
+
|
|
200
|
+
# Compile a variable
|
|
201
|
+
def compileVariable(self, command, classname):
|
|
202
|
+
return self.compileSymbol(command, self.nextToken(), classname)
|
|
203
|
+
|
|
204
|
+
# Compile a symbol
|
|
205
|
+
def compileSymbol(self, command, name, classname):
|
|
206
|
+
# try:
|
|
207
|
+
# self.symbols[name]
|
|
208
|
+
# raise FatalError(self, f'Duplicate symbol name "{name}"')
|
|
209
|
+
# except: pass
|
|
210
|
+
command['name'] = name
|
|
211
|
+
command['classname'] = classname
|
|
212
|
+
command['program'] = self.program
|
|
213
|
+
command['used'] = False
|
|
214
|
+
self.symbols[name] = self.getCodeSize()
|
|
215
|
+
if classname != ':':
|
|
216
|
+
object = self.instantiate(classname)
|
|
217
|
+
command['object'] = object
|
|
218
|
+
if object != None:
|
|
219
|
+
command['type'] = 'symbol'
|
|
220
|
+
object.setName(name) # type: ignore
|
|
221
|
+
self.addCommand(command, False)
|
|
222
|
+
return True
|
|
223
|
+
|
|
224
|
+
# Compile a program label (a symbol ending with ':')
|
|
225
|
+
def compileLabel(self, command):
|
|
226
|
+
return self.compileSymbol(command, self.getToken(), ':')
|
|
227
|
+
|
|
228
|
+
# Compile the current token
|
|
229
|
+
def compileToken(self):
|
|
230
|
+
self.warnings = []
|
|
231
|
+
token = self.getToken()
|
|
232
|
+
# print(f'Compile {token}')
|
|
233
|
+
if not token:
|
|
234
|
+
return False
|
|
235
|
+
if len(self.code) == 0:
|
|
236
|
+
if self.program.parent == None and self.program.graphics:
|
|
237
|
+
cmd = {'domain': 'graphics', 'keyword': 'init'}
|
|
238
|
+
self.code.append(cmd)
|
|
239
|
+
mark = self.getIndex()
|
|
240
|
+
for domain in self.program.getDomains():
|
|
241
|
+
handler = domain.keywordHandler(token)
|
|
242
|
+
if handler:
|
|
243
|
+
command = {}
|
|
244
|
+
command['domain'] = domain.getName()
|
|
245
|
+
command['lino'] = self.tokens[self.index].lino
|
|
246
|
+
command['keyword'] = token
|
|
247
|
+
result = handler(command)
|
|
248
|
+
if result:
|
|
249
|
+
return result
|
|
250
|
+
else:
|
|
251
|
+
self.rewindTo(mark)
|
|
252
|
+
else:
|
|
253
|
+
self.rewindTo(mark)
|
|
254
|
+
FatalError(self, f'Unable to compile this "{token}" command')
|
|
255
|
+
|
|
256
|
+
# Compile a single command
|
|
257
|
+
def compileOne(self):
|
|
258
|
+
keyword = self.getToken()
|
|
259
|
+
if not keyword:
|
|
260
|
+
return False
|
|
261
|
+
# print(f'Compile keyword "{keyword}"')
|
|
262
|
+
if keyword.endswith(':'):
|
|
263
|
+
command = {}
|
|
264
|
+
command['domain'] = None
|
|
265
|
+
command['lino'] = self.tokens[self.index].lino
|
|
266
|
+
return self.compileLabel(command)
|
|
267
|
+
else:
|
|
268
|
+
return self.compileToken()
|
|
269
|
+
|
|
270
|
+
# Compile the script
|
|
271
|
+
def compileFrom(self, index, stopOn):
|
|
272
|
+
self.index = index
|
|
273
|
+
while True:
|
|
274
|
+
token = self.tokens[self.index]
|
|
275
|
+
if self.debugCompile: print(f'{token.lino + 1}: {self.script.lines[token.lino]}')
|
|
276
|
+
if self.compileOne() == True:
|
|
277
|
+
if self.index == len(self.tokens) - 1:
|
|
278
|
+
return True
|
|
279
|
+
token = self.nextToken()
|
|
280
|
+
if token in stopOn:
|
|
281
|
+
return True
|
|
282
|
+
else:
|
|
283
|
+
return False
|
|
284
|
+
|
|
285
|
+
# Compile fom the current location, stopping on any of a list of tokens
|
|
286
|
+
def compileFromHere(self, stopOn):
|
|
287
|
+
return self.compileFrom(self.getIndex(), stopOn)
|
|
288
|
+
|
|
289
|
+
# Compile from the start of the script
|
|
290
|
+
def compileFromStart(self):
|
|
291
|
+
return self.compileFrom(0, [])
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
class Condition:
|
|
2
|
+
|
|
3
|
+
def __init__(self, compiler):
|
|
4
|
+
self.compiler = compiler
|
|
5
|
+
self.getToken = compiler.getToken
|
|
6
|
+
self.nextToken = compiler.nextToken
|
|
7
|
+
self.peek = compiler.peek
|
|
8
|
+
self.getIndex = compiler.getIndex
|
|
9
|
+
self.tokenIs = compiler.tokenIs
|
|
10
|
+
self.rewindTo = compiler.rewindTo
|
|
11
|
+
self.program = compiler.program
|
|
12
|
+
self.negate = False
|
|
13
|
+
|
|
14
|
+
def compileCondition(self):
|
|
15
|
+
mark = self.getIndex()
|
|
16
|
+
for domain in self.compiler.program.getDomains():
|
|
17
|
+
condition = domain.compileCondition()
|
|
18
|
+
if condition != None:
|
|
19
|
+
condition.domain = domain.getName()
|
|
20
|
+
return condition
|
|
21
|
+
self.rewindTo(mark)
|
|
22
|
+
return None
|
|
23
|
+
|
|
24
|
+
def testCondition(self, condition):
|
|
25
|
+
handler = self.program.domainIndex[condition.domain]
|
|
26
|
+
handler = handler.conditionHandler(condition.type)
|
|
27
|
+
return handler(condition)
|