easycoder 241211.3__py2.py3-none-any.whl → 250116.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 CHANGED
@@ -1,4 +1,4 @@
1
- import json, math, hashlib, threading, os, subprocess, sys, requests, time, numbers
1
+ import json, math, hashlib, threading, os, subprocess, sys, requests, time, numbers, base64
2
2
  from psutil import Process
3
3
  from datetime import datetime, timezone
4
4
  from random import randrange
@@ -10,6 +10,7 @@ class Core(Handler):
10
10
 
11
11
  def __init__(self, compiler):
12
12
  Handler.__init__(self, compiler)
13
+ self.encoding = 'utf-8'
13
14
 
14
15
  def getName(self):
15
16
  return 'core'
@@ -38,7 +39,7 @@ class Core(Handler):
38
39
  command['target'] = self.getToken()
39
40
  self.add(command)
40
41
  return True
41
- self.warning(f'core.add: Expected value holder')
42
+ self.warning(f'Core.add: Expected value holder')
42
43
  else:
43
44
  # Here we have 2 values so 'giving' must come next
44
45
  command['value2'] = self.getValue()
@@ -46,7 +47,7 @@ class Core(Handler):
46
47
  command['target'] = self.nextToken()
47
48
  self.add(command)
48
49
  return True
49
- self.warning(f'core.add: Expected "giving"')
50
+ self.warning(f'Core.add: Expected "giving"')
50
51
  return False
51
52
 
52
53
  def r_add(self, command):
@@ -90,7 +91,7 @@ class Core(Handler):
90
91
  command['target'] = symbolRecord['name']
91
92
  self.add(command)
92
93
  return True
93
- self.warning(f'Variable "{symbolRecord["name"]}" does not hold a value')
94
+ self.warning(f'Core.append: Variable "{symbolRecord["name"]}" does not hold a value')
94
95
  return False
95
96
 
96
97
  def r_append(self, command):
@@ -248,7 +249,7 @@ class Core(Handler):
248
249
  command['target'] = self.getToken()
249
250
  self.add(command)
250
251
  return True
251
- self.warning(f'Variable "{symbolRecord["name"]}" does not hold a value')
252
+ self.warning(f'Core.decrement: Variable "{symbolRecord["name"]}" does not hold a value')
252
253
  return False
253
254
 
254
255
  def r_decrement(self, command):
@@ -272,9 +273,9 @@ class Core(Handler):
272
273
  self.add(command)
273
274
  return True
274
275
  else:
275
- self.warning(f'"of" expected; got {self.getToken()}')
276
+ self.warning(f'Core.delete: "of" expected; got {self.getToken()}')
276
277
  else:
277
- self.warning(f'"file" or "property" expected; got {token}')
278
+ self.warning(f'Core.delete: "file" or "property" expected; got {token}')
278
279
  return False
279
280
 
280
281
  def r_delete(self, command):
@@ -366,8 +367,7 @@ class Core(Handler):
366
367
  return True
367
368
 
368
369
  def r_exit(self, command):
369
- sys.exit()
370
- return 0
370
+ return -1
371
371
 
372
372
  # Declare a file variable
373
373
  def k_file(self, command):
@@ -461,26 +461,9 @@ class Core(Handler):
461
461
  else:
462
462
  RuntimeError(self.program, f'Error: {errorReason}')
463
463
  retval['content'] = response.text
464
- self.program.putSymbolValue(target, retval);
464
+ self.program.putSymbolValue(target, retval)
465
465
  return self.nextPC()
466
466
 
467
- # Call a subroutine
468
- def k_gosub(self, command):
469
- if self.peek() == 'to':
470
- self.nextToken()
471
- command['gosub'] = self.nextToken()
472
- self.add(command)
473
- return True
474
-
475
- def r_gosub(self, command):
476
- label = command['gosub'] + ':'
477
- address = self.symbols[label]
478
- if address != None:
479
- self.stack.append(self.nextPC())
480
- return address
481
- RuntimeError(self.program, f'There is no label "{label + ":"}"')
482
- return None
483
-
484
467
  # Go to a label
485
468
  def k_go(self, command):
486
469
  if self.peek() == 'to':
@@ -506,6 +489,23 @@ class Core(Handler):
506
489
  def r_gotoPC(self, command):
507
490
  return command['goto']
508
491
 
492
+ # Call a subroutine
493
+ def k_gosub(self, command):
494
+ if self.peek() == 'to':
495
+ self.nextToken()
496
+ command['gosub'] = self.nextToken()
497
+ self.add(command)
498
+ return True
499
+
500
+ def r_gosub(self, command):
501
+ label = command['gosub'] + ':'
502
+ address = self.symbols[label]
503
+ if address != None:
504
+ self.stack.append(self.nextPC())
505
+ return address
506
+ RuntimeError(self.program, f'There is no label "{label + ":"}"')
507
+ return None
508
+
509
509
  # if <condition> <action> [else <action>]
510
510
  def k_if(self, command):
511
511
  command['condition'] = self.nextCondition()
@@ -552,15 +552,55 @@ class Core(Handler):
552
552
  self.program.pc += 1
553
553
  return self.program.pc
554
554
 
555
- # Import a plugin. This is done at compile time.
556
- # import {class} from {source}
557
555
  def k_import(self, command):
558
- clazz = self.nextToken()
559
- if self.nextIs('from'):
560
- source = self.nextToken()
561
- self.program.importPlugin(f'{source}:{clazz}')
556
+ if self.peek() == 'plugin':
557
+ # Import a plugin
558
+ self.nextToken()
559
+ clazz = self.nextToken()
560
+ if self.nextIs('from'):
561
+ source = self.nextToken()
562
+ self.program.importPlugin(f'{source}:{clazz}')
563
+ return True
564
+ return False
565
+ else:
566
+ # Import one or more variables
567
+ imports = []
568
+ while True:
569
+ keyword = self.nextToken()
570
+ name = self.nextToken()
571
+ item = [keyword, name]
572
+ imports.append(item)
573
+ self.symbols[name] = self.getPC()
574
+ variable = {}
575
+ variable['domain'] = None
576
+ variable['name'] = name
577
+ variable['keyword'] = keyword
578
+ variable['import'] = None
579
+ self.addCommand(variable)
580
+ if self.peek() != 'and':
581
+ break
582
+ self.nextToken()
583
+ command['imports'] = json.dumps(imports)
584
+ self.add(command)
562
585
  return True
