easycoder 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 +12 -0
- easycoder/ec_classes.py +51 -0
- easycoder/ec_compiler.py +201 -0
- easycoder/ec_condition.py +26 -0
- easycoder/ec_core.py +2181 -0
- easycoder/ec_handler.py +71 -0
- easycoder/ec_program.py +302 -0
- easycoder/ec_timestamp.py +10 -0
- easycoder/ec_value.py +99 -0
- easycoder-1.dist-info/LICENSE +201 -0
- easycoder-1.dist-info/METADATA +78 -0
- easycoder-1.dist-info/RECORD +13 -0
- easycoder-1.dist-info/WHEEL +5 -0
easycoder/ec_core.py
ADDED
|
@@ -0,0 +1,2181 @@
|
|
|
1
|
+
import json, math, hashlib, threading, os, subprocess, sys, requests, time, numbers
|
|
2
|
+
from psutil import Process
|
|
3
|
+
from datetime import datetime, timezone
|
|
4
|
+
from random import randrange
|
|
5
|
+
from .ec_classes import FatalError, RuntimeWarning, RuntimeError, AssertionError, Condition
|
|
6
|
+
from .ec_handler import Handler
|
|
7
|
+
from .ec_timestamp import getTimestamp
|
|
8
|
+
|
|
9
|
+
class Core(Handler):
|
|
10
|
+
|
|
11
|
+
def __init__(self, compiler):
|
|
12
|
+
Handler.__init__(self, compiler)
|
|
13
|
+
|
|
14
|
+
def getName(self):
|
|
15
|
+
return 'core'
|
|
16
|
+
|
|
17
|
+
#############################################################################
|
|
18
|
+
# Keyword handlers
|
|
19
|
+
|
|
20
|
+
# Arithmetic add
|
|
21
|
+
def k_add(self, command):
|
|
22
|
+
# Get the (first) value
|
|
23
|
+
command['value1'] = self.nextValue()
|
|
24
|
+
if self.nextToken() == 'to':
|
|
25
|
+
if self.nextIsSymbol():
|
|
26
|
+
symbolRecord = self.getSymbolRecord()
|
|
27
|
+
if symbolRecord['valueHolder']:
|
|
28
|
+
if self.peek() == 'giving':
|
|
29
|
+
# This variable must be treated as a second value
|
|
30
|
+
command['value2'] = self.getValue()
|
|
31
|
+
self.nextToken()
|
|
32
|
+
command['target'] = self.nextToken()
|
|
33
|
+
self.add(command)
|
|
34
|
+
return True
|
|
35
|
+
else:
|
|
36
|
+
# Here the variable is the target
|
|
37
|
+
command['target'] = self.getToken()
|
|
38
|
+
self.add(command)
|
|
39
|
+
return True
|
|
40
|
+
self.warning(f'core.add: Expected value holder')
|
|
41
|
+
else:
|
|
42
|
+
# Here we have 2 values so 'giving' must come next
|
|
43
|
+
command['value2'] = self.getValue()
|
|
44
|
+
if self.nextToken() == 'giving':
|
|
45
|
+
command['target'] = self.nextToken()
|
|
46
|
+
self.add(command)
|
|
47
|
+
return True
|
|
48
|
+
self.warning(f'core.add: Expected "giving"')
|
|
49
|
+
return False
|
|
50
|
+
|
|
51
|
+
def r_add(self, command):
|
|
52
|
+
value1 = command['value1']
|
|
53
|
+
try:
|
|
54
|
+
value2 = command['value2']
|
|
55
|
+
except:
|
|
56
|
+
value2 = None
|
|
57
|
+
target = self.getVariable(command['target'])
|
|
58
|
+
if not target['valueHolder']:
|
|
59
|
+
self.variableDoesNotHoldAValueError(target['name'])
|
|
60
|
+
targetValue = self.getSymbolValue(target)
|
|
61
|
+
if targetValue == None:
|
|
62
|
+
targetValue = {}
|
|
63
|
+
targetValue['content'] = 0
|
|
64
|
+
targetValue['type'] = 'int'
|
|
65
|
+
if value2:
|
|
66
|
+
v1 = int(self.getRuntimeValue(value1))
|
|
67
|
+
v2 = int(self.getRuntimeValue(value2))
|
|
68
|
+
targetValue['content'] = v1 + v2
|
|
69
|
+
else:
|
|
70
|
+
# if targetValue['type'] != 'int' and targetValue['content'] != None:
|
|
71
|
+
# self.nonNumericValueError()
|
|
72
|
+
v = self.getRuntimeValue(targetValue)
|
|
73
|
+
v = int(v)
|
|
74
|
+
v1 = int(self.getRuntimeValue(value1))
|
|
75
|
+
if v1 == None:
|
|
76
|
+
v1 = 0
|
|
77
|
+
targetValue['content'] = v + v1
|
|
78
|
+
self.putSymbolValue(target, targetValue)
|
|
79
|
+
return self.nextPC()
|
|
80
|
+
|
|
81
|
+
# Append a value to an array
|
|
82
|
+
def k_append(self, command):
|
|
83
|
+
command['value'] = self.nextValue()
|
|
84
|
+
if self.nextIs('to'):
|
|
85
|
+
if self.nextIsSymbol():
|
|
86
|
+
symbolRecord = self.getSymbolRecord()
|
|
87
|
+
if symbolRecord['valueHolder']:
|
|
88
|
+
command['target'] = symbolRecord['name']
|
|
89
|
+
self.add(command)
|
|
90
|
+
return True
|
|
91
|
+
self.warning(f'Variable "{symbolRecord["name"]}" does not hold a value')
|
|
92
|
+
return False
|
|
93
|
+
|
|
94
|
+
def r_append(self, command):
|
|
95
|
+
value = self.getRuntimeValue(command['value'])
|
|
96
|
+
target = self.getVariable(command['target'])
|
|
97
|
+
val = self.getSymbolValue(target)
|
|
98
|
+
content = val['content']
|
|
99
|
+
if content == '':
|
|
100
|
+
content = []
|
|
101
|
+
content.append(value)
|
|
102
|
+
val['content'] = content
|
|
103
|
+
self.putSymbolValue(target, val)
|
|
104
|
+
return self.nextPC()
|
|
105
|
+
|
|
106
|
+
# Define an array
|
|
107
|
+
def k_array(self, command):
|
|
108
|
+
return self.compileVariable(command)
|
|
109
|
+
|
|
110
|
+
def r_array(self, command):
|
|
111
|
+
return self.nextPC()
|
|
112
|
+
|
|
113
|
+
# Assertion
|
|
114
|
+
def k_assert(self, command):
|
|
115
|
+
command['test'] = self.nextCondition()
|
|
116
|
+
self.addCommand(command)
|
|
117
|
+
return True
|
|
118
|
+
|
|
119
|
+
def r_assert(self, command):
|
|
120
|
+
test = self.program.condition.testCondition(command['test'])
|
|
121
|
+
if test:
|
|
122
|
+
return self.nextPC()
|
|
123
|
+
AssertionError(self.program)
|
|
124
|
+
|
|
125
|
+
# Begin a block
|
|
126
|
+
def k_begin(self, command):
|
|
127
|
+
if self.nextToken() == 'end':
|
|
128
|
+
cmd = {}
|
|
129
|
+
cmd['domain'] = 'core'
|
|
130
|
+
cmd['keyword'] = 'end'
|
|
131
|
+
cmd['debug'] = True
|
|
132
|
+
cmd['lino'] = command['lino']
|
|
133
|
+
self.addCommand(cmd)
|
|
134
|
+
return self.nextPC()
|
|
135
|
+
else:
|
|
136
|
+
return self.compileFromHere(['end'])
|
|
137
|
+
|
|
138
|
+
# Clear (set False)
|
|
139
|
+
def k_clear(self, command):
|
|
140
|
+
if self.nextIsSymbol():
|
|
141
|
+
target = self.getSymbolRecord()
|
|
142
|
+
if target['valueHolder']:
|
|
143
|
+
command['target'] = target['name']
|
|
144
|
+
self.add(command)
|
|
145
|
+
return True
|
|
146
|
+
return False
|
|
147
|
+
|
|
148
|
+
def r_clear(self, command):
|
|
149
|
+
target = self.getVariable(command['target'])
|
|
150
|
+
val = {}
|
|
151
|
+
val['type'] = 'boolean'
|
|
152
|
+
val['content'] = False
|
|
153
|
+
self.putSymbolValue(target, val)
|
|
154
|
+
# self.add(command)
|
|
155
|
+
return self.nextPC()
|
|
156
|
+
|
|
157
|
+
# Close a file
|
|
158
|
+
def k_close(self, command):
|
|
159
|
+
if self.nextIsSymbol():
|
|
160
|
+
fileRecord = self.getSymbolRecord()
|
|
161
|
+
if fileRecord['keyword'] == 'file':
|
|
162
|
+
command['file'] = fileRecord['name']
|
|
163
|
+
self.add(command)
|
|
164
|
+
return True
|
|
165
|
+
return False
|
|
166
|
+
|
|
167
|
+
def r_close(self, command):
|
|
168
|
+
fileRecord = self.getVariable(command['file'])
|
|
169
|
+
fileRecord['file'].close()
|
|
170
|
+
return self.nextPC()
|
|
171
|
+
|
|
172
|
+
#Create directory
|
|
173
|
+
def k_create(self, command):
|
|
174
|
+
if self.nextIs('directory'):
|
|
175
|
+
command['item'] = 'directory'
|
|
176
|
+
command['path'] = self.nextValue()
|
|
177
|
+
self.add(command)
|
|
178
|
+
return True
|
|
179
|
+
return False
|
|
180
|
+
|
|
181
|
+
def r_create(self, command):
|
|
182
|
+
if command['item'] == 'directory':
|
|
183
|
+
path = self.getRuntimeValue(command['path'])
|
|
184
|
+
if not os.path.exists(path):
|
|
185
|
+
os.makedirs(path)
|
|
186
|
+
return self.nextPC()
|
|
187
|
+
|
|
188
|
+
# Debug the script
|
|
189
|
+
def k_debug(self, command):
|
|
190
|
+
token = self.peek()
|
|
191
|
+
if token in ['step', 'stop', 'program', 'custom']:
|
|
192
|
+
command['mode'] = token
|
|
193
|
+
self.nextToken()
|
|
194
|
+
elif token == 'stack':
|
|
195
|
+
command['mode'] = self.nextToken()
|
|
196
|
+
if (self.nextIsSymbol()):
|
|
197
|
+
command['stack'] = self.getToken()
|
|
198
|
+
if self.peek() == 'as':
|
|
199
|
+
self.nextToken()
|
|
200
|
+
command['as'] = self.nextValue()
|
|
201
|
+
else:
|
|
202
|
+
command['as'] = 'Stack'
|
|
203
|
+
else:
|
|
204
|
+
return False
|
|
205
|
+
else:
|
|
206
|
+
command['mode'] = None
|
|
207
|
+
self.add(command)
|
|
208
|
+
return True
|
|
209
|
+
|
|
210
|
+
def r_debug(self, command):
|
|
211
|
+
if command['mode'] == 'step':
|
|
212
|
+
self.program.debugStep = True
|
|
213
|
+
elif command['mode'] == 'stop':
|
|
214
|
+
self.program.debugStep = False
|
|
215
|
+
elif command['mode'] == 'program':
|
|
216
|
+
for item in self.code:
|
|
217
|
+
print(json.dumps(item, indent = 2))
|
|
218
|
+
elif command['mode'] == 'stack':
|
|
219
|
+
stackRecord = self.getVariable(command['stack'])
|
|
220
|
+
value = self.getSymbolValue(stackRecord)
|
|
221
|
+
print(f'{self.getRuntimeValue(command["as"])}:',json.dumps(self.getSymbolValue(stackRecord), indent = 2))
|
|
222
|
+
elif command['mode'] == 'custom':
|
|
223
|
+
# Custom debugging code goes in here
|
|
224
|
+
record = self.getVariable('Script')
|
|
225
|
+
print('(Debug) Script:',record)
|
|
226
|
+
value = self.getRuntimeValue(record)
|
|
227
|
+
print('(Debug) Value:',value)
|
|
228
|
+
pass
|
|
229
|
+
return self.nextPC()
|
|
230
|
+
|
|
231
|
+
# Decrement a variable
|
|
232
|
+
def k_decrement(self, command):
|
|
233
|
+
if self.nextIsSymbol():
|
|
234
|
+
symbolRecord = self.getSymbolRecord()
|
|
235
|
+
if symbolRecord['valueHolder']:
|
|
236
|
+
command['target'] = self.getToken()
|
|
237
|
+
self.add(command)
|
|
238
|
+
return True
|
|
239
|
+
self.warning(f'Variable "{symbolRecord["name"]}" does not hold a value')
|
|
240
|
+
return False
|
|
241
|
+
|
|
242
|
+
def r_decrement(self, command):
|
|
243
|
+
return self.incdec(command, '-')
|
|
244
|
+
|
|
245
|
+
# Delete a file or a property
|
|
246
|
+
def k_delete(self, command):
|
|
247
|
+
token = self.nextToken( )
|
|
248
|
+
if token == 'file':
|
|
249
|
+
command['type'] = 'file'
|
|
250
|
+
command['filename'] = self.nextValue()
|
|
251
|
+
self.add(command)
|
|
252
|
+
return True
|
|
253
|
+
elif token == 'property':
|
|
254
|
+
command['key'] = self.nextValue();
|
|
255
|
+
if self.nextIs('of'):
|
|
256
|
+
command['type'] = 'property'
|
|
257
|
+
command['var'] = self.nextToken()
|
|
258
|
+
self.add(command)
|
|
259
|
+
return True
|
|
260
|
+
else:
|
|
261
|
+
self.warning(f'"of" expected; got {self.getToken()}')
|
|
262
|
+
else:
|
|
263
|
+
self.warning(f'"file" or "property" expected; got {token}')
|
|
264
|
+
return False
|
|
265
|
+
|
|
266
|
+
def r_delete(self, command):
|
|
267
|
+
type = command['type']
|
|
268
|
+
if type == 'file':
|
|
269
|
+
filename = self.getRuntimeValue(command['filename'])
|
|
270
|
+
if os.path.isfile(filename):
|
|
271
|
+
print('Deleting',filename)
|
|
272
|
+
os.remove(filename)
|
|
273
|
+
elif type == 'property':
|
|
274
|
+
key = self.getRuntimeValue(command['key'])
|
|
275
|
+
symbolRecord = self.getVariable(command['var'])
|
|
276
|
+
value = self.getSymbolValue(symbolRecord)
|
|
277
|
+
content = value['content']
|
|
278
|
+
content.pop(key, None)
|
|
279
|
+
value['content'] = content
|
|
280
|
+
self.putSymbolValue(symbolRecord, value)
|
|
281
|
+
return self.nextPC()
|
|
282
|
+
|
|
283
|
+
# Arithmetic division
|
|
284
|
+
def k_divide(self, command):
|
|
285
|
+
# Get the (first) value
|
|
286
|
+
command['value1'] = self.nextValue()
|
|
287
|
+
if self.nextToken() == 'by':
|
|
288
|
+
command['value2'] = self.nextValue()
|
|
289
|
+
if self.peek() == 'giving':
|
|
290
|
+
self.nextToken()
|
|
291
|
+
if (self.nextIsSymbol()):
|
|
292
|
+
command['target'] = self.getToken()
|
|
293
|
+
self.add(command)
|
|
294
|
+
return True
|
|
295
|
+
FatalError(self.program.compiler, 'Symbol expected')
|
|
296
|
+
else:
|
|
297
|
+
# First value must be a variable
|
|
298
|
+
if command['value1']['type'] == 'symbol':
|
|
299
|
+
command['target'] = command['value1']['name']
|
|
300
|
+
self.add(command)
|
|
301
|
+
return True
|
|
302
|
+
FatalError(self.compiler, 'First value must be a variable')
|
|
303
|
+
return False
|
|
304
|
+
|
|
305
|
+
def r_divide(self, command):
|
|
306
|
+
value1 = command['value1']
|
|
307
|
+
try:
|
|
308
|
+
value2 = command['value2']
|
|
309
|
+
except:
|
|
310
|
+
value2 = None
|
|
311
|
+
target = self.getVariable(command['target'])
|
|
312
|
+
if not target['valueHolder']:
|
|
313
|
+
self.variableDoesNotHoldAValueError(target['name'])
|
|
314
|
+
return None
|
|
315
|
+
value = self.getSymbolValue(target)
|
|
316
|
+
if value == None:
|
|
317
|
+
value = {}
|
|
318
|
+
value['type'] = 'int'
|
|
319
|
+
if value2:
|
|
320
|
+
v1 = int(self.getRuntimeValue(value1))
|
|
321
|
+
v2 = int(self.getRuntimeValue(value2))
|
|
322
|
+
value['content'] = int(v1/v2)
|
|
323
|
+
else:
|
|
324
|
+
if value['type'] != 'int' and value['content'] != None:
|
|
325
|
+
self.nonNumericValueError(self.compiler, command['lino'])
|
|
326
|
+
v = int(self.getRuntimeValue(value))
|
|
327
|
+
v1 = int(self.getRuntimeValue(value1))
|
|
328
|
+
value['content'] = int(v/v1)
|
|
329
|
+
self.putSymbolValue(target, value)
|
|
330
|
+
return self.nextPC()
|
|
331
|
+
|
|
332
|
+
# Dummy command for testing
|
|
333
|
+
def k_dummy(self, command):
|
|
334
|
+
self.add(command)
|
|
335
|
+
return True
|
|
336
|
+
|
|
337
|
+
def r_dummy(self, command):
|
|
338
|
+
return self.nextPC()
|
|
339
|
+
|
|
340
|
+
# Match a begin
|
|
341
|
+
def k_end(self, command):
|
|
342
|
+
self.add(command)
|
|
343
|
+
return True
|
|
344
|
+
|
|
345
|
+
def r_end(self, command):
|
|
346
|
+
return self.nextPC()
|
|
347
|
+
|
|
348
|
+
# Exit the script
|
|
349
|
+
def k_exit(self, command):
|
|
350
|
+
self.add(command)
|
|
351
|
+
return True
|
|
352
|
+
|
|
353
|
+
def r_exit(self, command):
|
|
354
|
+
sys.exit()
|
|
355
|
+
return 0
|
|
356
|
+
|
|
357
|
+
# Declare a file variable
|
|
358
|
+
def k_file(self, command):
|
|
359
|
+
return self.compileVariable(command, False)
|
|
360
|
+
|
|
361
|
+
def r_file(self, command):
|
|
362
|
+
return self.nextPC()
|
|
363
|
+
|
|
364
|
+
# Fork to a label
|
|
365
|
+
def k_fork(self, command):
|
|
366
|
+
if self.peek() == 'to':
|
|
367
|
+
self.nextToken()
|
|
368
|
+
command['fork'] = self.nextToken()
|
|
369
|
+
self.add(command)
|
|
370
|
+
return True
|
|
371
|
+
|
|
372
|
+
def r_fork(self, command):
|
|
373
|
+
next = self.nextPC()
|
|
374
|
+
label = command['fork']
|
|
375
|
+
try:
|
|
376
|
+
label = self.symbols[label + ':']
|
|
377
|
+
except:
|
|
378
|
+
RuntimeError(self.program, f'There is no label "{label + ":"}"')
|
|
379
|
+
return None
|
|
380
|
+
self.run(label)
|
|
381
|
+
return next
|
|
382
|
+
|
|
383
|
+
# Issue a REST GET request
|
|
384
|
+
def k_get(self, command):
|
|
385
|
+
if self.nextIsSymbol():
|
|
386
|
+
symbolRecord = self.getSymbolRecord()
|
|
387
|
+
if symbolRecord['valueHolder']:
|
|
388
|
+
command['target'] = self.getToken()
|
|
389
|
+
else:
|
|
390
|
+
FatalError(self.compiler, f'Variable "{symbolRecord["name"]}" does not hold a value')
|
|
391
|
+
if self.nextIs('from'):
|
|
392
|
+
command['url'] = self.nextValue()
|
|
393
|
+
command['or'] = None
|
|
394
|
+
get = self.getPC()
|
|
395
|
+
if self.peek() == 'timeout':
|
|
396
|
+
self.nextToken()
|
|
397
|
+
command['timeout'] = self.nextValue()
|
|
398
|
+
else:
|
|
399
|
+
timeout = {}
|
|
400
|
+
timeout['type'] = 'int'
|
|
401
|
+
timeout['content'] = 5
|
|
402
|
+
command['timeout'] = timeout
|
|
403
|
+
self.addCommand(command)
|
|
404
|
+
if self.peek() == 'or':
|
|
405
|
+
self.nextToken()
|
|
406
|
+
self.nextToken()
|
|
407
|
+
# Add a 'goto' to skip the 'or'
|
|
408
|
+
cmd = {}
|
|
409
|
+
cmd['lino'] = command['lino']
|
|
410
|
+
cmd['domain'] = 'core'
|
|
411
|
+
cmd['keyword'] = 'gotoPC'
|
|
412
|
+
cmd['goto'] = 0
|
|
413
|
+
cmd['debug'] = False
|
|
414
|
+
skip = self.getPC()
|
|
415
|
+
self.addCommand(cmd)
|
|
416
|
+
# Process the 'or'
|
|
417
|
+
self.getCommandAt(get)['or'] = self.getPC()
|
|
418
|
+
self.compileOne()
|
|
419
|
+
# Fixup the skip
|
|
420
|
+
self.getCommandAt(skip)['goto'] = self.getPC()
|
|
421
|
+
return True
|
|
422
|
+
|
|
423
|
+
def r_get(self, command):
|
|
424
|
+
global errorCode, errorReason
|
|
425
|
+
retval = {}
|
|
426
|
+
retval['type'] = 'text'
|
|
427
|
+
retval['numeric'] = False
|
|
428
|
+
url = self.getRuntimeValue(command['url'])
|
|
429
|
+
target = self.getVariable(command['target'])
|
|
430
|
+
response = json.loads('{}')
|
|
431
|
+
try:
|
|
432
|
+
timeout = self.getRuntimeValue(command['timeout'])
|
|
433
|
+
response = requests.get(url, auth = ('user', 'pass'), timeout=timeout)
|
|
434
|
+
if response.status_code >= 400:
|
|
435
|
+
errorCode = response.status_code
|
|
436
|
+
errorReason = response.reason
|
|
437
|
+
if command['or'] != None:
|
|
438
|
+
return command['or']
|
|
439
|
+
else:
|
|
440
|
+
RuntimeError(self.program, f'Error code {errorCode}: {errorReason}')
|
|
441
|
+
except Exception as e:
|
|
442
|
+
errorReason = str(e)
|
|
443
|
+
if command['or'] != None:
|
|
444
|
+
return command['or']
|
|
445
|
+
else:
|
|
446
|
+
RuntimeError(self.program, f'Error: {errorReason}')
|
|
447
|
+
retval['content'] = response.text
|
|
448
|
+
self.program.putSymbolValue(target, retval);
|
|
449
|
+
return self.nextPC()
|
|
450
|
+
|
|
451
|
+
# Call a subroutine
|
|
452
|
+
def k_gosub(self, command):
|
|
453
|
+
if self.peek() == 'to':
|
|
454
|
+
self.nextToken()
|
|
455
|
+
command['gosub'] = self.nextToken()
|
|
456
|
+
self.add(command)
|
|
457
|
+
return True
|
|
458
|
+
|
|
459
|
+
def r_gosub(self, command):
|
|
460
|
+
label = command['gosub'] + ':'
|
|
461
|
+
address = self.symbols[label]
|
|
462
|
+
if address != None:
|
|
463
|
+
self.stack.append(self.nextPC())
|
|
464
|
+
return address
|
|
465
|
+
RuntimeError(self.program, f'There is no label "{label + ":"}"')
|
|
466
|
+
return None
|
|
467
|
+
|
|
468
|
+
# Go to a label
|
|
469
|
+
def k_go(self, command):
|
|
470
|
+
if self.peek() == 'to':
|
|
471
|
+
self.nextToken()
|
|
472
|
+
return self.k_goto(command)
|
|
473
|
+
|
|
474
|
+
def k_goto(self, command):
|
|
475
|
+
command['keyword'] = 'goto'
|
|
476
|
+
command['goto'] = self.nextToken()
|
|
477
|
+
self.add(command)
|
|
478
|
+
return True
|
|
479
|
+
|
|
480
|
+
def r_goto(self, command):
|
|
481
|
+
label = f'{command["goto"]}:'
|
|
482
|
+
try:
|
|
483
|
+
if self.symbols[label]:
|
|
484
|
+
return self.symbols[label]
|
|
485
|
+
except:
|
|
486
|
+
pass
|
|
487
|
+
RuntimeError(self.program, f'There is no label "{label}"')
|
|
488
|
+
return None
|
|
489
|
+
|
|
490
|
+
def r_gotoPC(self, command):
|
|
491
|
+
return command['goto']
|
|
492
|
+
|
|
493
|
+
# If <condition> <action> [else <action>]
|
|
494
|
+
def k_if(self, command):
|
|
495
|
+
command['condition'] = self.nextCondition()
|
|
496
|
+
self.addCommand(command)
|
|
497
|
+
self.nextToken()
|
|
498
|
+
pcElse = self.getPC()
|
|
499
|
+
cmd = {}
|
|
500
|
+
cmd['lino'] = command['lino']
|
|
501
|
+
cmd['domain'] = 'core'
|
|
502
|
+
cmd['keyword'] = 'gotoPC'
|
|
503
|
+
cmd['goto'] = 0
|
|
504
|
+
cmd['debug'] = False
|
|
505
|
+
self.addCommand(cmd)
|
|
506
|
+
# Get the 'then' code
|
|
507
|
+
self.compileOne()
|
|
508
|
+
if self.peek() == 'else':
|
|
509
|
+
self.nextToken()
|
|
510
|
+
# Add a 'goto' to skip the 'else'
|
|
511
|
+
pcNext = self.getPC()
|
|
512
|
+
cmd = {}
|
|
513
|
+
cmd['lino'] = command['lino']
|
|
514
|
+
cmd['domain'] = 'core'
|
|
515
|
+
cmd['keyword'] = 'gotoPC'
|
|
516
|
+
cmd['goto'] = 0
|
|
517
|
+
cmd['debug'] = False
|
|
518
|
+
self.addCommand(cmd)
|
|
519
|
+
# Fixup the link to the 'else' branch
|
|
520
|
+
self.getCommandAt(pcElse)['goto'] = self.getPC()
|
|
521
|
+
# Process the 'else' branch
|
|
522
|
+
self.nextToken()
|
|
523
|
+
self.compileOne()
|
|
524
|
+
# Fixup the pcNext 'goto'
|
|
525
|
+
self.getCommandAt(pcNext)['goto'] = self.getPC()
|
|
526
|
+
else:
|
|
527
|
+
# We're already at the next command
|
|
528
|
+
self.getCommandAt(pcElse)['goto'] = self.getPC()
|
|
529
|
+
return True
|
|
530
|
+
|
|
531
|
+
def r_if(self, command):
|
|
532
|
+
test = self.program.condition.testCondition(command['condition'])
|
|
533
|
+
if test:
|
|
534
|
+
self.program.pc += 2
|
|
535
|
+
else:
|
|
536
|
+
self.program.pc += 1
|
|
537
|
+
return self.program.pc
|
|
538
|
+
|
|
539
|
+
# Increment a variable
|
|
540
|
+
def k_increment(self, command):
|
|
541
|
+
if self.nextIsSymbol():
|
|
542
|
+
symbolRecord = self.getSymbolRecord()
|
|
543
|
+
if symbolRecord['valueHolder']:
|
|
544
|
+
command['target'] = self.getToken()
|
|
545
|
+
self.add(command)
|
|
546
|
+
return True
|
|
547
|
+
self.warning(f'Variable "{symbolRecord["name"]}" does not hold a value')
|
|
548
|
+
return False
|
|
549
|
+
|
|
550
|
+
def r_increment(self, command):
|
|
551
|
+
return self.incdec(command, '+')
|
|
552
|
+
|
|
553
|
+
# Index to a specified element in a variable
|
|
554
|
+
def k_index(self, command):
|
|
555
|
+
# get the variable
|
|
556
|
+
if self.nextIsSymbol():
|
|
557
|
+
command['target'] = self.getToken()
|
|
558
|
+
if self.nextToken() == 'to':
|
|
559
|
+
# get the value
|
|
560
|
+
command['value'] = self.nextValue()
|
|
561
|
+
self.add(command)
|
|
562
|
+
return True
|
|
563
|
+
return False
|
|
564
|
+
|
|
565
|
+
def r_index(self, command):
|
|
566
|
+
symbolRecord = self.getVariable(command['target'])
|
|
567
|
+
symbolRecord['index'] = self.getRuntimeValue(command['value'])
|
|
568
|
+
return self.nextPC()
|
|
569
|
+
|
|
570
|
+
# Inout a value from the terminal
|
|
571
|
+
def k_input(self, command):
|
|
572
|
+
# get the variable
|
|
573
|
+
if self.nextIsSymbol():
|
|
574
|
+
command['target'] = self.getToken()
|
|
575
|
+
value = {}
|
|
576
|
+
value['type'] = 'text'
|
|
577
|
+
value['numeric'] = 'false'
|
|
578
|
+
value['content'] = ': '
|
|
579
|
+
command['prompt'] = value
|
|
580
|
+
if self.peek() == 'with':
|
|
581
|
+
self.nextToken()
|
|
582
|
+
command['prompt'] = self.nextValue()
|
|
583
|
+
self.add(command)
|
|
584
|
+
return True
|
|
585
|
+
return False
|
|
586
|
+
|
|
587
|
+
def r_input(self, command):
|
|
588
|
+
symbolRecord = self.getVariable(command['target'])
|
|
589
|
+
prompt = command['prompt']['content']
|
|
590
|
+
value = {}
|
|
591
|
+
value['type'] = 'text'
|
|
592
|
+
value['numeric'] = False
|
|
593
|
+
value['content'] = prompt+input(prompt)
|
|
594
|
+
self.putSymbolValue(symbolRecord, value)
|
|
595
|
+
return self.nextPC()
|
|
596
|
+
|
|
597
|
+
# Initialise a stack, array or object
|
|
598
|
+
def k_init(self, command):
|
|
599
|
+
# get the variable
|
|
600
|
+
if self.nextIsSymbol():
|
|
601
|
+
symbolRecord = self.getSymbolRecord()
|
|
602
|
+
keyword = symbolRecord['keyword']
|
|
603
|
+
if keyword in ['stack','array', 'object']:
|
|
604
|
+
command['keyword'] = keyword
|
|
605
|
+
command['target'] = symbolRecord['name']
|
|
606
|
+
return True
|
|
607
|
+
return False
|
|
608
|
+
|
|
609
|
+
def r_init(self, command):
|
|
610
|
+
symbolRecord = self.getVariable(command['target'])
|
|
611
|
+
keyword = command['keyword']
|
|
612
|
+
if keyword in ['stack', 'array']:
|
|
613
|
+
self.putSymbolValue(symbolRecord, json.loads('[]'))
|
|
614
|
+
elif keyword == 'object':
|
|
615
|
+
self.putSymbolValue(symbolRecord, json.loads('{}'))
|
|
616
|
+
else:
|
|
617
|
+
RuntimeError(self.program, f"Inappropriate variable type '{keyword}'")
|
|
618
|
+
return self.nextPC()
|
|
619
|
+
|
|
620
|
+
# Arithmetic multiply
|
|
621
|
+
def k_multiply(self, command):
|
|
622
|
+
# Get the (first) value
|
|
623
|
+
command['value1'] = self.nextValue()
|
|
624
|
+
if self.nextToken() == 'by':
|
|
625
|
+
command['value2'] = self.nextValue()
|
|
626
|
+
if self.peek() == 'giving':
|
|
627
|
+
self.nextToken()
|
|
628
|
+
if (self.nextIsSymbol()):
|
|
629
|
+
command['target'] = self.getToken()
|
|
630
|
+
self.add(command)
|
|
631
|
+
return True
|
|
632
|
+
FatalError(self.program.compiler, 'Symbol expected')
|
|
633
|
+
else:
|
|
634
|
+
# First value must be a variable
|
|
635
|
+
if command['value1']['type'] == 'symbol':
|
|
636
|
+
command['target'] = command['value1']['name']
|
|
637
|
+
self.add(command)
|
|
638
|
+
return True
|
|
639
|
+
FatalError(self.program.compiler, 'First value must be a variable')
|
|
640
|
+
return False
|
|
641
|
+
|
|
642
|
+
def r_multiply(self, command):
|
|
643
|
+
value1 = command['value1']
|
|
644
|
+
try:
|
|
645
|
+
value2 = command['value2']
|
|
646
|
+
except:
|
|
647
|
+
value2 = None
|
|
648
|
+
target = self.getVariable(command['target'])
|
|
649
|
+
if not target['valueHolder']:
|
|
650
|
+
self.variableDoesNotHoldAValueError(target['name'])
|
|
651
|
+
return None
|
|
652
|
+
value = self.getSymbolValue(target)
|
|
653
|
+
if value == None:
|
|
654
|
+
value = {}
|
|
655
|
+
value['type'] = 'int'
|
|
656
|
+
if value2:
|
|
657
|
+
v1 = int(self.getRuntimeValue(value1))
|
|
658
|
+
v2 = int(self.getRuntimeValue(value2))
|
|
659
|
+
value['content'] = v1*v2
|
|
660
|
+
else:
|
|
661
|
+
if value['type'] != 'int' and value['content'] != None:
|
|
662
|
+
self.nonNumericValueError()
|
|
663
|
+
return None
|
|
664
|
+
v = int(self.getRuntimeValue(value))
|
|
665
|
+
v1 = int(self.getRuntimeValue(value1))
|
|
666
|
+
value['content'] = v*v1
|
|
667
|
+
self.putSymbolValue(target, value)
|
|
668
|
+
return self.nextPC()
|
|
669
|
+
|
|
670
|
+
# Define an object variable
|
|
671
|
+
def k_object(self, command):
|
|
672
|
+
return self.compileVariable(command)
|
|
673
|
+
|
|
674
|
+
def r_object(self, command):
|
|
675
|
+
return self.nextPC()
|
|
676
|
+
|
|
677
|
+
# Open a file
|
|
678
|
+
def k_open(self, command):
|
|
679
|
+
if self.nextIsSymbol():
|
|
680
|
+
symbolRecord = self.getSymbolRecord()
|
|
681
|
+
command['target'] = symbolRecord['name']
|
|
682
|
+
command['path'] = self.nextValue()
|
|
683
|
+
if symbolRecord['keyword'] == 'file':
|
|
684
|
+
if self.peek() == 'for':
|
|
685
|
+
self.nextToken()
|
|
686
|
+
token = self.nextToken()
|
|
687
|
+
if token == 'appending':
|
|
688
|
+
mode = 'a'
|
|
689
|
+
elif token == 'reading':
|
|
690
|
+
mode = 'r'
|
|
691
|
+
elif token == 'writing':
|
|
692
|
+
mode = 'w'
|
|
693
|
+
else:
|
|
694
|
+
FatalError(self.program.compiler, 'Unknown file open mode {self.getToken()}')
|
|
695
|
+
return False
|
|
696
|
+
command['mode'] = mode
|
|
697
|
+
self.add(command)
|
|
698
|
+
return True
|
|
699
|
+
else:
|
|
700
|
+
FatalError(self.compiler, f'Variable "{self.getToken()}" is not a file')
|
|
701
|
+
else:
|
|
702
|
+
self.warning(f'core.open: Variable "{self.getToken()}" not declared')
|
|
703
|
+
return False
|
|
704
|
+
|
|
705
|
+
def r_open(self, command):
|
|
706
|
+
symbolRecord = self.getVariable(command['target'])
|
|
707
|
+
path = self.getRuntimeValue(command['path'])
|
|
708
|
+
if command['mode'] == 'r' and os.path.exists(path) or command['mode'] != 'r':
|
|
709
|
+
symbolRecord['file'] = open(path, command['mode'])
|
|
710
|
+
return self.nextPC()
|
|
711
|
+
RuntimeError(self.program, f"File {path} does not exist")
|
|
712
|
+
|
|
713
|
+
# Pop a value from a stack
|
|
714
|
+
def k_pop(self, command):
|
|
715
|
+
if (self.nextIsSymbol()):
|
|
716
|
+
symbolRecord = self.getSymbolRecord()
|
|
717
|
+
command['target'] = symbolRecord['name']
|
|
718
|
+
if self.peek() == 'from':
|
|
719
|
+
self.nextToken()
|
|
720
|
+
if self.nextIsSymbol():
|
|
721
|
+
command['from'] = self.getToken()
|
|
722
|
+
self.add(command)
|
|
723
|
+
return True
|
|
724
|
+
return False;
|
|
725
|
+
|
|
726
|
+
def r_pop(self, command):
|
|
727
|
+
symbolRecord = self.getVariable(command['target'])
|
|
728
|
+
if not symbolRecord['valueHolder']:
|
|
729
|
+
RuntimeError(self.program, f'{symbolRecord["name"]} does not hold a value')
|
|
730
|
+
stackRecord = self.getVariable(command['from'])
|
|
731
|
+
stack = self.getSymbolValue(stackRecord)
|
|
732
|
+
v = stack.pop();
|
|
733
|
+
self.putSymbolValue(stackRecord, stack)
|
|
734
|
+
value = {}
|
|
735
|
+
value['type'] = 'int' if type(v) == int else 'text'
|
|
736
|
+
value['content'] = v
|
|
737
|
+
self.putSymbolValue(symbolRecord, value)
|
|
738
|
+
return self.nextPC()
|
|
739
|
+
|
|
740
|
+
# Perform an HTTP POST
|
|
741
|
+
def k_post(self, command):
|
|
742
|
+
if self.nextIs('to'):
|
|
743
|
+
command['value'] = self.getConstant('')
|
|
744
|
+
command['url'] = self.getValue()
|
|
745
|
+
else:
|
|
746
|
+
command['value'] = self.getValue()
|
|
747
|
+
if self.nextIs('to'):
|
|
748
|
+
command['url'] = self.nextValue()
|
|
749
|
+
if self.peek() == 'giving':
|
|
750
|
+
self.nextToken()
|
|
751
|
+
command['result'] = self.nextToken()
|
|
752
|
+
else:
|
|
753
|
+
command['result'] = None
|
|
754
|
+
command['or'] = None
|
|
755
|
+
post = self.getPC()
|
|
756
|
+
self.addCommand(command)
|
|
757
|
+
if self.peek() == 'or':
|
|
758
|
+
self.nextToken()
|
|
759
|
+
self.nextToken()
|
|
760
|
+
# Add a 'goto' to skip the 'or'
|
|
761
|
+
cmd = {}
|
|
762
|
+
cmd['lino'] = command['lino']
|
|
763
|
+
cmd['domain'] = 'core'
|
|
764
|
+
cmd['keyword'] = 'gotoPC'
|
|
765
|
+
cmd['goto'] = 0
|
|
766
|
+
cmd['debug'] = False
|
|
767
|
+
skip = self.getPC()
|
|
768
|
+
self.addCommand(cmd)
|
|
769
|
+
# Process the 'or'
|
|
770
|
+
self.getCommandAt(post)['or'] = self.getPC()
|
|
771
|
+
self.compileOne()
|
|
772
|
+
# Fixup the skip
|
|
773
|
+
self.getCommandAt(skip)['goto'] = self.getPC()
|
|
774
|
+
return True
|
|
775
|
+
|
|
776
|
+
def r_post(self, command):
|
|
777
|
+
global errorCode, errorReason
|
|
778
|
+
retval = {}
|
|
779
|
+
retval['type'] = 'text'
|
|
780
|
+
retval['numeric'] = False
|
|
781
|
+
value = self.getRuntimeValue(command['value'])
|
|
782
|
+
url = self.getRuntimeValue(command['url'])
|
|
783
|
+
try:
|
|
784
|
+
response = requests.post(url, value, timeout=5)
|
|
785
|
+
retval['content'] = response.text
|
|
786
|
+
if response.status_code >= 400:
|
|
787
|
+
errorCode = response.status_code
|
|
788
|
+
errorReason = response.reason
|
|
789
|
+
if command['or'] != None:
|
|
790
|
+
print(f'Error {errorCode} {errorReason}: Running the "or" clause')
|
|
791
|
+
return command['or']
|
|
792
|
+
else:
|
|
793
|
+
RuntimeError(self.program, f'Error code {errorCode}: {errorReason}')
|
|
794
|
+
except Exception as e:
|
|
795
|
+
errorReason = str(e)
|
|
796
|
+
if command['or'] != None:
|
|
797
|
+
print(f'Exception "{errorReason}": Running the "or" clause')
|
|
798
|
+
return command['or']
|
|
799
|
+
else:
|
|
800
|
+
RuntimeError(self.program, f'Error: {errorReason}')
|
|
801
|
+
if command['result'] != None:
|
|
802
|
+
result = self.getVariable(command['result'])
|
|
803
|
+
self.program.putSymbolValue(result, retval)
|
|
804
|
+
return self.nextPC()
|
|
805
|
+
|
|
806
|
+
# Print a value
|
|
807
|
+
def k_print(self, command):
|
|
808
|
+
value = self.nextValue()
|
|
809
|
+
if value != None:
|
|
810
|
+
command['value'] = value
|
|
811
|
+
self.add(command)
|
|
812
|
+
return True
|
|
813
|
+
FatalError(self.program.compiler, 'I can\'t print this value')
|
|
814
|
+
return False
|
|
815
|
+
|
|
816
|
+
def r_print(self, command):
|
|
817
|
+
value = self.getRuntimeValue(command['value'])
|
|
818
|
+
program = command['program']
|
|
819
|
+
code = program.code[program.pc]
|
|
820
|
+
lino = code['lino'] + 1
|
|
821
|
+
if value == None:
|
|
822
|
+
print(f'{lino}-> <empty>')
|
|
823
|
+
else:
|
|
824
|
+
print(f'{lino}-> {value}')
|
|
825
|
+
return self.nextPC()
|
|
826
|
+
|
|
827
|
+
# Push a value onto a stack
|
|
828
|
+
def k_push(self, command):
|
|
829
|
+
value = self.nextValue()
|
|
830
|
+
command['value'] = value
|
|
831
|
+
peekValue = self.peek()
|
|
832
|
+
if peekValue in ['onto', 'to']:
|
|
833
|
+
self.nextToken()
|
|
834
|
+
if self.nextIsSymbol():
|
|
835
|
+
symbolRecord = self.getSymbolRecord()
|
|
836
|
+
command['to'] = symbolRecord['name']
|
|
837
|
+
self.add(command)
|
|
838
|
+
return True
|
|
839
|
+
return False
|
|
840
|
+
|
|
841
|
+
def r_push(self, command):
|
|
842
|
+
value = self.getRuntimeValue(command['value'])
|
|
843
|
+
stackRecord = self.getVariable(command['to'])
|
|
844
|
+
if stackRecord['keyword'] != 'stack':
|
|
845
|
+
RuntimeError(self.program, f'{stackRecord["name"]} is not a stack')
|
|
846
|
+
return -1
|
|
847
|
+
stack = stackRecord['value'][stackRecord['index']]
|
|
848
|
+
if stack == None:
|
|
849
|
+
stack = [value]
|
|
850
|
+
else:
|
|
851
|
+
stack.append(value)
|
|
852
|
+
self.putSymbolValue(stackRecord, stack)
|
|
853
|
+
return self.nextPC()
|
|
854
|
+
|
|
855
|
+
# Put a value into a variable
|
|
856
|
+
def k_put(self, command):
|
|
857
|
+
command['value'] = self.nextValue()
|
|
858
|
+
if self.nextIs('into'):
|
|
859
|
+
if self.nextIsSymbol():
|
|
860
|
+
symbolRecord = self.getSymbolRecord()
|
|
861
|
+
command['target'] = symbolRecord['name']
|
|
862
|
+
if symbolRecord['valueHolder']:
|
|
863
|
+
self.add(command)
|
|
864
|
+
return True
|
|
865
|
+
else:
|
|
866
|
+
FatalError(self.program.compiler, f'Symbol {symbolRecord["name"]} is not a value holder')
|
|
867
|
+
else:
|
|
868
|
+
FatalError(self.program.compiler, f'No such variable: "{self.getToken()}"')
|
|
869
|
+
return False
|
|
870
|
+
|
|
871
|
+
def r_put(self, command):
|
|
872
|
+
value = self.evaluate(command['value'])
|
|
873
|
+
if value == None:
|
|
874
|
+
return -1
|
|
875
|
+
symbolRecord = self.getVariable(command['target'])
|
|
876
|
+
if not symbolRecord['valueHolder']:
|
|
877
|
+
RuntimeError(self.program, f'{symbolRecord["name"]} does not hold a value')
|
|
878
|
+
return -1
|
|
879
|
+
self.putSymbolValue(symbolRecord, value)
|
|
880
|
+
return self.nextPC()
|
|
881
|
+
|
|
882
|
+
# Read from a file
|
|
883
|
+
def k_read(self, command):
|
|
884
|
+
if self.peek() == 'line':
|
|
885
|
+
self.nextToken()
|
|
886
|
+
command['line'] = True
|
|
887
|
+
else:
|
|
888
|
+
command['line'] = False
|
|
889
|
+
if self.nextIsSymbol():
|
|
890
|
+
symbolRecord = self.getSymbolRecord()
|
|
891
|
+
if symbolRecord['valueHolder']:
|
|
892
|
+
if self.peek() == 'from':
|
|
893
|
+
self.nextToken()
|
|
894
|
+
if self.nextIsSymbol():
|
|
895
|
+
fileRecord = self.getSymbolRecord()
|
|
896
|
+
if fileRecord['keyword'] == 'file':
|
|
897
|
+
command['target'] = symbolRecord['name']
|
|
898
|
+
command['file'] = fileRecord['name']
|
|
899
|
+
self.add(command)
|
|
900
|
+
return True
|
|
901
|
+
FatalError(self.program.compiler, f'Symbol "{symbolRecord["name"]}" is not a value holder')
|
|
902
|
+
return False
|
|
903
|
+
FatalError(self.program.compiler, f'Symbol "{self.getToken()}" has not been declared')
|
|
904
|
+
return False
|
|
905
|
+
|
|
906
|
+
def r_read(self, command):
|
|
907
|
+
symbolRecord = self.getVariable(command['target'])
|
|
908
|
+
fileRecord = self.getVariable(command['file'])
|
|
909
|
+
line = command['line']
|
|
910
|
+
file = fileRecord['file']
|
|
911
|
+
if file.mode == 'r':
|
|
912
|
+
value = {}
|
|
913
|
+
content = file.readline().split('\n')[0] if line else file.read()
|
|
914
|
+
value['type'] = 'text'
|
|
915
|
+
value['numeric'] = False
|
|
916
|
+
value['content'] = content
|
|
917
|
+
self.putSymbolValue(symbolRecord, value)
|
|
918
|
+
return self.nextPC()
|
|
919
|
+
|
|
920
|
+
# Replace a substring
|
|
921
|
+
def k_replace(self, command):
|
|
922
|
+
original = self.nextValue()
|
|
923
|
+
if self.peek() == 'with':
|
|
924
|
+
self.nextToken()
|
|
925
|
+
replacement = self.nextValue()
|
|
926
|
+
if self.nextIs('in'):
|
|
927
|
+
if self.nextIsSymbol():
|
|
928
|
+
templateRecord = self.getSymbolRecord()
|
|
929
|
+
command['original'] = original
|
|
930
|
+
command['replacement'] = replacement
|
|
931
|
+
command['target'] = templateRecord['name']
|
|
932
|
+
self.add(command)
|
|
933
|
+
return True
|
|
934
|
+
return False
|
|
935
|
+
|
|
936
|
+
def r_replace(self, command):
|
|
937
|
+
templateRecord = self.getVariable(command['target'])
|
|
938
|
+
content = self.getSymbolValue(templateRecord)['content']
|
|
939
|
+
original = self.getRuntimeValue(command['original'])
|
|
940
|
+
replacement = self.getRuntimeValue(command['replacement'])
|
|
941
|
+
content = content.replace(original, replacement)
|
|
942
|
+
value = {}
|
|
943
|
+
value['type'] = 'text'
|
|
944
|
+
value['numeric'] = False
|
|
945
|
+
value['content'] = content
|
|
946
|
+
self.putSymbolValue(templateRecord, value)
|
|
947
|
+
return self.nextPC()
|
|
948
|
+
|
|
949
|
+
# Return from subroutine
|
|
950
|
+
def k_return(self, command):
|
|
951
|
+
self.add(command)
|
|
952
|
+
return True
|
|
953
|
+
|
|
954
|
+
def r_return(self, command):
|
|
955
|
+
return self.stack.pop()
|
|
956
|
+
|
|
957
|
+
# Provide a name for the script
|
|
958
|
+
def k_script(self, command):
|
|
959
|
+
self.program.name = self.nextToken()
|
|
960
|
+
return True
|
|
961
|
+
|
|
962
|
+
# Set a value
|
|
963
|
+
def k_set(self, command):
|
|
964
|
+
if self.nextIsSymbol():
|
|
965
|
+
target = self.getSymbolRecord()
|
|
966
|
+
if target['valueHolder']:
|
|
967
|
+
command['type'] = 'set'
|
|
968
|
+
command['target'] = target['name']
|
|
969
|
+
self.add(command)
|
|
970
|
+
return True
|
|
971
|
+
|
|
972
|
+
token = self.getToken()
|
|
973
|
+
if token == 'the':
|
|
974
|
+
token = self.nextToken()
|
|
975
|
+
if token == 'elements':
|
|
976
|
+
self.nextToken()
|
|
977
|
+
if self.peek() == 'of':
|
|
978
|
+
self.nextToken()
|
|
979
|
+
if self.nextIsSymbol():
|
|
980
|
+
command['type'] = 'elements'
|
|
981
|
+
command['name'] = self.getToken()
|
|
982
|
+
if self.peek() == 'to':
|
|
983
|
+
self.nextToken()
|
|
984
|
+
command['elements'] = self.nextValue()
|
|
985
|
+
self.add(command)
|
|
986
|
+
return True
|
|
987
|
+
|
|
988
|
+
if token == 'property':
|
|
989
|
+
command['type'] = 'property'
|
|
990
|
+
command['name'] = self.nextValue()
|
|
991
|
+
if self.nextIs('of'):
|
|
992
|
+
if self.nextIsSymbol():
|
|
993
|
+
command['target'] = self.getSymbolRecord()['name']
|
|
994
|
+
if self.nextIs('to'):
|
|
995
|
+
command['value'] = self.nextValue()
|
|
996
|
+
self.add(command)
|
|
997
|
+
return True
|
|
998
|
+
|
|
999
|
+
if token == 'element':
|
|
1000
|
+
command['type'] = 'element'
|
|
1001
|
+
command['index'] = self.nextValue()
|
|
1002
|
+
if self.nextIs('of'):
|
|
1003
|
+
if self.nextIsSymbol():
|
|
1004
|
+
command['target'] = self.getSymbolRecord()['name']
|
|
1005
|
+
if self.nextIs('to'):
|
|
1006
|
+
command['value'] = self.nextValue()
|
|
1007
|
+
self.add(command)
|
|
1008
|
+
return True
|
|
1009
|
+
|
|
1010
|
+
return False
|
|
1011
|
+
|
|
1012
|
+
def r_set(self, command):
|
|
1013
|
+
cmdType = command['type']
|
|
1014
|
+
if cmdType == 'set':
|
|
1015
|
+
target = self.getVariable(command['target'])
|
|
1016
|
+
val = {}
|
|
1017
|
+
val['type'] = 'boolean'
|
|
1018
|
+
val['content'] = True
|
|
1019
|
+
self.putSymbolValue(target, val)
|
|
1020
|
+
return self.nextPC()
|
|
1021
|
+
|
|
1022
|
+
if cmdType == 'elements':
|
|
1023
|
+
symbolRecord = self.getVariable(command['name'])
|
|
1024
|
+
elements = self.getRuntimeValue(command['elements'])
|
|
1025
|
+
currentElements = symbolRecord['elements']
|
|
1026
|
+
currentValue = symbolRecord['value']
|
|
1027
|
+
if currentValue == None:
|
|
1028
|
+
currentValue = [None]
|
|
1029
|
+
newValue = [None] * elements
|
|
1030
|
+
if elements > currentElements:
|
|
1031
|
+
for index, value in enumerate(currentValue):
|
|
1032
|
+
newValue[index] = value
|
|
1033
|
+
elif elements < currentElements:
|
|
1034
|
+
for index, value in enumerate(currentValue):
|
|
1035
|
+
if index < elements:
|
|
1036
|
+
newValue[index] = value
|
|
1037
|
+
symbolRecord['elements'] = elements
|
|
1038
|
+
symbolRecord['value'] = newValue
|
|
1039
|
+
return self.nextPC()
|
|
1040
|
+
|
|
1041
|
+
if cmdType == 'element':
|
|
1042
|
+
value = self.getRuntimeValue(command['value'])
|
|
1043
|
+
index = self.getRuntimeValue(command['index'])
|
|
1044
|
+
target = self.getVariable(command['target'])
|
|
1045
|
+
val = self.getSymbolValue(target)
|
|
1046
|
+
content = val['content']
|
|
1047
|
+
if content == '':
|
|
1048
|
+
content = []
|
|
1049
|
+
# else:
|
|
1050
|
+
# content = json.loads(content)
|
|
1051
|
+
content[index] = value
|
|
1052
|
+
val['content'] = content
|
|
1053
|
+
self.putSymbolValue(target, val)
|
|
1054
|
+
return self.nextPC()
|
|
1055
|
+
|
|
1056
|
+
if cmdType == 'property':
|
|
1057
|
+
value = self.getRuntimeValue(command['value'])
|
|
1058
|
+
name = self.getRuntimeValue(command['name'])
|
|
1059
|
+
target = command['target']
|
|
1060
|
+
targetVariable = self.getVariable(target)
|
|
1061
|
+
val = self.getSymbolValue(targetVariable)
|
|
1062
|
+
try:
|
|
1063
|
+
content = val['content']
|
|
1064
|
+
except:
|
|
1065
|
+
RuntimeError(self.program, f'{target} is not an object')
|
|
1066
|
+
if content == '':
|
|
1067
|
+
content = {}
|
|
1068
|
+
try:
|
|
1069
|
+
content[name] = value
|
|
1070
|
+
except:
|
|
1071
|
+
RuntimeError(self.program, f'{target} is not an object')
|
|
1072
|
+
val['content'] = content
|
|
1073
|
+
self.putSymbolValue(targetVariable, val)
|
|
1074
|
+
return self.nextPC()
|
|
1075
|
+
|
|
1076
|
+
# Split a string into a variable with several elements
|
|
1077
|
+
def k_split(self, command):
|
|
1078
|
+
if self.nextIsSymbol():
|
|
1079
|
+
symbolRecord = self.getSymbolRecord()
|
|
1080
|
+
if symbolRecord['valueHolder']:
|
|
1081
|
+
command['target'] = symbolRecord['name']
|
|
1082
|
+
value = {}
|
|
1083
|
+
value['type'] = 'text'
|
|
1084
|
+
value['numeric'] = 'false'
|
|
1085
|
+
value['content'] = '\n'
|
|
1086
|
+
command['on'] = value
|
|
1087
|
+
if self.peek() == 'on':
|
|
1088
|
+
self.nextToken()
|
|
1089
|
+
if self.peek() == 'tab':
|
|
1090
|
+
value['content'] = '\t'
|
|
1091
|
+
self.nextToken()
|
|
1092
|
+
else:
|
|
1093
|
+
command['on'] = self.nextValue()
|
|
1094
|
+
self.add(command)
|
|
1095
|
+
return True
|
|
1096
|
+
return False
|
|
1097
|
+
|
|
1098
|
+
def r_split(self, command):
|
|
1099
|
+
target = self.getVariable(command['target'])
|
|
1100
|
+
value = self.getSymbolValue(target)
|
|
1101
|
+
content = value['content'].split(self.getRuntimeValue(command['on']))
|
|
1102
|
+
elements = len(content)
|
|
1103
|
+
target['elements'] = elements
|
|
1104
|
+
target['value'] = [None] * elements
|
|
1105
|
+
|
|
1106
|
+
for index, item in enumerate(content):
|
|
1107
|
+
element = {}
|
|
1108
|
+
element['type'] = 'text'
|
|
1109
|
+
element['numeric'] = 'false'
|
|
1110
|
+
element['content'] = item
|
|
1111
|
+
target['value'][index] = element
|
|
1112
|
+
|
|
1113
|
+
return self.nextPC()
|
|
1114
|
+
|
|
1115
|
+
# Declare a stack variable
|
|
1116
|
+
def k_stack(self, command):
|
|
1117
|
+
return self.compileVariable(command)
|
|
1118
|
+
|
|
1119
|
+
def r_stack(self, command):
|
|
1120
|
+
return self.nextPC()
|
|
1121
|
+
|
|
1122
|
+
# Stop the current execution thread
|
|
1123
|
+
def k_stop(self, command):
|
|
1124
|
+
self.add(command)
|
|
1125
|
+
return True
|
|
1126
|
+
|
|
1127
|
+
def r_stop(self, command):
|
|
1128
|
+
return 0
|
|
1129
|
+
|
|
1130
|
+
# Issue a system call
|
|
1131
|
+
def k_system(self, command):
|
|
1132
|
+
background = False
|
|
1133
|
+
token = self.nextToken()
|
|
1134
|
+
if token == 'background':
|
|
1135
|
+
self.nextToken()
|
|
1136
|
+
background = True
|
|
1137
|
+
value = self.getValue()
|
|
1138
|
+
if value != None:
|
|
1139
|
+
command['value'] = value
|
|
1140
|
+
command['background'] = background
|
|
1141
|
+
self.add(command)
|
|
1142
|
+
return True
|
|
1143
|
+
FatalError(self.program.compiler, 'I can\'t give this command')
|
|
1144
|
+
return False
|
|
1145
|
+
|
|
1146
|
+
def r_system(self, command):
|
|
1147
|
+
value = self.getRuntimeValue(command['value'])
|
|
1148
|
+
background = command['background']
|
|
1149
|
+
if value != None:
|
|
1150
|
+
if command['background']:
|
|
1151
|
+
subprocess.Popen(["sh",value,"&"])
|
|
1152
|
+
else:
|
|
1153
|
+
os.system(value)
|
|
1154
|
+
return self.nextPC()
|
|
1155
|
+
|
|
1156
|
+
# Arithmetic subtraction
|
|
1157
|
+
def k_take(self, command):
|
|
1158
|
+
# Get the (first) value
|
|
1159
|
+
command['value1'] = self.nextValue()
|
|
1160
|
+
if self.nextToken() == 'from':
|
|
1161
|
+
if self.nextIsSymbol():
|
|
1162
|
+
symbolRecord = self.getSymbolRecord()
|
|
1163
|
+
if symbolRecord['valueHolder']:
|
|
1164
|
+
if self.peek() == 'giving':
|
|
1165
|
+
# This variable must be treated as a second value
|
|
1166
|
+
command['value2'] = self.getValue()
|
|
1167
|
+
self.nextToken()
|
|
1168
|
+
command['target'] = self.nextToken()
|
|
1169
|
+
self.add(command)
|
|
1170
|
+
return True
|
|
1171
|
+
else:
|
|
1172
|
+
# Here the variable is the target
|
|
1173
|
+
command['target'] = self.getToken()
|
|
1174
|
+
self.add(command)
|
|
1175
|
+
return True
|
|
1176
|
+
self.warning(f'core.take: Expected value holder')
|
|
1177
|
+
else:
|
|
1178
|
+
# Here we have 2 values so 'giving' must come next
|
|
1179
|
+
command['value2'] = self.getValue()
|
|
1180
|
+
if self.nextToken() == 'giving':
|
|
1181
|
+
if (self.nextIsSymbol()):
|
|
1182
|
+
command['target'] = self.getToken()
|
|
1183
|
+
self.add(command)
|
|
1184
|
+
return True
|
|
1185
|
+
else:
|
|
1186
|
+
FatalError(self.program.compiler, f'\'{self.getToken()}\' is not a symbol')
|
|
1187
|
+
else:
|
|
1188
|
+
self.warning(f'core.take: Expected "giving"')
|
|
1189
|
+
return False
|
|
1190
|
+
|
|
1191
|
+
def r_take(self, command):
|
|
1192
|
+
value1 = command['value1']
|
|
1193
|
+
try:
|
|
1194
|
+
value2 = command['value2']
|
|
1195
|
+
except:
|
|
1196
|
+
value2 = None
|
|
1197
|
+
target = self.getVariable(command['target'])
|
|
1198
|
+
if not target['valueHolder']:
|
|
1199
|
+
self.variableDoesNotHoldAValueError(target['name'])
|
|
1200
|
+
return None
|
|
1201
|
+
value = self.getSymbolValue(target)
|
|
1202
|
+
if value == None:
|
|
1203
|
+
value = {}
|
|
1204
|
+
value['type'] = 'int'
|
|
1205
|
+
if value2:
|
|
1206
|
+
v1 = int(self.getRuntimeValue(value1))
|
|
1207
|
+
v2 = int(self.getRuntimeValue(value2))
|
|
1208
|
+
value['content'] = v2-v1
|
|
1209
|
+
else:
|
|
1210
|
+
v = int(self.getRuntimeValue(value))
|
|
1211
|
+
v1 = int(self.getRuntimeValue(value1))
|
|
1212
|
+
value['content'] = v-v1
|
|
1213
|
+
self.putSymbolValue(target, value)
|
|
1214
|
+
return self.nextPC()
|
|
1215
|
+
|
|
1216
|
+
# Toggle a boolean value
|
|
1217
|
+
def k_toggle(self, command):
|
|
1218
|
+
if self.nextIsSymbol():
|
|
1219
|
+
target = self.getSymbolRecord()
|
|
1220
|
+
if target['valueHolder']:
|
|
1221
|
+
command['target'] = target['name']
|
|
1222
|
+
self.add(command)
|
|
1223
|
+
return True
|
|
1224
|
+
return False
|
|
1225
|
+
|
|
1226
|
+
def r_toggle(self, command):
|
|
1227
|
+
target = self.getVariable(command['target'])
|
|
1228
|
+
value = self.getSymbolValue(target)
|
|
1229
|
+
val = {}
|
|
1230
|
+
val['type'] = 'boolean'
|
|
1231
|
+
val['content'] = not value['content']
|
|
1232
|
+
self.putSymbolValue(target, val)
|
|
1233
|
+
self.add(command)
|
|
1234
|
+
return self.nextPC()
|
|
1235
|
+
|
|
1236
|
+
# Truncate a file
|
|
1237
|
+
def k_truncate(self, command):
|
|
1238
|
+
if self.nextIsSymbol():
|
|
1239
|
+
fileRecord = self.getSymbolRecord()
|
|
1240
|
+
if fileRecord['keyword'] == 'file':
|
|
1241
|
+
command['file'] = fileRecord['name']
|
|
1242
|
+
self.add(command)
|
|
1243
|
+
return True
|
|
1244
|
+
return False
|
|
1245
|
+
|
|
1246
|
+
def r_truncate(self, command):
|
|
1247
|
+
fileRecord = self.getVariable(command['file'])
|
|
1248
|
+
fileRecord['file'].truncate()
|
|
1249
|
+
return self.nextPC()
|
|
1250
|
+
|
|
1251
|
+
# Declare a general-purpose variable
|
|
1252
|
+
def k_variable(self, command):
|
|
1253
|
+
return self.compileVariable(command, True)
|
|
1254
|
+
|
|
1255
|
+
def r_variable(self, command):
|
|
1256
|
+
return self.nextPC()
|
|
1257
|
+
|
|
1258
|
+
# Pause for a specified time
|
|
1259
|
+
def k_wait(self, command):
|
|
1260
|
+
command['value'] = self.nextValue()
|
|
1261
|
+
multipliers = {}
|
|
1262
|
+
multipliers['milli'] = 1
|
|
1263
|
+
multipliers['millis'] = 1
|
|
1264
|
+
multipliers['tick'] = 10
|
|
1265
|
+
multipliers['ticks'] = 10
|
|
1266
|
+
multipliers['second'] = 1000
|
|
1267
|
+
multipliers['seconds'] = 1000
|
|
1268
|
+
multipliers['minute'] = 60000
|
|
1269
|
+
multipliers['minutes'] = 60000
|
|
1270
|
+
command['multiplier'] = multipliers['second']
|
|
1271
|
+
token = self.peek()
|
|
1272
|
+
if token in multipliers:
|
|
1273
|
+
self.nextToken()
|
|
1274
|
+
command['multiplier'] = multipliers[token]
|
|
1275
|
+
self.add(command)
|
|
1276
|
+
return True
|
|
1277
|
+
|
|
1278
|
+
def r_wait(self, command):
|
|
1279
|
+
value = self.getRuntimeValue(command['value']) * command['multiplier']
|
|
1280
|
+
next = self.nextPC()
|
|
1281
|
+
threading.Timer(value/1000.0, lambda: (self.run(next))).start()
|
|
1282
|
+
return 0
|
|
1283
|
+
|
|
1284
|
+
# While <condition> <action>
|
|
1285
|
+
def k_while(self, command):
|
|
1286
|
+
code = self.nextCondition()
|
|
1287
|
+
if code == None:
|
|
1288
|
+
return None
|
|
1289
|
+
# token = self.getToken()
|
|
1290
|
+
command['condition'] = code
|
|
1291
|
+
test = self.getPC()
|
|
1292
|
+
self.addCommand(command)
|
|
1293
|
+
# Set up a goto for when the test fails
|
|
1294
|
+
fail = self.getPC()
|
|
1295
|
+
cmd = {}
|
|
1296
|
+
cmd['lino'] = command['lino']
|
|
1297
|
+
cmd['domain'] = 'core'
|
|
1298
|
+
cmd['keyword'] = 'gotoPC'
|
|
1299
|
+
cmd['goto'] = 0
|
|
1300
|
+
cmd['debug'] = False
|
|
1301
|
+
self.addCommand(cmd)
|
|
1302
|
+
# Do the body of the while
|
|
1303
|
+
self.nextToken()
|
|
1304
|
+
if self.compileOne() == False:
|
|
1305
|
+
return False
|
|
1306
|
+
# Repeat the test
|
|
1307
|
+
cmd = {}
|
|
1308
|
+
cmd['lino'] = command['lino']
|
|
1309
|
+
cmd['domain'] = 'core'
|
|
1310
|
+
cmd['keyword'] = 'gotoPC'
|
|
1311
|
+
cmd['goto'] = test
|
|
1312
|
+
cmd['debug'] = False
|
|
1313
|
+
self.addCommand(cmd)
|
|
1314
|
+
# Fixup the 'goto' on completion
|
|
1315
|
+
self.getCommandAt(fail)['goto'] = self.getPC()
|
|
1316
|
+
return True
|
|
1317
|
+
|
|
1318
|
+
def r_while(self, command):
|
|
1319
|
+
test = self.program.condition.testCondition(command['condition'])
|
|
1320
|
+
if test:
|
|
1321
|
+
self.program.pc += 2
|
|
1322
|
+
else:
|
|
1323
|
+
self.program.pc += 1
|
|
1324
|
+
return self.program.pc
|
|
1325
|
+
|
|
1326
|
+
# Write to a file
|
|
1327
|
+
def k_write(self, command):
|
|
1328
|
+
if self.peek() == 'line':
|
|
1329
|
+
self.nextToken()
|
|
1330
|
+
command['line'] = True
|
|
1331
|
+
else:
|
|
1332
|
+
command['line'] = False
|
|
1333
|
+
command['value'] = self.nextValue()
|
|
1334
|
+
if self.peek() == 'to':
|
|
1335
|
+
self.nextToken()
|
|
1336
|
+
if self.nextIsSymbol():
|
|
1337
|
+
fileRecord = self.getSymbolRecord()
|
|
1338
|
+
if fileRecord['keyword'] == 'file':
|
|
1339
|
+
command['file'] = fileRecord['name']
|
|
1340
|
+
self.add(command)
|
|
1341
|
+
return True
|
|
1342
|
+
return False
|
|
1343
|
+
|
|
1344
|
+
def r_write(self, command):
|
|
1345
|
+
value = self.getRuntimeValue(command['value'])
|
|
1346
|
+
fileRecord = self.getVariable(command['file'])
|
|
1347
|
+
file = fileRecord['file']
|
|
1348
|
+
if file.mode in ['w', 'w+', 'a', 'a+']:
|
|
1349
|
+
file.write(f'{value}')
|
|
1350
|
+
if command['line']:
|
|
1351
|
+
file.write('\n')
|
|
1352
|
+
return self.nextPC()
|
|
1353
|
+
|
|
1354
|
+
#############################################################################
|
|
1355
|
+
# Support functions
|
|
1356
|
+
|
|
1357
|
+
def incdec(self, command, mode):
|
|
1358
|
+
symbolRecord = self.getVariable(command['target'])
|
|
1359
|
+
if not symbolRecord['valueHolder']:
|
|
1360
|
+
RuntimeError(self.program, f'{symbolRecord["name"]} does not hold a value')
|
|
1361
|
+
return None
|
|
1362
|
+
value = self.getSymbolValue(symbolRecord)
|
|
1363
|
+
if mode == '+':
|
|
1364
|
+
value['content'] += 1
|
|
1365
|
+
else:
|
|
1366
|
+
value['content'] -= 1
|
|
1367
|
+
self.putSymbolValue(symbolRecord, value)
|
|
1368
|
+
return self.nextPC()
|
|
1369
|
+
|
|
1370
|
+
#############################################################################
|
|
1371
|
+
# Compile a value in this domain
|
|
1372
|
+
def compileValue(self):
|
|
1373
|
+
value = {}
|
|
1374
|
+
value['domain'] = 'core'
|
|
1375
|
+
token = self.getToken()
|
|
1376
|
+
if self.isSymbol():
|
|
1377
|
+
value['name'] = token
|
|
1378
|
+
symbolRecord = self.getSymbolRecord()
|
|
1379
|
+
keyword = symbolRecord['keyword']
|
|
1380
|
+
if keyword == 'module':
|
|
1381
|
+
value['type'] = 'module'
|
|
1382
|
+
return value
|
|
1383
|
+
|
|
1384
|
+
if keyword == 'variable':
|
|
1385
|
+
value['type'] = 'symbol'
|
|
1386
|
+
return value
|
|
1387
|
+
return None
|
|
1388
|
+
|
|
1389
|
+
value['type'] = token
|
|
1390
|
+
|
|
1391
|
+
if token == 'arg':
|
|
1392
|
+
self.nextToken()
|
|
1393
|
+
value['index'] = self.getValue()
|
|
1394
|
+
return value
|
|
1395
|
+
|
|
1396
|
+
if token in ['cos', 'sin', 'tan']:
|
|
1397
|
+
value['angle'] = self.nextValue()
|
|
1398
|
+
if self.nextToken() == 'radius':
|
|
1399
|
+
value['radius'] = self.nextValue()
|
|
1400
|
+
return value
|
|
1401
|
+
return None
|
|
1402
|
+
|
|
1403
|
+
if token in ['now', 'today', 'newline', 'break', 'empty']:
|
|
1404
|
+
return value
|
|
1405
|
+
|
|
1406
|
+
if token in ['date', 'encode', 'decode', 'stringify', 'json', 'lowercase', 'uppercase', 'hash', 'random', 'float', 'integer']:
|
|
1407
|
+
value['content'] = self.nextValue()
|
|
1408
|
+
return value
|
|
1409
|
+
|
|
1410
|
+
if (token in ['datime', 'datetime']):
|
|
1411
|
+
value['type'] = 'datime'
|
|
1412
|
+
value['timestamp'] = self.nextValue()
|
|
1413
|
+
if self.peek() == 'format':
|
|
1414
|
+
self.nextToken()
|
|
1415
|
+
value['format'] = self.nextValue()
|
|
1416
|
+
else:
|
|
1417
|
+
value['format'] = None
|
|
1418
|
+
return value
|
|
1419
|
+
|
|
1420
|
+
if token == 'element':
|
|
1421
|
+
value['index'] = self.nextValue()
|
|
1422
|
+
if self.nextToken() == 'of':
|
|
1423
|
+
if self.nextIsSymbol():
|
|
1424
|
+
symbolRecord = self.getSymbolRecord()
|
|
1425
|
+
if symbolRecord['valueHolder']:
|
|
1426
|
+
value['target'] = symbolRecord['name']
|
|
1427
|
+
return value
|
|
1428
|
+
self.warning(f'Token \'{self.getToken()}\' does not hold a value')
|
|
1429
|
+
return None
|
|
1430
|
+
|
|
1431
|
+
if token == 'property':
|
|
1432
|
+
value['name'] = self.nextValue()
|
|
1433
|
+
if self.nextToken() == 'of':
|
|
1434
|
+
if self.nextIsSymbol():
|
|
1435
|
+
symbolRecord = self.getSymbolRecord()
|
|
1436
|
+
if symbolRecord['valueHolder']:
|
|
1437
|
+
value['target'] = symbolRecord['name']
|
|
1438
|
+
return value
|
|
1439
|
+
self.warning(f'Token \'{self.getToken()}\' does not hold a value')
|
|
1440
|
+
return None
|
|
1441
|
+
|
|
1442
|
+
if token == 'arg':
|
|
1443
|
+
value['content'] = self.nextValue()
|
|
1444
|
+
if self.getToken() == 'of':
|
|
1445
|
+
if self.nextIsSymbol():
|
|
1446
|
+
symbolRecord = self.getSymbolRecord()
|
|
1447
|
+
if symbolRecord['keyword'] == 'variable':
|
|
1448
|
+
value['target'] = symbolRecord['name']
|
|
1449
|
+
return value
|
|
1450
|
+
return None
|
|
1451
|
+
|
|
1452
|
+
if token == 'trim':
|
|
1453
|
+
self.nextToken()
|
|
1454
|
+
value['content'] = self.getValue()
|
|
1455
|
+
return value
|
|
1456
|
+
|
|
1457
|
+
if self.getToken() == 'the':
|
|
1458
|
+
self.nextToken()
|
|
1459
|
+
|
|
1460
|
+
token = self.getToken()
|
|
1461
|
+
value['type'] = token
|
|
1462
|
+
|
|
1463
|
+
if token == 'args':
|
|
1464
|
+
return value
|
|
1465
|
+
|
|
1466
|
+
if token == 'elements':
|
|
1467
|
+
if self.nextIs('of'):
|
|
1468
|
+
if self.nextIsSymbol():
|
|
1469
|
+
value['name'] = self.getToken()
|
|
1470
|
+
return value
|
|
1471
|
+
return None
|
|
1472
|
+
|
|
1473
|
+
if token == 'keys':
|
|
1474
|
+
if self.nextIs('of'):
|
|
1475
|
+
value['name'] = self.nextValue()
|
|
1476
|
+
return value
|
|
1477
|
+
return None
|
|
1478
|
+
|
|
1479
|
+
if token == 'count':
|
|
1480
|
+
if self.nextIs('of'):
|
|
1481
|
+
if self.nextIsSymbol():
|
|
1482
|
+
value['name'] = self.getToken()
|
|
1483
|
+
return value
|
|
1484
|
+
return None
|
|
1485
|
+
|
|
1486
|
+
if token == 'index':
|
|
1487
|
+
if self.nextIs('of'):
|
|
1488
|
+
if self.nextIsSymbol():
|
|
1489
|
+
if self.peek() == 'in':
|
|
1490
|
+
value['type'] = 'indexOf'
|
|
1491
|
+
if self.nextIsSymbol():
|
|
1492
|
+
value['target'] = self.getSymbolRecord()['name']
|
|
1493
|
+
return value
|
|
1494
|
+
else:
|
|
1495
|
+
value['name'] = self.getToken()
|
|
1496
|
+
return value
|
|
1497
|
+
else:
|
|
1498
|
+
value['value1'] = self.getValue()
|
|
1499
|
+
if self.nextIs('in'):
|
|
1500
|
+
value['type'] = 'indexOf'
|
|
1501
|
+
if self.nextIsSymbol():
|
|
1502
|
+
value['target'] = self.getSymbolRecord()['name']
|
|
1503
|
+
return value
|
|
1504
|
+
return None
|
|
1505
|
+
|
|
1506
|
+
if token == 'value':
|
|
1507
|
+
value['type'] = 'valueOf'
|
|
1508
|
+
if self.nextIs('of'):
|
|
1509
|
+
value['content'] = self.nextValue()
|
|
1510
|
+
return value
|
|
1511
|
+
return None
|
|
1512
|
+
|
|
1513
|
+
if token == 'length':
|
|
1514
|
+
value['type'] = 'lengthOf'
|
|
1515
|
+
if self.nextIs('of'):
|
|
1516
|
+
value['content'] = self.nextValue()
|
|
1517
|
+
return value
|
|
1518
|
+
return None
|
|
1519
|
+
|
|
1520
|
+
if token in ['left', 'right']:
|
|
1521
|
+
value['count'] = self.nextValue()
|
|
1522
|
+
if self.nextToken() == 'of':
|
|
1523
|
+
value['content'] = self.nextValue()
|
|
1524
|
+
return value
|
|
1525
|
+
return None
|
|
1526
|
+
|
|
1527
|
+
if token == 'from':
|
|
1528
|
+
value['start'] = self.nextValue()
|
|
1529
|
+
if self.peek() == 'to':
|
|
1530
|
+
self.nextToken()
|
|
1531
|
+
value['to'] = self.nextValue()
|
|
1532
|
+
else:
|
|
1533
|
+
value['to'] = None
|
|
1534
|
+
if self.nextToken() == 'of':
|
|
1535
|
+
value['content'] = self.nextValue()
|
|
1536
|
+
return value
|
|
1537
|
+
|
|
1538
|
+
if token == 'position':
|
|
1539
|
+
if self.nextIs('of'):
|
|
1540
|
+
value['last'] = False
|
|
1541
|
+
if self.nextIs('the'):
|
|
1542
|
+
if self.nextIs('last'):
|
|
1543
|
+
self.nextToken()
|
|
1544
|
+
value['last'] = True
|
|
1545
|
+
value['needle'] = self.getValue()
|
|
1546
|
+
if self.nextToken() == 'in':
|
|
1547
|
+
value['haystack'] = self.nextValue()
|
|
1548
|
+
return value
|
|
1549
|
+
|
|
1550
|
+
if token == 'message':
|
|
1551
|
+
self.nextToken()
|
|
1552
|
+
return value
|
|
1553
|
+
|
|
1554
|
+
if token == 'timestamp':
|
|
1555
|
+
value['format'] = None
|
|
1556
|
+
if self.peek() == 'of':
|
|
1557
|
+
self.nextToken()
|
|
1558
|
+
value['datime'] = self.nextValue()
|
|
1559
|
+
if self.peek() == 'format':
|
|
1560
|
+
self.nextToken()
|
|
1561
|
+
value['format'] = self.nextValue()
|
|
1562
|
+
return value
|
|
1563
|
+
|
|
1564
|
+
if token == 'files':
|
|
1565
|
+
if self.nextIs('of'):
|
|
1566
|
+
value['target'] = self.nextValue()
|
|
1567
|
+
return value
|
|
1568
|
+
return None
|
|
1569
|
+
|
|
1570
|
+
if token == 'weekday':
|
|
1571
|
+
value['type'] = 'weekday'
|
|
1572
|
+
return value
|
|
1573
|
+
|
|
1574
|
+
if token == 'mem' or token == 'memory':
|
|
1575
|
+
value['type'] = 'memory'
|
|
1576
|
+
return value
|
|
1577
|
+
|
|
1578
|
+
if token == 'error':
|
|
1579
|
+
if self.peek() == 'code':
|
|
1580
|
+
self.nextToken()
|
|
1581
|
+
value['item'] = 'errorCode'
|
|
1582
|
+
return value
|
|
1583
|
+
if self.peek() == 'reason':
|
|
1584
|
+
self.nextToken()
|
|
1585
|
+
value['item'] = 'errorReason'
|
|
1586
|
+
return value
|
|
1587
|
+
|
|
1588
|
+
if token == 'type':
|
|
1589
|
+
if self.nextIs('of'):
|
|
1590
|
+
value['value'] = self.nextValue()
|
|
1591
|
+
return value
|
|
1592
|
+
return None
|
|
1593
|
+
|
|
1594
|
+
if token == 'modification':
|
|
1595
|
+
if self.nextIs('time'):
|
|
1596
|
+
if self.nextIs('of'):
|
|
1597
|
+
value['fileName'] = self.nextValue()
|
|
1598
|
+
return value
|
|
1599
|
+
return None
|
|
1600
|
+
|
|
1601
|
+
print(f'Unknown token {token}')
|
|
1602
|
+
return None
|
|
1603
|
+
|
|
1604
|
+
#############################################################################
|
|
1605
|
+
# Modify a value or leave it unchanged.
|
|
1606
|
+
def modifyValue(self, value):
|
|
1607
|
+
if self.peek() == 'modulo':
|
|
1608
|
+
self.nextToken()
|
|
1609
|
+
mv = {}
|
|
1610
|
+
mv['domain'] = 'core'
|
|
1611
|
+
mv['type'] = 'modulo'
|
|
1612
|
+
mv['content'] = value
|
|
1613
|
+
mv['modval'] = self.nextValue()
|
|
1614
|
+
value = mv
|
|
1615
|
+
|
|
1616
|
+
return value
|
|
1617
|
+
|
|
1618
|
+
#############################################################################
|
|
1619
|
+
# Value handlers
|
|
1620
|
+
|
|
1621
|
+
def v_args(self, v):
|
|
1622
|
+
value = {}
|
|
1623
|
+
value['type'] = 'text'
|
|
1624
|
+
value['content'] = json.dumps(self.program.argv)
|
|
1625
|
+
return value
|
|
1626
|
+
|
|
1627
|
+
def v_arg(self, v):
|
|
1628
|
+
value = {}
|
|
1629
|
+
value['type'] = 'text'
|
|
1630
|
+
index = self.getRuntimeValue(v['index'])
|
|
1631
|
+
if index >= len(self.program.argv):
|
|
1632
|
+
RuntimeError(self.program, 'Index exceeds # of args')
|
|
1633
|
+
value['content'] = self.program.argv[index]
|
|
1634
|
+
return value
|
|
1635
|
+
|
|
1636
|
+
def v_boolean(self, v):
|
|
1637
|
+
value = {}
|
|
1638
|
+
value['type'] = 'boolean'
|
|
1639
|
+
value['content'] = v['content']
|
|
1640
|
+
return value
|
|
1641
|
+
|
|
1642
|
+
def v_cos(self, v):
|
|
1643
|
+
angle = self.getRuntimeValue(v['angle'])
|
|
1644
|
+
radius = self.getRuntimeValue(v['radius'])
|
|
1645
|
+
value = {}
|
|
1646
|
+
value['type'] = 'int'
|
|
1647
|
+
value['content'] = round(math.cos(angle * 0.01745329) * radius)
|
|
1648
|
+
return value
|
|
1649
|
+
|
|
1650
|
+
def v_datime(self, v):
|
|
1651
|
+
ts = self.getRuntimeValue(v['timestamp'])
|
|
1652
|
+
fmt = v['format']
|
|
1653
|
+
if fmt == None:
|
|
1654
|
+
fmt = '%b %d %Y %H:%M:%S'
|
|
1655
|
+
else:
|
|
1656
|
+
fmt = self.getRuntimeValue(fmt)
|
|
1657
|
+
value = {}
|
|
1658
|
+
value['type'] = 'text'
|
|
1659
|
+
value['content'] = datetime.fromtimestamp(ts/1000).strftime(fmt)
|
|
1660
|
+
return value
|
|
1661
|
+
|
|
1662
|
+
def v_decode(self, v):
|
|
1663
|
+
value = {}
|
|
1664
|
+
value['type'] = 'text'
|
|
1665
|
+
value['content'] = self.program.decode(v['content'])
|
|
1666
|
+
return value
|
|
1667
|
+
|
|
1668
|
+
def v_element(self, v):
|
|
1669
|
+
index = self.getRuntimeValue(v['index'])
|
|
1670
|
+
target = self.getVariable(v['target'])
|
|
1671
|
+
val = self.getSymbolValue(target)
|
|
1672
|
+
content = val['content']
|
|
1673
|
+
value = {}
|
|
1674
|
+
value['type'] = 'int' if isinstance(content, int) else 'text'
|
|
1675
|
+
if type(content) == list:
|
|
1676
|
+
try:
|
|
1677
|
+
value['content'] = content[index]
|
|
1678
|
+
return value
|
|
1679
|
+
except:
|
|
1680
|
+
RuntimeError(self.program, 'Index out of range')
|
|
1681
|
+
# lino = self.program.code[self.program.pc]['lino']
|
|
1682
|
+
RuntimeError(self.program, 'Item is not a list')
|
|
1683
|
+
|
|
1684
|
+
def v_elements(self, v):
|
|
1685
|
+
var = self.getVariable(v['name'])
|
|
1686
|
+
value = {}
|
|
1687
|
+
value['type'] = 'int'
|
|
1688
|
+
# value['content'] = self.getVariable(v['name'])['elements']
|
|
1689
|
+
value['content'] = var['elements']
|
|
1690
|
+
return value
|
|
1691
|
+
|
|
1692
|
+
def v_count(self, v):
|
|
1693
|
+
variable = self.getVariable(v['name'])
|
|
1694
|
+
content = variable['value'][variable['index']]['content']
|
|
1695
|
+
value = {}
|
|
1696
|
+
value['type'] = 'int'
|
|
1697
|
+
value['content'] = len(content)
|
|
1698
|
+
return value
|
|
1699
|
+
|
|
1700
|
+
def v_empty(self, v):
|
|
1701
|
+
value = {}
|
|
1702
|
+
value['type'] = 'text'
|
|
1703
|
+
value['content'] = ''
|
|
1704
|
+
return value
|
|
1705
|
+
|
|
1706
|
+
def v_encode(self, v):
|
|
1707
|
+
value = {}
|
|
1708
|
+
value['type'] = 'text'
|
|
1709
|
+
value['content'] = self.program.encode(v['content'])
|
|
1710
|
+
return value
|
|
1711
|
+
|
|
1712
|
+
def v_error(self, v):
|
|
1713
|
+
global errorCode, errorReason
|
|
1714
|
+
value = {}
|
|
1715
|
+
if v['item'] == 'errorCode':
|
|
1716
|
+
value['type'] = 'int'
|
|
1717
|
+
value['content'] = errorCode
|
|
1718
|
+
elif v['item'] == 'errorReason':
|
|
1719
|
+
value['type'] = 'text'
|
|
1720
|
+
value['content'] = errorReason
|
|
1721
|
+
return value
|
|
1722
|
+
|
|
1723
|
+
def v_stringify(self, v):
|
|
1724
|
+
item = self.getRuntimeValue(v['content'])
|
|
1725
|
+
value = {}
|
|
1726
|
+
value['type'] = 'text'
|
|
1727
|
+
value['content'] = json.dumps(item)
|
|
1728
|
+
return value
|
|
1729
|
+
|
|
1730
|
+
def v_json(self, v):
|
|
1731
|
+
item = self.getRuntimeValue(v['content'])
|
|
1732
|
+
value = {}
|
|
1733
|
+
value['type'] = 'object'
|
|
1734
|
+
try:
|
|
1735
|
+
value['content'] = json.loads(item)
|
|
1736
|
+
except:
|
|
1737
|
+
RuntimeError(self.program, 'Cannot encode value')
|
|
1738
|
+
return value
|
|
1739
|
+
|
|
1740
|
+
def v_from(self, v):
|
|
1741
|
+
content = self.getRuntimeValue(v['content'])
|
|
1742
|
+
start = self.getRuntimeValue(v['start'])
|
|
1743
|
+
to = v['to']
|
|
1744
|
+
if not to == None:
|
|
1745
|
+
to = self.getRuntimeValue(to)
|
|
1746
|
+
value = {}
|
|
1747
|
+
value['type'] = 'text'
|
|
1748
|
+
if to == None:
|
|
1749
|
+
value['content'] = content[start:]
|
|
1750
|
+
else:
|
|
1751
|
+
value['content'] = content[start:to]
|
|
1752
|
+
return value
|
|
1753
|
+
|
|
1754
|
+
def v_hash(self, v):
|
|
1755
|
+
hashval = self.getRuntimeValue(v['content'])
|
|
1756
|
+
value = {}
|
|
1757
|
+
value['type'] = 'text'
|
|
1758
|
+
value['content'] = hashlib.sha256(hashval.encode('utf-8')).hexdigest()
|
|
1759
|
+
return value
|
|
1760
|
+
|
|
1761
|
+
def v_float(self, v):
|
|
1762
|
+
val = self.getRuntimeValue(v['content'])
|
|
1763
|
+
value = {}
|
|
1764
|
+
value['type'] = 'float'
|
|
1765
|
+
try:
|
|
1766
|
+
value['content'] = float(val)
|
|
1767
|
+
except:
|
|
1768
|
+
RuntimeWarning(self.program, f'Value cannot be parsed as floating-point')
|
|
1769
|
+
value['content'] = 0.0
|
|
1770
|
+
return value
|
|
1771
|
+
|
|
1772
|
+
def v_index(self, v):
|
|
1773
|
+
value = {}
|
|
1774
|
+
value['type'] = 'int'
|
|
1775
|
+
value['content'] = self.getVariable(v['name'])['index']
|
|
1776
|
+
return value
|
|
1777
|
+
|
|
1778
|
+
def v_indexOf(self, v):
|
|
1779
|
+
value1 = v['value1']
|
|
1780
|
+
target = self.getVariable(v['target'])
|
|
1781
|
+
try:
|
|
1782
|
+
index = target['value'].index(value1)
|
|
1783
|
+
except:
|
|
1784
|
+
index = -1
|
|
1785
|
+
value = {}
|
|
1786
|
+
value['type'] = 'int'
|
|
1787
|
+
value['content'] = index
|
|
1788
|
+
return value
|
|
1789
|
+
|
|
1790
|
+
def v_integer(self, v):
|
|
1791
|
+
val = self.getRuntimeValue(v['content'])
|
|
1792
|
+
value = {}
|
|
1793
|
+
value['type'] = 'int'
|
|
1794
|
+
value['content'] = int(val)
|
|
1795
|
+
return value
|
|
1796
|
+
|
|
1797
|
+
def v_keys(self, v):
|
|
1798
|
+
value = {}
|
|
1799
|
+
value['type'] = 'int'
|
|
1800
|
+
value['content'] = list(self.getRuntimeValue(v['name']).keys())
|
|
1801
|
+
return value
|
|
1802
|
+
|
|
1803
|
+
def v_left(self, v):
|
|
1804
|
+
content = self.getRuntimeValue(v['content'])
|
|
1805
|
+
count = self.getRuntimeValue(v['count'])
|
|
1806
|
+
value = {}
|
|
1807
|
+
value['type'] = 'text'
|
|
1808
|
+
value['content'] = content[0:count]
|
|
1809
|
+
return value
|
|
1810
|
+
|
|
1811
|
+
def v_lengthOf(self, v):
|
|
1812
|
+
content = self.getRuntimeValue(v['content'])
|
|
1813
|
+
if type(content) == str:
|
|
1814
|
+
value = {}
|
|
1815
|
+
value['type'] = 'int'
|
|
1816
|
+
value['content'] = len(content)
|
|
1817
|
+
return value
|
|
1818
|
+
RuntimeError(self.program, 'Value is not a string')
|
|
1819
|
+
|
|
1820
|
+
def v_lowercase(self, v):
|
|
1821
|
+
content = self.getRuntimeValue(v['content'])
|
|
1822
|
+
value = {}
|
|
1823
|
+
value['type'] = 'text'
|
|
1824
|
+
value['content'] = content.lower()
|
|
1825
|
+
return value
|
|
1826
|
+
|
|
1827
|
+
def v_uppercase(self, v):
|
|
1828
|
+
content = self.getRuntimeValue(v['content'])
|
|
1829
|
+
value = {}
|
|
1830
|
+
value['type'] = 'text'
|
|
1831
|
+
value['content'] = content.upper()
|
|
1832
|
+
return value
|
|
1833
|
+
|
|
1834
|
+
def v_random(self, v):
|
|
1835
|
+
limit = self.getRuntimeValue(v['content'])
|
|
1836
|
+
value = {}
|
|
1837
|
+
value['type'] = 'int'
|
|
1838
|
+
value['content'] = randrange(0, limit)
|
|
1839
|
+
return value
|
|
1840
|
+
|
|
1841
|
+
def v_modulo(self, v):
|
|
1842
|
+
val = self.getRuntimeValue(v['content'])
|
|
1843
|
+
modval = self.getRuntimeValue(v['modval'])
|
|
1844
|
+
value = {}
|
|
1845
|
+
value['type'] = 'int'
|
|
1846
|
+
value['content'] = val % modval
|
|
1847
|
+
return value
|
|
1848
|
+
|
|
1849
|
+
def v_newline(self, v):
|
|
1850
|
+
value = {}
|
|
1851
|
+
value['type'] = 'text'
|
|
1852
|
+
value['content'] = '\n'
|
|
1853
|
+
return value
|
|
1854
|
+
|
|
1855
|
+
def v_now(self, v):
|
|
1856
|
+
value = {}
|
|
1857
|
+
value['type'] = 'int'
|
|
1858
|
+
value['content'] = getTimestamp(time.time())
|
|
1859
|
+
return value
|
|
1860
|
+
|
|
1861
|
+
def v_position(self, v):
|
|
1862
|
+
needle = self.getRuntimeValue(v['needle'])
|
|
1863
|
+
haystack = self.getRuntimeValue(v['haystack'])
|
|
1864
|
+
last = v['last']
|
|
1865
|
+
value = {}
|
|
1866
|
+
value['type'] = 'int'
|
|
1867
|
+
value['content'] = haystack.rfind(needle) if last else haystack.find(needle)
|
|
1868
|
+
return value
|
|
1869
|
+
|
|
1870
|
+
def v_property(self, v):
|
|
1871
|
+
propertyValue = self.getRuntimeValue(v['name'])
|
|
1872
|
+
targetName = v['target']
|
|
1873
|
+
target = self.getVariable(targetName)
|
|
1874
|
+
targetValue = self.getRuntimeValue(target)
|
|
1875
|
+
try:
|
|
1876
|
+
val = targetValue[propertyValue]
|
|
1877
|
+
except:
|
|
1878
|
+
RuntimeError(self.program, f'{targetName} does not have the property \'{propertyValue}\'')
|
|
1879
|
+
return None
|
|
1880
|
+
value = {}
|
|
1881
|
+
value['content'] = val
|
|
1882
|
+
if isinstance(v, numbers.Number):
|
|
1883
|
+
value['type'] = 'int'
|
|
1884
|
+
else:
|
|
1885
|
+
value['type'] = 'text'
|
|
1886
|
+
return value
|
|
1887
|
+
|
|
1888
|
+
def v_right(self, v):
|
|
1889
|
+
content = self.getRuntimeValue(v['content'])
|
|
1890
|
+
count = self.getRuntimeValue(v['count'])
|
|
1891
|
+
value = {}
|
|
1892
|
+
value['type'] = 'text'
|
|
1893
|
+
value['content'] = content[-count:]
|
|
1894
|
+
return value
|
|
1895
|
+
|
|
1896
|
+
def v_sin(self, v):
|
|
1897
|
+
angle = self.getRuntimeValue(v['angle'])
|
|
1898
|
+
radius = self.getRuntimeValue(v['radius'])
|
|
1899
|
+
value = {}
|
|
1900
|
+
value['type'] = 'int'
|
|
1901
|
+
value['content'] = round(math.sin(angle * 0.01745329) * radius)
|
|
1902
|
+
return value
|
|
1903
|
+
|
|
1904
|
+
def v_tan(self, v):
|
|
1905
|
+
angle = self.getRuntimeValue(v['angle'])
|
|
1906
|
+
radius = self.getRuntimeValue(v['radius'])
|
|
1907
|
+
value = {}
|
|
1908
|
+
value['type'] = 'int'
|
|
1909
|
+
value['content'] = round(math.tan(angle * 0.01745329) * radius)
|
|
1910
|
+
return value
|
|
1911
|
+
|
|
1912
|
+
def v_timestamp(self, v):
|
|
1913
|
+
value = {}
|
|
1914
|
+
value['type'] = 'int'
|
|
1915
|
+
fmt = v['format']
|
|
1916
|
+
if fmt == None:
|
|
1917
|
+
value['content'] = int(time.time())
|
|
1918
|
+
else:
|
|
1919
|
+
fmt = self.getRuntimeValue(fmt)
|
|
1920
|
+
dt = self.getRuntimeValue(v['datime'])
|
|
1921
|
+
spec = datetime.strptime(dt, fmt)
|
|
1922
|
+
t = datetime.now().replace(hour=spec.hour, minute=spec.minute, second=spec.second, microsecond=0)
|
|
1923
|
+
value['content'] = int(t.timestamp())
|
|
1924
|
+
return value
|
|
1925
|
+
|
|
1926
|
+
def v_today(self, v):
|
|
1927
|
+
value = {}
|
|
1928
|
+
value['type'] = 'int'
|
|
1929
|
+
value['content'] = int(datetime.combine(datetime.now().date(),datetime.min.time()).timestamp())*1000
|
|
1930
|
+
return value
|
|
1931
|
+
|
|
1932
|
+
def v_symbol(self, symbolRecord):
|
|
1933
|
+
result = {}
|
|
1934
|
+
if symbolRecord['keyword'] == 'variable':
|
|
1935
|
+
symbolValue = self.getSymbolValue(symbolRecord)
|
|
1936
|
+
return symbolValue
|
|
1937
|
+
# if symbolValue == None:
|
|
1938
|
+
# return None
|
|
1939
|
+
# result['type'] = symbolValue['type']
|
|
1940
|
+
# content = symbolValue['content']
|
|
1941
|
+
# if content == None:
|
|
1942
|
+
# return ''
|
|
1943
|
+
# result['content'] = content
|
|
1944
|
+
# return result
|
|
1945
|
+
else:
|
|
1946
|
+
return None
|
|
1947
|
+
|
|
1948
|
+
def v_valueOf(self, v):
|
|
1949
|
+
v = self.getRuntimeValue(v['content'])
|
|
1950
|
+
value = {}
|
|
1951
|
+
value['type'] = 'int'
|
|
1952
|
+
value['content'] = int(v)
|
|
1953
|
+
return value
|
|
1954
|
+
|
|
1955
|
+
def v_files(self, v):
|
|
1956
|
+
v = self.getRuntimeValue(v['target'])
|
|
1957
|
+
value = {}
|
|
1958
|
+
value['type'] = 'text'
|
|
1959
|
+
value['content'] = os.listdir(v)
|
|
1960
|
+
return value
|
|
1961
|
+
|
|
1962
|
+
def v_trim(self, v):
|
|
1963
|
+
v = self.getRuntimeValue(v['content'])
|
|
1964
|
+
value = {}
|
|
1965
|
+
value['type'] = 'text'
|
|
1966
|
+
value['content'] = v.strip()
|
|
1967
|
+
return value
|
|
1968
|
+
|
|
1969
|
+
def v_weekday(self, v):
|
|
1970
|
+
value = {}
|
|
1971
|
+
value['type'] = 'int'
|
|
1972
|
+
value['content'] = datetime.today().weekday()
|
|
1973
|
+
return value
|
|
1974
|
+
|
|
1975
|
+
def v_memory(self, v):
|
|
1976
|
+
process: Process = Process(os.getpid())
|
|
1977
|
+
megabytes: float = process.memory_info().rss / (1024 * 1024)
|
|
1978
|
+
value = {}
|
|
1979
|
+
value['type'] = 'float'
|
|
1980
|
+
value['content'] = megabytes
|
|
1981
|
+
return value
|
|
1982
|
+
|
|
1983
|
+
def v_type(self, v):
|
|
1984
|
+
value = {}
|
|
1985
|
+
value['type'] = 'text'
|
|
1986
|
+
val = self.getRuntimeValue(v['value'])
|
|
1987
|
+
if val is None:
|
|
1988
|
+
value['content'] = 'none'
|
|
1989
|
+
elif type(val) is str:
|
|
1990
|
+
value['content'] = 'text'
|
|
1991
|
+
elif type(val) is int:
|
|
1992
|
+
value['content'] = 'numeric'
|
|
1993
|
+
elif type(val) is bool:
|
|
1994
|
+
value['content'] = 'boolean'
|
|
1995
|
+
elif type(val) is list:
|
|
1996
|
+
value['content'] = 'list'
|
|
1997
|
+
elif type(val) is dict:
|
|
1998
|
+
value['content'] = 'object'
|
|
1999
|
+
return value
|
|
2000
|
+
|
|
2001
|
+
def v_modification(self, v):
|
|
2002
|
+
fileName = self.getRuntimeValue(v['fileName'])
|
|
2003
|
+
ts = int(os.stat(fileName).st_mtime)
|
|
2004
|
+
value = {}
|
|
2005
|
+
value['type'] = 'int'
|
|
2006
|
+
value['content'] = ts
|
|
2007
|
+
return value
|
|
2008
|
+
|
|
2009
|
+
#############################################################################
|
|
2010
|
+
# Compile a condition
|
|
2011
|
+
def compileCondition(self):
|
|
2012
|
+
condition = Condition()
|
|
2013
|
+
if self.getToken() == 'not':
|
|
2014
|
+
condition.type = 'not'
|
|
2015
|
+
condition.value = self.nextValue()
|
|
2016
|
+
return condition
|
|
2017
|
+
|
|
2018
|
+
if self.getToken() == 'file':
|
|
2019
|
+
path = self.nextValue()
|
|
2020
|
+
if self.peek() == 'exists':
|
|
2021
|
+
condition.type = 'exists'
|
|
2022
|
+
condition.path = path
|
|
2023
|
+
self.nextToken()
|
|
2024
|
+
return condition
|
|
2025
|
+
return None
|
|
2026
|
+
|
|
2027
|
+
value = self.getValue()
|
|
2028
|
+
if value == None:
|
|
2029
|
+
return None
|
|
2030
|
+
|
|
2031
|
+
condition.value1 = value
|
|
2032
|
+
token = self.peek()
|
|
2033
|
+
condition.type = token
|
|
2034
|
+
|
|
2035
|
+
if token == 'has':
|
|
2036
|
+
self.nextToken()
|
|
2037
|
+
if self.nextToken() == 'property':
|
|
2038
|
+
prop = self.nextValue()
|
|
2039
|
+
condition.type = 'hasProperty'
|
|
2040
|
+
condition.property = prop
|
|
2041
|
+
return condition
|
|
2042
|
+
return None
|
|
2043
|
+
|
|
2044
|
+
if token in ['starts', 'ends']:
|
|
2045
|
+
self.nextToken()
|
|
2046
|
+
if self.nextToken() == 'with':
|
|
2047
|
+
condition.value2 = self.nextValue()
|
|
2048
|
+
return condition
|
|
2049
|
+
|
|
2050
|
+
if token == 'includes':
|
|
2051
|
+
condition.value2 = self.nextValue()
|
|
2052
|
+
return condition
|
|
2053
|
+
|
|
2054
|
+
if token == 'is':
|
|
2055
|
+
token = self.nextToken()
|
|
2056
|
+
if self.peek() == 'not':
|
|
2057
|
+
self.nextToken()
|
|
2058
|
+
condition.negate = True
|
|
2059
|
+
token = self.nextToken()
|
|
2060
|
+
condition.type = token
|
|
2061
|
+
if token in ['numeric', 'string', 'boolean', 'none', 'list', 'object', 'even', 'odd', 'empty']:
|
|
2062
|
+
return condition
|
|
2063
|
+
if token in ['greater', 'less']:
|
|
2064
|
+
if self.nextToken() == 'than':
|
|
2065
|
+
condition.value2 = self.nextValue()
|
|
2066
|
+
return condition
|
|
2067
|
+
condition.type = 'is'
|
|
2068
|
+
condition.value2 = self.getValue()
|
|
2069
|
+
return condition
|
|
2070
|
+
|
|
2071
|
+
if condition.value1:
|
|
2072
|
+
# It's a boolean if
|
|
2073
|
+
condition.type = 'boolean'
|
|
2074
|
+
return condition
|
|
2075
|
+
|
|
2076
|
+
self.warning(f'I can\'t get a conditional:')
|
|
2077
|
+
return None
|
|
2078
|
+
|
|
2079
|
+
def isNegate(self):
|
|
2080
|
+
token = self.getToken()
|
|
2081
|
+
if token == 'not':
|
|
2082
|
+
self.nextToken()
|
|
2083
|
+
return True
|
|
2084
|
+
return False
|
|
2085
|
+
|
|
2086
|
+
#############################################################################
|
|
2087
|
+
# Condition handlers
|
|
2088
|
+
|
|
2089
|
+
def c_boolean(self, condition):
|
|
2090
|
+
value = self.getRuntimeValue(condition.value1)
|
|
2091
|
+
if type(value) == bool:
|
|
2092
|
+
return not value if condition.negate else value
|
|
2093
|
+
elif type(value) == int:
|
|
2094
|
+
return True if condition.negate else False
|
|
2095
|
+
elif type(value) == str:
|
|
2096
|
+
if value.lower() == 'true':
|
|
2097
|
+
return False if condition.negate else True
|
|
2098
|
+
elif value.lower() == 'false':
|
|
2099
|
+
return True if condition.negate else False
|
|
2100
|
+
else:
|
|
2101
|
+
return True if condition.negate else False
|
|
2102
|
+
return False
|
|
2103
|
+
|
|
2104
|
+
def c_numeric(self, condition):
|
|
2105
|
+
comparison = type(self.getRuntimeValue(condition.value1)) is int
|
|
2106
|
+
return not comparison if condition.negate else comparison
|
|
2107
|
+
|
|
2108
|
+
def c_string(self, condition):
|
|
2109
|
+
comparison = type(self.getRuntimeValue(condition.value1)) is str
|
|
2110
|
+
return not comparison if condition.negate else comparison
|
|
2111
|
+
|
|
2112
|
+
def c_list(self, condition):
|
|
2113
|
+
comparison = type(self.getRuntimeValue(condition.value1)) is list
|
|
2114
|
+
return not comparison if condition.negate else comparison
|
|
2115
|
+
|
|
2116
|
+
def c_object(self, condition):
|
|
2117
|
+
comparison = type(self.getRuntimeValue(condition.value1)) is dict
|
|
2118
|
+
return not comparison if condition.negate else comparison
|
|
2119
|
+
|
|
2120
|
+
def c_none(self, condition):
|
|
2121
|
+
comparison = self.getRuntimeValue(condition.value1) is None
|
|
2122
|
+
return not comparison if condition.negate else comparison
|
|
2123
|
+
|
|
2124
|
+
def c_not(self, condition):
|
|
2125
|
+
return not self.getRuntimeValue(condition.value1)
|
|
2126
|
+
|
|
2127
|
+
def c_even(self, condition):
|
|
2128
|
+
return self.getRuntimeValue(condition.value1) % 2 == 0
|
|
2129
|
+
|
|
2130
|
+
def c_odd(self, condition):
|
|
2131
|
+
return self.getRuntimeValue(condition.value1) % 2 == 1
|
|
2132
|
+
|
|
2133
|
+
def c_is(self, condition):
|
|
2134
|
+
comparison = self.program.compare(condition.value1, condition.value2)
|
|
2135
|
+
return comparison != 0 if condition.negate else comparison == 0
|
|
2136
|
+
|
|
2137
|
+
def c_greater(self, condition):
|
|
2138
|
+
comparison = self.program.compare(condition.value1, condition.value2)
|
|
2139
|
+
return comparison <= 0 if condition.negate else comparison > 0
|
|
2140
|
+
|
|
2141
|
+
def c_less(self, condition):
|
|
2142
|
+
comparison = self.program.compare(condition.value1, condition.value2)
|
|
2143
|
+
return comparison >= 0 if condition.negate else comparison < 0
|
|
2144
|
+
|
|
2145
|
+
def c_starts(self, condition):
|
|
2146
|
+
value1 = self.getRuntimeValue(condition.value1)
|
|
2147
|
+
value2 = self.getRuntimeValue(condition.value2)
|
|
2148
|
+
return value1.startswith(value2)
|
|
2149
|
+
|
|
2150
|
+
def c_ends(self, condition):
|
|
2151
|
+
value1 = self.getRuntimeValue(condition.value1)
|
|
2152
|
+
value2 = self.getRuntimeValue(condition.value2)
|
|
2153
|
+
return value1.endswith(value2)
|
|
2154
|
+
|
|
2155
|
+
def c_includes(self, condition):
|
|
2156
|
+
value1 = self.getRuntimeValue(condition.value1)
|
|
2157
|
+
value2 = self.getRuntimeValue(condition.value2)
|
|
2158
|
+
return value2 in value1
|
|
2159
|
+
|
|
2160
|
+
def c_empty(self, condition):
|
|
2161
|
+
value = self.getRuntimeValue(condition.value1)
|
|
2162
|
+
if value == None:
|
|
2163
|
+
comparison = True
|
|
2164
|
+
else:
|
|
2165
|
+
comparison = len(value) == 0
|
|
2166
|
+
return not comparison if condition.negate else comparison
|
|
2167
|
+
|
|
2168
|
+
def c_exists(self, condition):
|
|
2169
|
+
path = self.getRuntimeValue(condition.path)
|
|
2170
|
+
return os.path.exists(path)
|
|
2171
|
+
|
|
2172
|
+
def c_hasProperty(self, condition):
|
|
2173
|
+
value = self.getRuntimeValue(condition.value1)
|
|
2174
|
+
prop = self.getRuntimeValue(condition.property)
|
|
2175
|
+
try:
|
|
2176
|
+
value[prop]
|
|
2177
|
+
hasProp = True
|
|
2178
|
+
except:
|
|
2179
|
+
hasProp = False
|
|
2180
|
+
return hasProp
|
|
2181
|
+
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|