easycoder 251104.2__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 +493 -11
- easycoder/ec_compiler.py +81 -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 +308 -156
- 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 -496
- 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.2.dist-info → easycoder-260108.1.dist-info}/METADATA +11 -1
- easycoder-260108.1.dist-info/RECORD +59 -0
- easycoder/ec_debug.py +0 -464
- easycoder-251104.2.dist-info/RECORD +0 -20
- /easycoder/{close.png → icons/close.png} +0 -0
- /easycoder/{tick.png → icons/tick.png} +0 -0
- {easycoder-251104.2.dist-info → easycoder-260108.1.dist-info}/WHEEL +0 -0
- {easycoder-251104.2.dist-info → easycoder-260108.1.dist-info}/entry_points.txt +0 -0
- {easycoder-251104.2.dist-info → easycoder-260108.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,557 @@
|
|
|
1
|
+
import time, sys, json
|
|
2
|
+
from copy import deepcopy
|
|
3
|
+
from collections import deque
|
|
4
|
+
from .ec_classes import (
|
|
5
|
+
Script,
|
|
6
|
+
Token,
|
|
7
|
+
FatalError,
|
|
8
|
+
RuntimeError,
|
|
9
|
+
NoValueRuntimeError,
|
|
10
|
+
ECObject,
|
|
11
|
+
ECValue
|
|
12
|
+
)
|
|
13
|
+
from .ec_compiler import Compiler
|
|
14
|
+
from .ec_core import Core
|
|
15
|
+
import importlib
|
|
16
|
+
from importlib.metadata import version
|
|
17
|
+
|
|
18
|
+
# Flush the queue
|
|
19
|
+
def flush():
|
|
20
|
+
global queue
|
|
21
|
+
while len(queue):
|
|
22
|
+
item = queue.popleft()
|
|
23
|
+
item.program.flush(item.pc)
|
|
24
|
+
|
|
25
|
+
class Program:
|
|
26
|
+
|
|
27
|
+
def __init__(self, arg):
|
|
28
|
+
global queue
|
|
29
|
+
print(f'EasyCoder pre-Python 3.10, version {version("easycoder")}')
|
|
30
|
+
if len(arg) == 0:
|
|
31
|
+
print('No script supplied')
|
|
32
|
+
exit()
|
|
33
|
+
if arg in ['-v', '--version']: return
|
|
34
|
+
if arg[0:6] == 'debug ':
|
|
35
|
+
print('Debug mode requested')
|
|
36
|
+
self.scriptName = arg[6:]
|
|
37
|
+
self.debugging = True
|
|
38
|
+
else:
|
|
39
|
+
self.scriptName = arg
|
|
40
|
+
self.debugging = False
|
|
41
|
+
|
|
42
|
+
f = open(self.scriptName, 'r')
|
|
43
|
+
source = f.read()
|
|
44
|
+
f.close()
|
|
45
|
+
queue = deque()
|
|
46
|
+
self.domains = []
|
|
47
|
+
self.domainIndex = {}
|
|
48
|
+
self.name = '<anon>'
|
|
49
|
+
self.code = []
|
|
50
|
+
self.pc = 0
|
|
51
|
+
self.symbols = {}
|
|
52
|
+
self.onError = 0
|
|
53
|
+
self.debugStep = False
|
|
54
|
+
self.debugSkip = False
|
|
55
|
+
self.stack = []
|
|
56
|
+
self.script = Script(source)
|
|
57
|
+
self.compiler = Compiler(self)
|
|
58
|
+
self.object = ECObject()
|
|
59
|
+
self.value = self.compiler.value
|
|
60
|
+
self.condition = self.compiler.condition
|
|
61
|
+
self.graphics = None
|
|
62
|
+
self.psutil = None
|
|
63
|
+
self.useClass(Core)
|
|
64
|
+
self.ticker = 0
|
|
65
|
+
self.graphicsRunning = False
|
|
66
|
+
self.debugger = None
|
|
67
|
+
self.running = False
|
|
68
|
+
self.parent = None
|
|
69
|
+
self.message = None
|
|
70
|
+
self.onMessagePC = 0
|
|
71
|
+
self.breakpoint = False
|
|
72
|
+
|
|
73
|
+
# This is called at 10msec intervals by the GUI code
|
|
74
|
+
def flushCB(self):
|
|
75
|
+
self.ticker += 1
|
|
76
|
+
# if self.ticker % 1000 == 0: print(f'GUI Tick {self.ticker}')
|
|
77
|
+
flush()
|
|
78
|
+
|
|
79
|
+
def start(self, parent=None, module = None, exports=[]):
|
|
80
|
+
self.parent = parent
|
|
81
|
+
self.exports = exports
|
|
82
|
+
if self.debugging: self.useGraphics()
|
|
83
|
+
if module != None:
|
|
84
|
+
module['child'] = self
|
|
85
|
+
startCompile = time.time()
|
|
86
|
+
self.tokenise(self.script)
|
|
87
|
+
if self.compiler.compileFromStart():
|
|
88
|
+
finishCompile = time.time()
|
|
89
|
+
s = len(self.script.lines)
|
|
90
|
+
t = len(self.script.tokens)
|
|
91
|
+
print(f'Compiled {self.name}: {s} lines ({t} tokens) in ' +
|
|
92
|
+
f'{round((finishCompile - startCompile) * 1000)} ms')
|
|
93
|
+
for name in self.symbols.keys():
|
|
94
|
+
record = self.code[self.symbols[name]]
|
|
95
|
+
if name[-1] != ':' and not 'used' in record:
|
|
96
|
+
print(f'Variable "{name}" not used')
|
|
97
|
+
else:
|
|
98
|
+
print(f'Run {self.name}')
|
|
99
|
+
self.run(0)
|
|
100
|
+
else:
|
|
101
|
+
self.compiler.showWarnings()
|
|
102
|
+
|
|
103
|
+
# If this is the main script and there's no graphics, run a main loop
|
|
104
|
+
if parent == None:
|
|
105
|
+
while not self.graphicsRunning:
|
|
106
|
+
if self.running == True:
|
|
107
|
+
flush()
|
|
108
|
+
time.sleep(0.01)
|
|
109
|
+
else:
|
|
110
|
+
break
|
|
111
|
+
|
|
112
|
+
# Use the graphics module
|
|
113
|
+
def useGraphics(self):
|
|
114
|
+
if self.graphics == None:
|
|
115
|
+
print('Loading graphics module')
|
|
116
|
+
from .ec_graphics import Graphics
|
|
117
|
+
self.graphics = Graphics
|
|
118
|
+
self.useClass(Graphics)
|
|
119
|
+
return True
|
|
120
|
+
|
|
121
|
+
# Use the psutil module
|
|
122
|
+
def usePSUtil(self):
|
|
123
|
+
if self.psutil == None:
|
|
124
|
+
print('Loading psutil module')
|
|
125
|
+
from .ec_psutil import PSUtil
|
|
126
|
+
self.psutil = PSUtil
|
|
127
|
+
self.useClass(PSUtil)
|
|
128
|
+
return True
|
|
129
|
+
|
|
130
|
+
# Indicate that graphics are running
|
|
131
|
+
def startGraphics(self):
|
|
132
|
+
self.graphicsRunning = True
|
|
133
|
+
|
|
134
|
+
# Import a plugin
|
|
135
|
+
def importPlugin(self, source):
|
|
136
|
+
args=source.split(':')
|
|
137
|
+
if len(args)<2:
|
|
138
|
+
RuntimeError(None, f'Invalid plugin spec "{source}"')
|
|
139
|
+
idx=args[0].rfind('/')
|
|
140
|
+
if idx<0:
|
|
141
|
+
sys.path.append('.')
|
|
142
|
+
module=args[0]
|
|
143
|
+
else:
|
|
144
|
+
sys.path.append(args[0][0:idx])
|
|
145
|
+
module=args[0][idx+1:len(args[0])]
|
|
146
|
+
module = module.replace('/','.').replace('.py','')
|
|
147
|
+
module = importlib.import_module(module)
|
|
148
|
+
plugin = getattr(module, args[1])
|
|
149
|
+
self.useClass(plugin)
|
|
150
|
+
|
|
151
|
+
# Use a specified class
|
|
152
|
+
def useClass(self, clazz):
|
|
153
|
+
handler = clazz(self.compiler)
|
|
154
|
+
self.domains.append(handler)
|
|
155
|
+
self.domainIndex[handler.getName()] = handler
|
|
156
|
+
|
|
157
|
+
# This is the runtime callback for event handlers
|
|
158
|
+
def callback(self, item, record, goto):
|
|
159
|
+
object = self.getObject(record)
|
|
160
|
+
values = object.getValues() # type: ignore
|
|
161
|
+
for i, v in enumerate(values):
|
|
162
|
+
if isinstance(v, ECValue): v = v.getContent()
|
|
163
|
+
if v == item:
|
|
164
|
+
object.setIndex(i) # type: ignore
|
|
165
|
+
self.run(goto)
|
|
166
|
+
return
|
|
167
|
+
|
|
168
|
+
# Ensure the program is running
|
|
169
|
+
def ensureRunning(self):
|
|
170
|
+
if not self.running:
|
|
171
|
+
raise RuntimeError(self, 'Improper use of runtime function')
|
|
172
|
+
|
|
173
|
+
# Ensure the program is not running
|
|
174
|
+
def ensureNotRunning(self):
|
|
175
|
+
if self.running:
|
|
176
|
+
raise RuntimeError(self, 'Improper use of non-runtime function')
|
|
177
|
+
|
|
178
|
+
# Get the domain list
|
|
179
|
+
def getDomains(self):
|
|
180
|
+
return self.domains
|
|
181
|
+
|
|
182
|
+
def isSymbol(self, name):
|
|
183
|
+
return name in self.symbols
|
|
184
|
+
|
|
185
|
+
# Get the symbol record for a given name
|
|
186
|
+
def getVariable(self, name):
|
|
187
|
+
self.ensureRunning()
|
|
188
|
+
if isinstance(name, dict): name = name['name']
|
|
189
|
+
try:
|
|
190
|
+
target = self.code[self.symbols[name]]
|
|
191
|
+
if 'import' in target:
|
|
192
|
+
target = target['import']
|
|
193
|
+
return target
|
|
194
|
+
except:
|
|
195
|
+
RuntimeError(self, f'Unknown symbol \'{name}\'')
|
|
196
|
+
|
|
197
|
+
# Get the object represented by a symbol record
|
|
198
|
+
def getObject(self, record):
|
|
199
|
+
if isinstance(record, dict) and 'object' in record:
|
|
200
|
+
return record['object']
|
|
201
|
+
return record
|
|
202
|
+
|
|
203
|
+
# Check if an object is an instance of a given class
|
|
204
|
+
# This can either be variable record (a dict) or an instance of ECObject
|
|
205
|
+
def isObjectType(self, object, classes):
|
|
206
|
+
if isinstance(object, dict) and 'object' in object and isinstance(object['object'], ECObject):
|
|
207
|
+
object = object['object']
|
|
208
|
+
return isinstance(object, classes)
|
|
209
|
+
|
|
210
|
+
# Check if the object is an instance of one of a set of classes. Compile and runtime
|
|
211
|
+
def checkObjectType(self, object, classes):
|
|
212
|
+
if isinstance(object, dict): return
|
|
213
|
+
if not isinstance(object, classes):
|
|
214
|
+
if isinstance(classes, tuple):
|
|
215
|
+
class_names = ", ".join([c.__name__ for c in classes])
|
|
216
|
+
message = f"Variable {object.name} should be one of {class_names}"
|
|
217
|
+
else:
|
|
218
|
+
class_names = classes.__name__
|
|
219
|
+
message = f"Variable {object.name} should be {class_names}"
|
|
220
|
+
if self.running:
|
|
221
|
+
raise RuntimeError(self, message)
|
|
222
|
+
else:
|
|
223
|
+
raise FatalError(self.compiler, message)
|
|
224
|
+
|
|
225
|
+
# Get the inner (non-EC) object from a name, record or object
|
|
226
|
+
def getInnerObject(self, object):
|
|
227
|
+
if isinstance(object, dict): object = object['object']
|
|
228
|
+
elif isinstance(object, str):
|
|
229
|
+
record = self.getVariable(object) # type: ignore
|
|
230
|
+
object = self.getObject(record) # type: ignore
|
|
231
|
+
value = object.getValue() # type: ignore
|
|
232
|
+
if isinstance(value, ECValue) and value.getType() == 'object':
|
|
233
|
+
return value.getContent()
|
|
234
|
+
else: return value
|
|
235
|
+
|
|
236
|
+
def constant(self, content, numeric):
|
|
237
|
+
result = {}
|
|
238
|
+
result['type'] = int if numeric else str
|
|
239
|
+
result['content'] = content
|
|
240
|
+
return result
|
|
241
|
+
|
|
242
|
+
# Test if an item is a string or a number
|
|
243
|
+
def getItemType(self, value):
|
|
244
|
+
return int if isinstance(value, int) else str
|
|
245
|
+
|
|
246
|
+
# Get the value of an item that may be an ECValue or a raw value. Return as an ECValue
|
|
247
|
+
def getValueOf(self, item):
|
|
248
|
+
value = ECValue()
|
|
249
|
+
if isinstance(item, ECValue):
|
|
250
|
+
if item.getType() == 'object':
|
|
251
|
+
return item.getContent()
|
|
252
|
+
else: value = item
|
|
253
|
+
else:
|
|
254
|
+
varType = type(item).__name__
|
|
255
|
+
if varType in [int, str, 'bool', float, 'list', 'dict']:
|
|
256
|
+
if varType == int: value.setValue(type=int, content=item)
|
|
257
|
+
elif varType == str: value.setValue(type=str, content=item)
|
|
258
|
+
elif varType == 'bool': value.setValue(type=bool, content=item)
|
|
259
|
+
elif varType == float: value.setValue(type=str, content=str(item))
|
|
260
|
+
elif varType == 'list': value.setValue(type='list', content=item)
|
|
261
|
+
elif varType == 'dict': value.setValue(type='dict', content=item)
|
|
262
|
+
else: value.setValue(None)
|
|
263
|
+
return value
|
|
264
|
+
|
|
265
|
+
# Runtime function to evaluate an ECObject or ECValue. Returns another ECValue
|
|
266
|
+
# This function may be called recursively by value handlers.
|
|
267
|
+
def evaluate(self, item):
|
|
268
|
+
self.ensureRunning()
|
|
269
|
+
if isinstance(item, ECObject):
|
|
270
|
+
value = item.getValue()
|
|
271
|
+
if value == None:
|
|
272
|
+
raise RuntimeError(self, f'Symbol {item.getName()} not initialized')
|
|
273
|
+
else: value = item
|
|
274
|
+
try:
|
|
275
|
+
valType = value.getType() # type: ignore
|
|
276
|
+
except:
|
|
277
|
+
RuntimeError(self, 'Value does not hold a valid ECValue')
|
|
278
|
+
result = ECValue(type=valType)
|
|
279
|
+
|
|
280
|
+
if valType in (str, int, bool, 'list', 'dict', None):
|
|
281
|
+
# Simple value - just return the content
|
|
282
|
+
result.setContent(value.getContent()) # type: ignore
|
|
283
|
+
|
|
284
|
+
elif valType == 'object':
|
|
285
|
+
# Object other than ECVariable
|
|
286
|
+
record = self.getVariable(value.getName())
|
|
287
|
+
object = self.getObject(record) # type: ignore
|
|
288
|
+
result = object.getContent() # type: ignore
|
|
289
|
+
|
|
290
|
+
elif valType == 'symbol': # type: ignore
|
|
291
|
+
# If it's a symbol, get its value
|
|
292
|
+
record = self.getVariable(value.getContent()) # type: ignore
|
|
293
|
+
if not 'object' in record: return None # type: ignore
|
|
294
|
+
variable = self.getObject(record) # type: ignore
|
|
295
|
+
result = variable.getValue() # type: ignore
|
|
296
|
+
if isinstance(result, ECValue): return self.evaluate(result)
|
|
297
|
+
if isinstance(result, ECObject): return result.getValue()
|
|
298
|
+
if isinstance(result, dict) or isinstance(result, list):
|
|
299
|
+
return result
|
|
300
|
+
# See if one of the domains can handle this value
|
|
301
|
+
value = result
|
|
302
|
+
result = None
|
|
303
|
+
for domain in self.domains:
|
|
304
|
+
result = domain.getUnknownValue(value)
|
|
305
|
+
if result != None: break
|
|
306
|
+
|
|
307
|
+
elif valType == 'cat':
|
|
308
|
+
# Handle concatenation
|
|
309
|
+
content = ''
|
|
310
|
+
for part in value.getContent(): # pyright: ignore[reportOptionalMemberAccess]
|
|
311
|
+
val = self.evaluate(part) # pyright: ignore[reportAttributeAccessIssue]
|
|
312
|
+
if val != None:
|
|
313
|
+
if isinstance(val, ECValue): val = str(val.getContent())
|
|
314
|
+
if val == None: val = ''
|
|
315
|
+
else: content += str(val)
|
|
316
|
+
result.setValue(type=str, content=content)
|
|
317
|
+
|
|
318
|
+
else:
|
|
319
|
+
# Call the given domain to handle a value
|
|
320
|
+
domainName = value.getDomain() # type: ignore
|
|
321
|
+
if domainName == None: domainName = 'core'
|
|
322
|
+
domain = self.domainIndex[domainName]
|
|
323
|
+
handler = domain.valueHandler(value.getType()) # type: ignore
|
|
324
|
+
if handler: result = handler(value)
|
|
325
|
+
|
|
326
|
+
return result
|
|
327
|
+
|
|
328
|
+
# Get the runtime value of a value object (as a string or integer)
|
|
329
|
+
def textify(self, value):
|
|
330
|
+
self.ensureRunning()
|
|
331
|
+
if value is None:
|
|
332
|
+
return None
|
|
333
|
+
|
|
334
|
+
if isinstance(value, dict):
|
|
335
|
+
value = value['object']
|
|
336
|
+
if isinstance(value, ECObject):
|
|
337
|
+
value = value.getValue()
|
|
338
|
+
if isinstance(value, ECValue): # type: ignore
|
|
339
|
+
v = self.evaluate(value) # type: ignore
|
|
340
|
+
else:
|
|
341
|
+
v = value
|
|
342
|
+
if v is None: return None
|
|
343
|
+
if isinstance(v, ECValue):
|
|
344
|
+
if v.getType() == 'object':
|
|
345
|
+
return value.getContent() # type: ignore
|
|
346
|
+
return v.getContent()
|
|
347
|
+
if isinstance(v, (dict, list)):
|
|
348
|
+
return json.dumps(v)
|
|
349
|
+
return v
|
|
350
|
+
|
|
351
|
+
# Get the content of a symbol
|
|
352
|
+
def getSymbolContent(self, record):
|
|
353
|
+
if len(record['value']) == 0:
|
|
354
|
+
return None
|
|
355
|
+
try: return record['value'][record['index']]
|
|
356
|
+
except: raise RuntimeError(self, f'Cannot get content of symbol "{record["name"]}"')
|
|
357
|
+
|
|
358
|
+
# Get the value of a symbol as an ECValue
|
|
359
|
+
def getSymbolValue(self, record):
|
|
360
|
+
self.ensureRunning()
|
|
361
|
+
object = self.getObject(record)
|
|
362
|
+
self.checkObjectType(object, ECObject)
|
|
363
|
+
value = object.getValue() # type: ignore
|
|
364
|
+
if value is None:
|
|
365
|
+
raise NoValueRuntimeError(self, f'Symbol "{record["name"]}" has no value')
|
|
366
|
+
# copy = deepcopy(value)
|
|
367
|
+
copy = ECValue(domain=value.getDomain(),type=value.getType(),content=deepcopy(value.getContent()))
|
|
368
|
+
return copy
|
|
369
|
+
|
|
370
|
+
# Set the value of a symbol to either an ECValue or a raw value
|
|
371
|
+
def putSymbolValue(self, record, value):
|
|
372
|
+
variable = self.getObject(record)
|
|
373
|
+
if variable.isLocked(): # type: ignore
|
|
374
|
+
name = record['name']
|
|
375
|
+
raise RuntimeError(self, f'Symbol "{name}" is locked')
|
|
376
|
+
variable.setValue(self.getValueOf(value)) # type: ignore
|
|
377
|
+
|
|
378
|
+
def encode(self, value):
|
|
379
|
+
return value
|
|
380
|
+
|
|
381
|
+
def decode(self, value):
|
|
382
|
+
return value
|
|
383
|
+
|
|
384
|
+
# Tokenise the script
|
|
385
|
+
def tokenise(self, script):
|
|
386
|
+
token = ''
|
|
387
|
+
literal = False
|
|
388
|
+
for lino in range(0, len(script.lines)):
|
|
389
|
+
line = script.lines[lino]
|
|
390
|
+
length = len(line)
|
|
391
|
+
if length == 0:
|
|
392
|
+
continue
|
|
393
|
+
# Look for the first non-space
|
|
394
|
+
n = 0
|
|
395
|
+
while n < length and line[n].isspace():
|
|
396
|
+
n += 1
|
|
397
|
+
# The whole line may be empty
|
|
398
|
+
if n == length:
|
|
399
|
+
if literal:
|
|
400
|
+
token += '\n'
|
|
401
|
+
continue
|
|
402
|
+
# If in an unfinished literal, the first char must be a backtick to continue adding to it
|
|
403
|
+
if literal:
|
|
404
|
+
if line[n] != '`':
|
|
405
|
+
# Close the current token
|
|
406
|
+
if len(token) > 0:
|
|
407
|
+
script.tokens.append(Token(lino, token))
|
|
408
|
+
token = ''
|
|
409
|
+
literal = False
|
|
410
|
+
n += 1
|
|
411
|
+
for n in range(n, length):
|
|
412
|
+
c = line[n]
|
|
413
|
+
# Test if we are in a literal
|
|
414
|
+
if not literal:
|
|
415
|
+
if c.isspace():
|
|
416
|
+
if len(token) > 0:
|
|
417
|
+
script.tokens.append(Token(lino, token))
|
|
418
|
+
token = ''
|
|
419
|
+
continue
|
|
420
|
+
elif c == '!':
|
|
421
|
+
break
|
|
422
|
+
# Test for the start or end of a literal
|
|
423
|
+
if c == '`':
|
|
424
|
+
if literal:
|
|
425
|
+
token += c
|
|
426
|
+
literal = False
|
|
427
|
+
else:
|
|
428
|
+
token += c
|
|
429
|
+
literal = True
|
|
430
|
+
m = n
|
|
431
|
+
continue
|
|
432
|
+
else:
|
|
433
|
+
token += c
|
|
434
|
+
if len(token) > 0:
|
|
435
|
+
if literal:
|
|
436
|
+
token += '\n'
|
|
437
|
+
else:
|
|
438
|
+
script.tokens.append(Token(lino, token))
|
|
439
|
+
token = ''
|
|
440
|
+
return
|
|
441
|
+
|
|
442
|
+
def releaseParent(self):
|
|
443
|
+
if self.parent and self.parent.waiting and self.parent.program.running: # type: ignore[union-attr]
|
|
444
|
+
self.parent.waiting = False # type: ignore[union-attr]
|
|
445
|
+
self.parent.program.run(self.parent.pc) # type: ignore[union-attr]
|
|
446
|
+
|
|
447
|
+
# Flush the queue
|
|
448
|
+
def flush(self, pc):
|
|
449
|
+
global queue
|
|
450
|
+
self.pc = pc
|
|
451
|
+
while self.running:
|
|
452
|
+
command = self.code[self.pc]
|
|
453
|
+
|
|
454
|
+
# Check if debugger wants to halt before executing this command
|
|
455
|
+
if self.debugger != None:
|
|
456
|
+
# pc==1 is the first real command (pc==0 is the debug loader)
|
|
457
|
+
is_first = (self.pc == 1)
|
|
458
|
+
if self.debugger.checkIfHalt(is_first):
|
|
459
|
+
# Debugger says halt - break out and wait for user
|
|
460
|
+
break
|
|
461
|
+
|
|
462
|
+
domainName = command['domain']
|
|
463
|
+
if domainName == None:
|
|
464
|
+
self.pc += 1
|
|
465
|
+
else:
|
|
466
|
+
keyword = command['keyword']
|
|
467
|
+
if self.debugStep and not self.debugSkip and 'debug' in command:
|
|
468
|
+
lino = command['lino'] + 1
|
|
469
|
+
line = self.script.lines[command['lino']].strip()
|
|
470
|
+
print(f'{self.name}: Line {lino}: {domainName}:{keyword}: {line}')
|
|
471
|
+
domain = self.domainIndex[domainName]
|
|
472
|
+
handler = domain.runHandler(keyword)
|
|
473
|
+
if handler:
|
|
474
|
+
command = self.code[self.pc]
|
|
475
|
+
command['program'] = self
|
|
476
|
+
try:
|
|
477
|
+
if self.breakpoint:
|
|
478
|
+
pass # Place a breakpoint here for a debugger to catch
|
|
479
|
+
self.pc = handler(command)
|
|
480
|
+
except Exception as e:
|
|
481
|
+
raise RuntimeError(self, f'Error during execution of {domainName}:{keyword}: {str(e)}')
|
|
482
|
+
# Deal with 'exit'
|
|
483
|
+
if self.pc == -1:
|
|
484
|
+
queue = deque()
|
|
485
|
+
if self.parent != None:
|
|
486
|
+
self.releaseParent()
|
|
487
|
+
self.running = False
|
|
488
|
+
break
|
|
489
|
+
elif self.pc == None or self.pc == 0 or self.pc >= len(self.code):
|
|
490
|
+
break
|
|
491
|
+
|
|
492
|
+
# Run the script at a given PC value
|
|
493
|
+
def run(self, pc):
|
|
494
|
+
global queue
|
|
495
|
+
item = ECValue()
|
|
496
|
+
item.program = self # type: ignore
|
|
497
|
+
item.pc = pc # type: ignore
|
|
498
|
+
queue.append(item)
|
|
499
|
+
self.running = True
|
|
500
|
+
|
|
501
|
+
def kill(self):
|
|
502
|
+
self.running = False
|
|
503
|
+
if self.parent != None: self.parent.program.kill()
|
|
504
|
+
|
|
505
|
+
def nonNumericValueError(self):
|
|
506
|
+
FatalError(self.compiler, 'Non-numeric value')
|
|
507
|
+
|
|
508
|
+
def compare(self, value1, value2):
|
|
509
|
+
if value1 == None or value2 == None:
|
|
510
|
+
RuntimeError(self, 'Cannot compare a value with None')
|
|
511
|
+
v1 = self.textify(value1)
|
|
512
|
+
v2 = self.textify(value2)
|
|
513
|
+
if v1 == None or v2 == None:
|
|
514
|
+
raise RuntimeError(self, 'Both items must have a value for comparison')
|
|
515
|
+
if type(v1) == str and type(v2) == str:
|
|
516
|
+
# String comparison
|
|
517
|
+
if v1 < v2: return -1
|
|
518
|
+
if v1 > v2: return 1
|
|
519
|
+
return 0
|
|
520
|
+
|
|
521
|
+
if type(v1) is str:
|
|
522
|
+
try:
|
|
523
|
+
v1 = int(v1)
|
|
524
|
+
except:
|
|
525
|
+
print(f'{v1} is not an integer')
|
|
526
|
+
return None
|
|
527
|
+
if type(v2) is str:
|
|
528
|
+
try:
|
|
529
|
+
v2 = int(v2)
|
|
530
|
+
except:
|
|
531
|
+
print(f'{v2} is not an integer')
|
|
532
|
+
return None
|
|
533
|
+
if v1 < v2: # type: ignore[operator]
|
|
534
|
+
return -1
|
|
535
|
+
if v1 > v2: # type: ignore[operator]
|
|
536
|
+
return 1
|
|
537
|
+
return 0
|
|
538
|
+
|
|
539
|
+
# Set up a message handler
|
|
540
|
+
def onMessage(self, pc):
|
|
541
|
+
self.onMessagePC = pc
|
|
542
|
+
|
|
543
|
+
# Handle a message from our parent program
|
|
544
|
+
def handleMessage(self, message):
|
|
545
|
+
self.message = message
|
|
546
|
+
self.run(self.onMessagePC)
|
|
547
|
+
|
|
548
|
+
# This is the program launcher
|
|
549
|
+
def Main():
|
|
550
|
+
if (len(sys.argv) > 1):
|
|
551
|
+
Program(' '.join(sys.argv[1:])).start()
|
|
552
|
+
else:
|
|
553
|
+
Program('-v')
|
|
554
|
+
|
|
555
|
+
if __name__ == '__main__':
|
|
556
|
+
Main()
|
|
557
|
+
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from easycoder import Handler, ECValue
|
|
2
|
+
import os
|
|
3
|
+
from psutil import Process
|
|
4
|
+
|
|
5
|
+
class PSUtil(Handler):
|
|
6
|
+
|
|
7
|
+
def __init__(self, compiler):
|
|
8
|
+
Handler.__init__(self, compiler)
|
|
9
|
+
|
|
10
|
+
def getName(self):
|
|
11
|
+
return 'psutil'
|
|
12
|
+
|
|
13
|
+
#############################################################################
|
|
14
|
+
# Keyword handlers
|
|
15
|
+
|
|
16
|
+
#############################################################################
|
|
17
|
+
# Compile a value in this domain
|
|
18
|
+
def compileValue(self):
|
|
19
|
+
value = ECValue(domain=self.getName())
|
|
20
|
+
if self.tokenIs('the'):
|
|
21
|
+
self.nextToken()
|
|
22
|
+
token = self.getToken()
|
|
23
|
+
if token in ['mem', 'memory']:
|
|
24
|
+
value.setType('memory')
|
|
25
|
+
return value
|
|
26
|
+
return None
|
|
27
|
+
|
|
28
|
+
#############################################################################
|
|
29
|
+
# Modify a value or leave it unchanged.
|
|
30
|
+
def modifyValue(self, value):
|
|
31
|
+
return value
|
|
32
|
+
|
|
33
|
+
#############################################################################
|
|
34
|
+
# Value handlers
|
|
35
|
+
|
|
36
|
+
def v_memory(self, v):
|
|
37
|
+
process: Process = Process(os.getpid())
|
|
38
|
+
megabytes: float = process.memory_info().rss / (1024 * 1024)
|
|
39
|
+
return ECValue(domain=self.getName(), type=float, content=megabytes)
|
|
40
|
+
|
|
41
|
+
#############################################################################
|
|
42
|
+
# Compile a condition
|
|
43
|
+
def compileCondition(self):
|
|
44
|
+
condition = {}
|
|
45
|
+
return condition
|
|
46
|
+
|
|
47
|
+
#############################################################################
|
|
48
|
+
# Condition handlers
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import pytz, time
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
|
|
4
|
+
def getTimestamp(t):
|
|
5
|
+
tz = pytz.timezone('GB') # Localize this!
|
|
6
|
+
dt = datetime.fromtimestamp(t)
|
|
7
|
+
# print(f'{dt} + {tz.dst(dt).seconds}')
|
|
8
|
+
dst = tz.dst(dt)
|
|
9
|
+
return int(t) + (dst.seconds if dst else 0)
|
|
10
|
+
|
|
11
|
+
# Usage: print(getTimestamp(time.time()))
|