563
- return False
586
+
587
+ def r_import(self, command):
588
+ exports = self.program.exports
589
+ imports = json.loads(command['imports'])
590
+ if len(imports) < len(exports):
591
+ RuntimeError(self.program, 'Too few imports')
592
+ elif len(imports) > len(exports):
593
+ RuntimeError(self.program, 'Too many imports')
594
+ for n in range(0, len(imports)):
595
+ exportRecord = exports[n]
596
+ exportKeyword = exportRecord['keyword']
597
+ name = imports[n][1]
598
+ symbolRecord = self.program.getSymbolRecord(name)
599
+ symbolKeyword = symbolRecord['keyword']
600
+ if symbolKeyword != exportKeyword:
601
+ RuntimeError(self.program, f'Import {n} ({symbolKeyword}) does not match export {n} ({exportKeyword})')
602
+ symbolRecord['import'] = exportRecord
603
+ return self.nextPC()
564
604
 
565
605
  # Increment a variable
566
606
  def k_increment(self, command):
@@ -570,7 +610,7 @@ class Core(Handler):
570
610
  command['target'] = self.getToken()
571
611
  self.add(command)
572
612
  return True
573
- self.warning(f'Variable "{symbolRecord["name"]}" does not hold a value')
613
+ self.warning(f'Core.increment: Variable "{symbolRecord["name"]}" does not hold a value')
574
614
  return False
575
615
 
576
616
  def r_increment(self, command):
@@ -645,6 +685,57 @@ class Core(Handler):
645
685
  self.putSymbolValue(symbolRecord, value)
646
686
  return self.nextPC()
647
687
 
688
+ # 1 Load a plugin. This is done at compile time.
689
+ # 2 Load text from a file
690
+ def k_load(self, command):
691
+ self.nextToken()
692
+ if self.tokenIs('plugin'):
693
+ clazz = self.nextToken()
694
+ if self.nextIs('from'):
695
+ source = self.nextToken()
696
+ self.program.importPlugin(f'{source}:{clazz}')
697
+ return True
698
+ elif self.isSymbol():
699
+ command['target'] = self.getToken()
700
+ if self.nextIs('from'):
701
+ command['file'] = self.nextValue()
702
+ self.add(command)
703
+ return True
704
+ return False
705
+
706
+ def r_load(self, command):
707
+ target = self.getVariable(command['target'])
708
+ file = self.getRuntimeValue(command['file'])
709
+ f = open(file, 'r')
710
+ content = f.read()
711
+ f.close()
712
+ value = {}
713
+ value['type'] = 'text'
714
+ value['content'] = content
715
+ self.putSymbolValue(target, value)
716
+ return self.nextPC()
717
+
718
+ # Lock a variable
719
+ def k_lock(self, command):
720
+ if self.nextIsSymbol():
721
+ symbolRecord = self.getSymbolRecord()
722
+ command['target'] = symbolRecord['name']
723
+ self.add(command)
724
+ return True
725
+ return False
726
+
727
+ def r_lock(self, command):
728
+ target = self.getVariable(command['target'])
729
+ target['locked'] = True
730
+ return self.nextPC()
731
+
732
+ # Declare a module variable
733
+ def k_module(self, command):
734
+ return self.compileVariable(command)
735
+
736
+ def r_module(self, command):
737
+ return self.nextPC()
738
+
648
739
  # Arithmetic multiply
649
740
  # multiply {variable} by {value}[ giving {variable}]}
650
741
  def k_multiply(self, command):
@@ -696,6 +787,29 @@ class Core(Handler):
696
787
  self.putSymbolValue(target, value)
697
788
  return self.nextPC()
698
789
 
790
+ # Negate a variable
791
+ def k_negate(self, command):
792
+ if self.nextIsSymbol():
793
+ symbolRecord = self.getSymbolRecord()
794
+ if symbolRecord['valueHolder']:
795
+ command['target'] = self.getToken()
796
+ self.add(command)
797
+ return True
798
+ self.warning(f'Core.negate: Variable "{symbolRecord["name"]}" does not hold a value')
799
+ return False
800
+
801
+ def r_negate(self, command):
802
+ symbolRecord = self.getVariable(command['target'])
803
+ if not symbolRecord['valueHolder']:
804
+ RuntimeError(self.program, f'{symbolRecord["name"]} does not hold a value')
805
+ return None
806
+ value = self.getSymbolValue(symbolRecord)
807
+ if value == None:
808
+ RuntimeError(self.program, f'{symbolRecord["name"]} has not been initialised')
809
+ value['content'] *= -1
810
+ self.putSymbolValue(symbolRecord, value)
811
+ return self.nextPC()
812
+
699
813
  # Define an object variable
700
814
  def k_object(self, command):
701
815
  return self.compileVariable(command)
@@ -703,6 +817,36 @@ class Core(Handler):
703
817
  def r_object(self, command):
704
818
  return self.nextPC()
705
819
 
820
+ # on message {action}
821
+ def k_on(self, command):
822
+ if self.nextIs('message'):
823
+ self.nextToken()
824
+ command['goto'] = 0
825
+ self.add(command)
826
+ cmd = {}
827
+ cmd['domain'] = 'core'
828
+ cmd['lino'] = command['lino']
829
+ cmd['keyword'] = 'gotoPC'
830
+ cmd['goto'] = 0
831
+ cmd['debug'] = False
832
+ self.addCommand(cmd)
833
+ # Add the action and a 'stop'
834
+ self.compileOne()
835
+ cmd = {}
836
+ cmd['domain'] = 'core'
837
+ cmd['lino'] = command['lino']
838
+ cmd['keyword'] = 'stop'
839
+ cmd['debug'] = False
840
+ self.addCommand(cmd)
841
+ # Fixup the link
842
+ command['goto'] = self.getPC()
843
+ return True
844
+ return False
845
+
846
+ def r_on(self, command):
847
+ self.program.onMessage(self.nextPC()+1)
848
+ return command['goto']
849
+
706
850
  # Open a file
