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