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/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