707
851
  # open {file} for reading/writing/appending
708
852
  def k_open(self, command):
@@ -724,12 +868,14 @@ class Core(Handler):
724
868
  FatalError(self.program.compiler, 'Unknown file open mode {self.getToken()}')
725
869
  return False
726
870
  command['mode'] = mode
727
- self.add(command)
728
- return True
871
+ else:
872
+ command['mode'] = 'r'
873
+ self.add(command)
874
+ return True
729
875
  else:
730
876
  FatalError(self.compiler, f'Variable "{self.getToken()}" is not a file')
731
877
  else:
732
- self.warning(f'core.open: Variable "{self.getToken()}" not declared')
878
+ self.warning(f'Core.open: Variable "{self.getToken()}" not declared')
733
879
  return False
734
880
 
735
881
  def r_open(self, command):
@@ -893,13 +1039,13 @@ class Core(Handler):
893
1039
  if self.nextIsSymbol():
894
1040
  symbolRecord = self.getSymbolRecord()
895
1041
  command['target'] = symbolRecord['name']
896
- if symbolRecord['valueHolder']:
1042
+ if 'valueholder' in symbolRecord and symbolRecord['valueHolder'] == False:
1043
+ FatalError(self.program.compiler, f'Symbol {symbolRecord["name"]} is not a value holder')
1044
+ else:
897
1045
  self.add(command)
898
1046
  return True
899
- else:
900
- FatalError(self.program.compiler, f'Symbol {symbolRecord["name"]} is not a value holder')
901
1047
  else:
902
- FatalError(self.program.compiler, f'No such variable: "{self.getToken()}"')
1048
+ FatalError(self.program.compiler, f'Symbol {self.getToken()} is not a variable')
903
1049
  return False
904
1050
 
905
1051
  def r_put(self, command):
@@ -974,7 +1120,7 @@ class Core(Handler):
974
1120
  content = self.getSymbolValue(templateRecord)['content']
975
1121
  original = self.getRuntimeValue(command['original'])
976
1122
  replacement = self.getRuntimeValue(command['replacement'])
977
- content = content.replace(original, replacement)
1123
+ content = content.replace(original, str(replacement))
978
1124
  value = {}
979
1125
  value['type'] = 'text'
980
1126
  value['numeric'] = False
@@ -982,6 +1128,16 @@ class Core(Handler):
982
1128
  self.putSymbolValue(templateRecord, value)
983
1129
  return self.nextPC()
984
1130
 
1131
+ # Release the parent script
1132
+ def k_release(self, command):
1133
+ if self.nextIs('parent'):
1134
+ self.add(command)
1135
+ return True
1136
+
1137
+ def r_release(self, command):
1138
+ self.program.releaseParent()
1139
+ return self.nextPC()
1140
+
985
1141
  # Return from subroutine
986
1142
  def k_return(self, command):
987
1143
  self.add(command)
@@ -990,11 +1146,87 @@ class Core(Handler):
990
1146
  def r_return(self, command):
991
1147
  return self.stack.pop()
992
1148
 
1149
+ # Compile and run a script
1150
+ def k_run(self, command):
1151
+ try:
1152
+ command['path'] = self.nextValue()
1153
+ except Exception as e:
1154
+ self.warning(f'Core.run: Path expected')
1155
+ return False
1156
+ if self.nextIs('as'):
1157
+ if self.nextIsSymbol():
1158
+ record = self.getSymbolRecord()
1159
+ if record['keyword'] == 'module':
1160
+ command['module'] = record['name']
1161
+ exports = []
1162
+ if self.nextIs('with'):
1163
+ while True:
1164
+ name = self.nextToken()
1165
+ record = self.getSymbolRecord()
1166
+ exports.append(name)
1167
+ if self.peek() != 'and':
1168
+ break
1169
+ self.nextToken()
1170
+ command['exports'] = json.dumps(exports)
1171
+ self.add(command)
1172
+ return True
1173
+ return False
1174
+
1175
+ def r_run(self, command):
1176
+ module = self.getVariable(command['module'])
1177
+ path = self.getRuntimeValue(command['path'])
1178
+ exports = json.loads(command['exports'])
1179
+ for n in range(0, len(exports)):
1180
+ exports[n] = self.getVariable(exports[n])
1181
+ module['path'] = path
1182
+ parent = Object()
1183
+ parent.program = self.program
1184
+ parent.pc = self.nextPC()
1185
+ parent.waiting = True
1186
+ p = self.program.__class__
1187
+ p(path).start(parent, module, exports)
1188
+ return 0
1189
+
993
1190
  # Provide a name for the script
994
1191
  def k_script(self, command):
995
1192
  self.program.name = self.nextToken()
996
1193
  return True
997
1194
 
1195
+ # Save a value to a file
1196
+ def k_save(self, command):
1197
+ command['content'] = self.nextValue()
1198
+ if self.nextIs('to'):
1199
+ command['file'] = self.nextValue()
1200
+ self.add(command)
1201
+ return True
1202
+ return False
1203
+
1204
+ def r_save(self, command):
1205
+ content = self.getRuntimeValue(command['content'])
1206
+ file = self.getRuntimeValue(command['file'])
1207
+ f = open(file, 'w')
1208
+ f.write(content)
1209
+ f.close()
1210
+ return self.nextPC()
1211
+
1212
+ # Send a message to a module
1213
+ def k_send(self, command):
1214
+ command['message'] = self.nextValue()
1215
+ if self.nextIs('to'):
1216
+ if self.nextIsSymbol():
1217
+ record = self.getSymbolRecord()
1218
+ if record['keyword'] == 'module':
1219
+ command['module'] = record['name']
1220
+ self.add(command)
1221
+ return True
1222
+ return False
1223
+
1224
+ def r_send(self, command):
1225
+ message = self.getRuntimeValue(command['message'])
1226
+ module = self.getVariable(command['module'])
1227
+ module['child'].handleMessage(message)
1228
+ return self.nextPC()
1229
+
998
1230
  # Set a value
999
1231
  # set {variable}
1000
1232
  # set the elements of {variable} to {value}
@@ -1007,16 +1239,18 @@ class Core(Handler):
1007
1239
  command['target'] = target['name']
1008
1240
  self.add(command)
1009
1241
  return True
1242
+ return False
1010
1243
 
1011
1244
  token = self.getToken()
1012
1245
  if token == 'the':
1013
1246
  token = self.nextToken()
1247
+ command['type'] = token
1248
+
1014
1249
  if token == 'elements':
1015
1250
  self.nextToken()
1016
1251
  if self.peek() == 'of':
1017
1252
  self.nextToken()
1018
1253
  if self.nextIsSymbol():
1019
- command['type'] = 'elements'
1020
1254
  command['name'] = self.getToken()
1021
1255
  if self.peek() == 'to':
1022
1256
  self.nextToken()
@@ -1024,8 +1258,13 @@ class Core(Handler):
1024
1258
  self.add(command)
1025
1259
  return True
1026
1260
 
1027
- if token == 'property':
1028
- command['type'] = 'property'
1261
+ elif token == 'encoding':
1262
+ if self.nextIs('to'):
1263
+ command['encoding'] = self.nextValue()
1264
+ self.add(command)
1265
+ return True
1266
+
1267
+ elif token == 'property':
1029
1268
  command['name'] = self.nextValue()
1030
1269
  if self.nextIs('of'):
1031
1270
  if self.nextIsSymbol():
@@ -1035,8 +1274,7 @@ class Core(Handler):
1035
1274
  self.add(command)
1036
1275
  return True
1037
1276
 
1038
- if token == 'element':
1039
- command['type'] = 'element'
1277
+ elif token == 'element':
1040
1278
  command['index'] = self.nextValue()
1041
1279
  if self.nextIs('of'):
1042
1280
  if self.nextIsSymbol():
@@ -1045,7 +1283,6 @@ class Core(Handler):
1045
1283
  command['value'] = self.nextValue()
1046
1284
  self.add(command)
1047
1285
  return True
1048
-
1049
1286
  return False
1050
1287
 
1051
1288
  def r_set(self, command):
@@ -1058,7 +1295,7 @@ class Core(Handler):
1058
1295
  self.putSymbolValue(target, val)
1059
1296
  return self.nextPC()
1060
1297
 
1061
- if cmdType == 'elements':
1298
+ elif cmdType == 'elements':
1062
1299
  symbolRecord = self.getVariable(command['name'])
1063
1300
  elements = self.getRuntimeValue(command['elements'])
1064
1301
  currentElements = symbolRecord['elements']
@@ -1077,7 +1314,7 @@ class Core(Handler):
1077
1314
  symbolRecord['value'] = newValue
1078
1315
  return self.nextPC()
1079
1316
 
1080
- if cmdType == 'element':
1317
+ elif cmdType == 'element':
1081
1318
  value = self.getRuntimeValue(command['value'])
1082
1319
  index = self.getRuntimeValue(command['index'])
1083
1320
  target = self.getVariable(command['target'])
@@ -1092,7 +1329,11 @@ class Core(Handler):
1092
1329
  self.putSymbolValue(target, val)
1093
1330
  return self.nextPC()
1094
1331
 
1095
- if cmdType == 'property':
1332
+ elif cmdType == 'encoding':
1333
+ self.encoding = self.getRuntimeValue(command['encoding'])
1334
+ return self.nextPC()
1335
+
1336
+ elif cmdType == 'property':
1096
1337
  value = self.getRuntimeValue(command['value'])
1097
1338
  name = self.getRuntimeValue(command['name'])
1098
1339
  target = command['target']
@@ -1215,7 +1456,7 @@ class Core(Handler):
1215
1456
  command['target'] = self.getToken()
1216
1457
  self.add(command)
1217
1458
  return True
1218
- self.warning(f'core.take: Expected value holder')
1459
+ self.warning(f'Core.take: Expected value holder')
1219
1460
  else:
1220
1461
  # Here we have 2 values so 'giving' must come next
1221
1462
  command['value2'] = self.getValue()
@@ -1227,7 +1468,7 @@ class Core(Handler):
1227
1468
  else:
1228
1469
  FatalError(self.program.compiler, f'\'{self.getToken()}\' is not a symbol')
1229
1470
  else:
1230
- self.warning(f'core.take: Expected "giving"')
1471
+ self.warning(f'Core.take: Expected "giving"')
1231
1472
  return False
1232
1473
 
1233
1474
  def r_take(self, command):
@@ -1290,6 +1531,20 @@ class Core(Handler):
1290
1531
  fileRecord['file'].truncate()
1291
1532
  return self.nextPC()
1292
1533
 
1534
+ # Unlock a variable
1535
+ def k_unlock(self, command):
1536
+ if self.nextIsSymbol():
1537
+ symbolRecord = self.getSymbolRecord()
1538
+ command['target'] = symbolRecord['name']
1539
+ self.add(command)
1540
+ return True
1541
+ return False
1542
+
1543
+ def r_unlock(self, command):
1544
+ target = self.getVariable(command['target'])
1545
+ target['locked'] = False
1546
+ return self.nextPC()
1547
+
1293
1548
  # Declare a general-purpose variable
1294
1549
  def k_variable(self, command):
1295
1550
  return self.compileVariable(command, True)
@@ -1402,6 +1657,8 @@ class Core(Handler):
1402
1657
  RuntimeError(self.program, f'{symbolRecord["name"]} does not hold a value')
1403
1658
  return None
1404
1659
  value = self.getSymbolValue(symbolRecord)
1660
+ if value == None:
1661
+ RuntimeError(self.program, f'{symbolRecord["name"]} has not been initialised')
1405
1662
  if mode == '+':
1406
1663
  value['content'] += 1
1407
1664
  else:
@@ -1413,7 +1670,7 @@ class Core(Handler):
1413
1670
  # Compile a value in this domain
1414
1671
  def compileValue(self):
1415
1672
  value = {}
1416
- value['domain'] = 'core'
1673
+ value['domain'] = self.getName()
1417
1674
  token = self.getToken()
1418
1675
  if self.isSymbol():
1419
1676
  value['name'] = token
@@ -1442,10 +1699,10 @@ class Core(Handler):
1442
1699
  return value
1443
1700
  return None
1444
1701
 
1445
- if token in ['now', 'today', 'newline', 'break', 'empty']:
1702
+ if token in ['now', 'today', 'newline', 'tab', 'empty']:
1446
1703
  return value
1447
1704
 
1448
- if token in ['date', 'encode', 'decode', 'stringify', 'json', 'lowercase', 'uppercase', 'hash', 'random', 'float', 'integer']:
1705
+ if token in ['stringify', 'json', 'lowercase', 'uppercase', 'hash', 'random', 'float', 'integer', 'encode', 'decode']:
1449
1706
  value['content'] = self.nextValue()
1450
1707
  return value
1451
1708
 
@@ -1467,7 +1724,7 @@ class Core(Handler):
1467
1724
  if symbolRecord['valueHolder']:
1468
1725
  value['target'] = symbolRecord['name']
1469
1726
  return value
1470
- self.warning(f'Token \'{self.getToken()}\' does not hold a value')
1727
+ self.warning(f'Core.compileValue: Token \'{self.getToken()}\' does not hold a value')
1471
1728
  return None
1472
1729
 
1473
1730
  if token == 'property':
@@ -1478,7 +1735,7 @@ class Core(Handler):
1478
1735
  if symbolRecord['valueHolder']:
1479
1736
  value['target'] = symbolRecord['name']
1480
1737
  return value
1481
- self.warning(f'Token \'{self.getToken()}\' does not hold a value')
1738
+ self.warning(f'Core.compileValue: Token \'{self.getToken()}\' does not hold a value')
1482
1739
  return None
1483
1740
 
1484
1741
  if token == 'arg':
@@ -1528,7 +1785,9 @@ class Core(Handler):
1528
1785
  if token == 'index':
1529
1786
  if self.nextIs('of'):
1530
1787
  if self.nextIsSymbol():
1788
+ value['variable'] = self.getSymbolRecord()['name']
1531
1789
  if self.peek() == 'in':
1790
+ value['value'] = None
1532
1791
  value['type'] = 'indexOf'
1533
1792
  if self.nextIsSymbol():
1534
1793
  value['target'] = self.getSymbolRecord()['name']
@@ -1537,8 +1796,9 @@ class Core(Handler):
1537
1796
  value['name'] = self.getToken()
1538
1797
  return value
1539
1798
  else:
1540
- value['value1'] = self.getValue()
1799
+ value['value'] = self.getValue()
1541
1800
  if self.nextIs('in'):
1801
+ value['variable'] = None
1542
1802
  value['type'] = 'indexOf'
1543
1803
  if self.nextIsSymbol():
1544
1804
  value['target'] = self.getSymbolRecord()['name']
@@ -1590,7 +1850,6 @@ class Core(Handler):
1590
1850
  return value
1591
1851
 
1592
1852
  if token == 'message':
1593
- self.nextToken()
1594
1853
  return value
1595
1854
 
1596
1855
  if token == 'timestamp':
@@ -1604,7 +1863,8 @@ class Core(Handler):
1604
1863
  return value
1605
1864
 
1606
1865
  if token == 'files':
1607
- if self.nextIs('of'):
1866
+ token = self.nextToken()
1867
+ if token in ['in', 'of']:
1608
1868
  value['target'] = self.nextValue()
1609
1869
  return value
1610
1870
  return None
@@ -1640,7 +1900,6 @@ class Core(Handler):
1640
1900
  return value
1641
1901
  return None
1642
1902
 
1643
- self.warning(f'Core: Unknown token {token}')
1644
1903
  return None
1645
1904
 
1646
1905
  #############################################################################
@@ -1689,6 +1948,14 @@ class Core(Handler):
1689
1948
  value['content'] = round(math.cos(angle * 0.01745329) * radius)
1690
1949
  return value
1691
1950
 
1951
+ def v_count(self, v):
1952
+ variable = self.getVariable(v['name'])
1953
+ content = variable['value'][variable['index']]['content']
1954
+ value = {}
1955
+ value['type'] = 'int'
1956
+ value['content'] = len(content)
1957
+ return value
1958
+
1692
1959
  def v_datime(self, v):
1693
1960
  ts = self.getRuntimeValue(v['timestamp'])
1694
1961
  fmt = v['format']
@@ -1702,9 +1969,17 @@ class Core(Handler):
1702
1969
  return value
1703
1970
 
1704
1971
  def v_decode(self, v):
1972
+ content = self.getRuntimeValue(v['content'])
1705
1973
  value = {}
1706
1974
  value['type'] = 'text'
1707
- value['content'] = self.program.decode(v['content'])
1975
+ if self.encoding == 'utf-8':
1976
+ value['content'] = content.decode('utf-8')
1977
+ elif self.encoding == 'base64':
1978
+ base64_bytes = content.encode('ascii')
1979
+ message_bytes = base64.b64decode(base64_bytes)
1980
+ value['content'] = message_bytes.decode('ascii')
1981
+ else:
1982
+ value = v
1708
1983
  return value
1709
1984
 
1710
1985
  def v_element(self, v):
@@ -1727,18 +2002,9 @@ class Core(Handler):
1727
2002
  var = self.getVariable(v['name'])
1728
2003
  value = {}
1729
2004
  value['type'] = 'int'
1730
- # value['content'] = self.getVariable(v['name'])['elements']
1731
2005
  value['content'] = var['elements']
1732
2006
  return value
1733
2007
 
1734
- def v_count(self, v):
1735
- variable = self.getVariable(v['name'])
1736
- content = variable['value'][variable['index']]['content']
1737
- value = {}
1738
- value['type'] = 'int'
1739
- value['content'] = len(content)
1740
- return value
1741
-
1742
2008
  def v_empty(self, v):
1743
2009
  value = {}
1744
2010
  value['type'] = 'text'
@@ -1746,9 +2012,17 @@ class Core(Handler):
1746
2012
  return value
1747
2013
 
1748
2014
  def v_encode(self, v):
2015
+ content = self.getRuntimeValue(v['content'])
1749
2016
  value = {}
1750
2017
  value['type'] = 'text'
1751
- value['content'] = self.program.encode(v['content'])
2018
+ if self.encoding == 'utf-8':
2019
+ value['content'] = content.encode('utf-8')
2020
+ elif self.encoding == 'base64':
2021
+ data_bytes = content.encode('ascii')
2022
+ base64_bytes = base64.b64encode(data_bytes)
2023
+ value['content'] = base64_bytes.decode('ascii')
2024
+ else:
2025
+ value = v
1752
2026
  return value
1753
2027
 
1754
2028
  def v_error(self, v):
@@ -1762,21 +2036,22 @@ class Core(Handler):
1762
2036
  value['content'] = errorReason
1763
2037
  return value
1764
2038
 
1765
- def v_stringify(self, v):
1766
- item = self.getRuntimeValue(v['content'])
2039
+ def v_files(self, v):
2040
+ v = self.getRuntimeValue(v['target'])
1767
2041
  value = {}
1768
2042
  value['type'] = 'text'
1769
- value['content'] = json.dumps(item)
2043
+ value['content'] = os.listdir(v)
1770
2044
  return value
1771
2045
 
1772
- def v_json(self, v):
1773
- item = self.getRuntimeValue(v['content'])
2046
+ def v_float(self, v):
2047
+ val = self.getRuntimeValue(v['content'])
1774
2048
  value = {}
1775
- value['type'] = 'object'
2049
+ value['type'] = 'float'
1776
2050
  try:
1777
- value['content'] = json.loads(item)
2051
+ value['content'] = float(val)
1778
2052
  except:
1779
- RuntimeError(self.program, 'Cannot encode value')
2053
+ RuntimeWarning(self.program, f'Value cannot be parsed as floating-point')
2054
+ value['content'] = 0.0
1780
2055
  return value
1781
2056
 
1782
2057
  def v_from(self, v):
@@ -1800,17 +2075,6 @@ class Core(Handler):
1800
2075
  value['content'] = hashlib.sha256(hashval.encode('utf-8')).hexdigest()
1801
2076
  return value
1802
2077
 
1803
- def v_float(self, v):
1804
- val = self.getRuntimeValue(v['content'])
1805
- value = {}
1806
- value['type'] = 'float'
1807
- try:
1808
- value['content'] = float(val)
1809
- except:
1810
- RuntimeWarning(self.program, f'Value cannot be parsed as floating-point')
1811
- value['content'] = 0.0
1812
- return value
1813
-
1814
2078
  def v_index(self, v):
1815
2079
  value = {}
1816
2080
  value['type'] = 'int'
@@ -1818,16 +2082,22 @@ class Core(Handler):
1818
2082
  return value
1819
2083
 
1820
2084
  def v_indexOf(self, v):
1821
- value1 = v['value1']
2085
+ value = v['value']
2086
+ if value == None:
2087
+ value = self.getSymbolValue(v['variable'])['content']
2088
+ else:
2089
+ value = self.getRuntimeValue(value)
1822
2090
  target = self.getVariable(v['target'])
1823
- try:
1824
- index = target['value'].index(value1)
1825
- except:
1826
- index = -1
1827
- value = {}
1828
- value['type'] = 'int'
1829
- value['content'] = index
1830
- return value
2091
+ data = self.getSymbolValue(target)['content']
2092
+ index = -1
2093
+ for n in range(0, len(data)):
2094
+ if data[n] == value:
2095
+ index = n
2096
+ break
2097
+ retval = {}
2098
+ retval['type'] = 'int'
2099
+ retval['content'] = index
2100
+ return retval
1831
2101
 
1832
2102
  def v_integer(self, v):
1833
2103
  val = self.getRuntimeValue(v['content'])
@@ -1836,6 +2106,16 @@ class Core(Handler):
1836
2106
  value['content'] = int(val)
1837
2107
  return value
1838
2108
 
2109
+ def v_json(self, v):
2110
+ item = self.getRuntimeValue(v['content'])
2111
+ value = {}
2112
+ value['type'] = 'object'
2113
+ try:
2114
+ value['content'] = json.loads(item)
2115
+ except:
2116
+ RuntimeError(self.program, 'Cannot encode value')
2117
+ return value
2118
+
1839
2119
  def v_keys(self, v):
1840
2120
  value = {}
1841
2121
  value['type'] = 'int'
@@ -1866,18 +2146,26 @@ class Core(Handler):
1866
2146
  value['content'] = content.lower()
1867
2147
  return value
1868
2148
 
1869
- def v_uppercase(self, v):
1870
- content = self.getRuntimeValue(v['content'])
2149
+ def v_memory(self, v):
2150
+ process: Process = Process(os.getpid())
2151
+ megabytes: float = process.memory_info().rss / (1024 * 1024)
2152
+ value = {}
2153
+ value['type'] = 'float'
2154
+ value['content'] = megabytes
2155
+ return value
2156
+
2157
+ def v_message(self, v):
1871
2158
  value = {}
1872
2159
  value['type'] = 'text'
1873
- value['content'] = content.upper()
2160
+ value['content'] = self.program.message
1874
2161
  return value
1875
2162
 
1876
- def v_random(self, v):
1877
- limit = self.getRuntimeValue(v['content'])
2163
+ def v_modification(self, v):
2164
+ fileName = self.getRuntimeValue(v['fileName'])
2165
+ ts = int(os.stat(fileName).st_mtime)
1878
2166
  value = {}
1879
2167
  value['type'] = 'int'
1880
- value['content'] = randrange(0, limit)
2168
+ value['content'] = ts
1881
2169
  return value
1882
2170
 
1883
2171
  def v_modulo(self, v):
@@ -1927,6 +2215,13 @@ class Core(Handler):
1927
2215
  value['type'] = 'text'
1928
2216
  return value
1929
2217
 
2218
+ def v_random(self, v):
2219
+ limit = self.getRuntimeValue(v['content'])
2220
+ value = {}
2221
+ value['type'] = 'int'
2222
+ value['content'] = randrange(0, limit)
2223
+ return value
2224
+
1930
2225
  def v_right(self, v):
1931
2226
  content = self.getRuntimeValue(v['content'])
1932
2227
  count = self.getRuntimeValue(v['count'])
@@ -1943,6 +2238,28 @@ class Core(Handler):
1943
2238
  value['content'] = round(math.sin(angle * 0.01745329) * radius)
1944
2239
  return value
1945
2240
 
2241
+ def v_stringify(self, v):
2242
+ item = self.getRuntimeValue(v['content'])
2243
+ value = {}
2244
+ value['type'] = 'text'
2245
+ value['content'] = json.dumps(item)
2246
+ return value
2247
+
2248
+ # This is used by the expression evaluator to get the value of a symbol
2249
+ def v_symbol(self, symbolRecord):
2250
+ result = {}
2251
+ if symbolRecord['keyword'] == 'variable':
2252
+ symbolValue = self.getSymbolValue(symbolRecord)
2253
+ return symbolValue
2254
+ else:
2255
+ return None
2256
+
2257
+ def v_tab(self, v):
2258
+ value = {}
2259
+ value['type'] = 'text'
2260
+ value['content'] = '\t'
2261
+ return value
2262
+
1946
2263
  def v_tan(self, v):
1947
2264
  angle = self.getRuntimeValue(v['angle'])
1948
2265
  radius = self.getRuntimeValue(v['radius'])
@@ -1971,36 +2288,6 @@ class Core(Handler):
1971
2288
  value['content'] = int(datetime.combine(datetime.now().date(),datetime.min.time()).timestamp())*1000
1972
2289
  return value
1973
2290
 
1974
- def v_symbol(self, symbolRecord):
1975
- result = {}
1976
- if symbolRecord['keyword'] == 'variable':
1977
- symbolValue = self.getSymbolValue(symbolRecord)
1978
- return symbolValue
1979
- # if symbolValue == None:
1980
- # return None
1981
- # result['type'] = symbolValue['type']
1982
- # content = symbolValue['content']
1983
- # if content == None:
1984
- # return ''
1985
- # result['content'] = content
1986
- # return result
1987
- else:
1988
- return None
1989
-
1990
- def v_valueOf(self, v):
1991
- v = self.getRuntimeValue(v['content'])
1992
- value = {}
1993
- value['type'] = 'int'
1994
- value['content'] = int(v)
1995
- return value
1996
-
1997
- def v_files(self, v):
1998
- v = self.getRuntimeValue(v['target'])
1999
- value = {}
2000
- value['type'] = 'text'
2001
- value['content'] = os.listdir(v)
2002
- return value
2003
-
2004
2291
  def v_trim(self, v):
2005
2292
  v = self.getRuntimeValue(v['content'])
2006
2293
  value = {}
@@ -2008,20 +2295,6 @@ class Core(Handler):
2008
2295
  value['content'] = v.strip()
2009
2296
  return value
2010
2297
 
2011
- def v_weekday(self, v):
2012
- value = {}
2013
- value['type'] = 'int'
2014
- value['content'] = datetime.today().weekday()
2015
- return value
2016
-
2017
- def v_memory(self, v):
2018
- process: Process = Process(os.getpid())
2019
- megabytes: float = process.memory_info().rss / (1024 * 1024)
2020
- value = {}
2021
- value['type'] = 'float'
2022
- value['content'] = megabytes
2023
- return value
2024
-
2025
2298
  def v_type(self, v):
2026
2299
  value = {}
2027
2300
  value['type'] = 'text'
@@ -2040,12 +2313,24 @@ class Core(Handler):
2040
2313
  value['content'] = 'object'
2041
2314
  return value
2042
2315
 
2043
- def v_modification(self, v):
2044
- fileName = self.getRuntimeValue(v['fileName'])
2045
- ts = int(os.stat(fileName).st_mtime)
2316
+ def v_uppercase(self, v):
2317
+ content = self.getRuntimeValue(v['content'])
2318
+ value = {}
2319
+ value['type'] = 'text'
2320
+ value['content'] = content.upper()
2321
+ return value
2322
+
2323
+ def v_valueOf(self, v):
2324
+ v = self.getRuntimeValue(v['content'])
2046
2325
  value = {}
2047
2326
  value['type'] = 'int'
2048
- value['content'] = ts
2327
+ value['content'] = int(v)
2328
+ return value
2329
+
2330
+ def v_weekday(self, v):
2331
+ value = {}
2332
+ value['type'] = 'int'
2333
+ value['content'] = datetime.today().weekday()
2049
2334
  return value
2050
2335
 
2051
2336
  #############################################################################
@@ -2115,7 +2400,7 @@ class Core(Handler):
2115
2400
  condition.type = 'boolean'
2116
2401
  return condition
2117
2402
 
2118
- self.warning(f'I can\'t get a conditional:')
2403
+ self.warning(f'Core.compileCondition: I can\'t get a conditional:')
2119
2404
  return None
2120
2405
 
2121
2406
  def isNegate(self):
@@ -2143,20 +2428,59 @@ class Core(Handler):
2143
2428
  return True if condition.negate else False
2144
2429
  return False
2145
2430
 
2146
- def c_numeric(self, condition):
2147
- comparison = type(self.getRuntimeValue(condition.value1)) is int
2431
+ def c_empty(self, condition):
2432
+ value = self.getRuntimeValue(condition.value1)
2433
+ if value == None:
2434
+ comparison = True
2435
+ else:
2436
+ comparison = len(value) == 0
2148
2437
  return not comparison if condition.negate else comparison
2149
2438
 
2150
- def c_string(self, condition):
2151
- comparison = type(self.getRuntimeValue(condition.value1)) is str
2152
- return not comparison if condition.negate else comparison
2439
+ def c_ends(self, condition):
2440
+ value1 = self.getRuntimeValue(condition.value1)
2441
+ value2 = self.getRuntimeValue(condition.value2)
2442
+ return value1.endswith(value2)
2443
+
2444
+ def c_even(self, condition):
2445
+ return self.getRuntimeValue(condition.value1) % 2 == 0
2446
+
2447
+ def c_exists(self, condition):
2448
+ path = self.getRuntimeValue(condition.path)
2449
+ return os.path.exists(path)
2450
+
2451
+ def c_greater(self, condition):
2452
+ comparison = self.program.compare(condition.value1, condition.value2)
2453
+ return comparison <= 0 if condition.negate else comparison > 0
2454
+
2455
+ def c_hasProperty(self, condition):
2456
+ value = self.getRuntimeValue(condition.value1)
2457
+ prop = self.getRuntimeValue(condition.property)
2458
+ try:
2459
+ value[prop]
2460
+ hasProp = True
2461
+ except:
2462
+ hasProp = False
2463
+ return hasProp
2464
+
2465
+ def c_includes(self, condition):
2466
+ value1 = self.getRuntimeValue(condition.value1)
2467
+ value2 = self.getRuntimeValue(condition.value2)
2468
+ return value2 in value1
2469
+
2470
+ def c_is(self, condition):
2471
+ comparison = self.program.compare(condition.value1, condition.value2)
2472
+ return comparison != 0 if condition.negate else comparison == 0
2473
+
2474
+ def c_less(self, condition):
2475
+ comparison = self.program.compare(condition.value1, condition.value2)
2476
+ return comparison >= 0 if condition.negate else comparison < 0
2153
2477
 
2154
2478
  def c_list(self, condition):
2155
2479
  comparison = type(self.getRuntimeValue(condition.value1)) is list
2156
2480
  return not comparison if condition.negate else comparison
2157
2481
 
2158
- def c_object(self, condition):
2159
- comparison = type(self.getRuntimeValue(condition.value1)) is dict
2482
+ def c_numeric(self, condition):
2483
+ comparison = type(self.getRuntimeValue(condition.value1)) is int
2160
2484
  return not comparison if condition.negate else comparison
2161
2485
 
2162
2486
  def c_none(self, condition):
@@ -2166,58 +2490,19 @@ class Core(Handler):
2166
2490
  def c_not(self, condition):
2167
2491
  return not self.getRuntimeValue(condition.value1)
2168
2492
 
2169
- def c_even(self, condition):
2170
- return self.getRuntimeValue(condition.value1) % 2 == 0
2493
+ def c_object(self, condition):
2494
+ comparison = type(self.getRuntimeValue(condition.value1)) is dict
2495
+ return not comparison if condition.negate else comparison
2171
2496
 
2172
2497
  def c_odd(self, condition):
2173
2498
  return self.getRuntimeValue(condition.value1) % 2 == 1
2174
2499
 
2175
- def c_is(self, condition):
2176
- comparison = self.program.compare(condition.value1, condition.value2)
2177
- return comparison != 0 if condition.negate else comparison == 0
2178
-
2179
- def c_greater(self, condition):
2180
- comparison = self.program.compare(condition.value1, condition.value2)
2181
- return comparison <= 0 if condition.negate else comparison > 0
2182
-
2183
- def c_less(self, condition):
2184
- comparison = self.program.compare(condition.value1, condition.value2)
2185
- return comparison >= 0 if condition.negate else comparison < 0
2186
-
2187
2500
  def c_starts(self, condition):
2188
2501
  value1 = self.getRuntimeValue(condition.value1)
2189
2502
  value2 = self.getRuntimeValue(condition.value2)
2190
2503
  return value1.startswith(value2)
2191
2504
 
2192
- def c_ends(self, condition):
2193
- value1 = self.getRuntimeValue(condition.value1)
2194
- value2 = self.getRuntimeValue(condition.value2)
2195
- return value1.endswith(value2)
2196
-
2197
- def c_includes(self, condition):
2198
- value1 = self.getRuntimeValue(condition.value1)
2199
- value2 = self.getRuntimeValue(condition.value2)
2200
- return value2 in value1
2201
-
2202
- def c_empty(self, condition):
2203
- value = self.getRuntimeValue(condition.value1)
2204
- if value == None:
2205
- comparison = True
2206
- else:
2207
- comparison = len(value) == 0
2505
+ def c_string(self, condition):
2506
+ comparison = type(self.getRuntimeValue(condition.value1)) is str
2208
2507
  return not comparison if condition.negate else comparison
2209
-
2210
- def c_exists(self, condition):
2211
- path = self.getRuntimeValue(condition.path)
2212
- return os.path.exists(path)
2213
-
2214
- def c_hasProperty(self, condition):
2215
- value = self.getRuntimeValue(condition.value1)
2216
- prop = self.getRuntimeValue(condition.property)
2217
- try:
2218
- value[prop]
2219
- hasProp = True
2220
- except:
2221
- hasProp = False
2222
- return hasProp
2223
2508
  # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx