easycoder 250103.1__py2.py3-none-any.whl → 250104.1__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of easycoder might be problematic. Click here for more details.
- easycoder/__init__.py +1 -1
- easycoder/ec_compiler.py +3 -0
- easycoder/ec_core.py +173 -19
- easycoder/ec_graphics.py +39 -11
- easycoder/ec_program.py +80 -48
- easycoder/ec_renderer.py +1 -1
- {easycoder-250103.1.dist-info → easycoder-250104.1.dist-info}/METADATA +19 -5
- easycoder-250104.1.dist-info/RECORD +19 -0
- easycoder-250103.1.dist-info/RECORD +0 -19
- {easycoder-250103.1.dist-info → easycoder-250104.1.dist-info}/LICENSE +0 -0
- {easycoder-250103.1.dist-info → easycoder-250104.1.dist-info}/WHEEL +0 -0
- {easycoder-250103.1.dist-info → easycoder-250104.1.dist-info}/entry_points.txt +0 -0
easycoder/__init__.py
CHANGED
easycoder/ec_compiler.py
CHANGED
|
@@ -128,6 +128,7 @@ class Compiler:
|
|
|
128
128
|
FatalError(self, f'Duplicate symbol name "{name}"')
|
|
129
129
|
return False
|
|
130
130
|
self.symbols[name] = self.getPC()
|
|
131
|
+
command['program'] = self.program
|
|
131
132
|
command['type'] = 'symbol'
|
|
132
133
|
command['valueHolder'] = valueHolder
|
|
133
134
|
command['name'] = name
|
|
@@ -136,6 +137,8 @@ class Compiler:
|
|
|
136
137
|
command['value'] = [None]
|
|
137
138
|
command['used'] = False
|
|
138
139
|
command['debug'] = False
|
|
140
|
+
command['import'] = None
|
|
141
|
+
command['locked'] = False
|
|
139
142
|
self.addCommand(command)
|
|
140
143
|
return True
|
|
141
144
|
|
easycoder/ec_core.py
CHANGED
|
@@ -367,8 +367,7 @@ class Core(Handler):
|
|
|
367
367
|
return True
|
|
368
368
|
|
|
369
369
|
def r_exit(self, command):
|
|
370
|
-
|
|
371
|
-
return 0
|
|
370
|
+
return -1
|
|
372
371
|
|
|
373
372
|
# Declare a file variable
|
|
374
373
|
def k_file(self, command):
|
|
@@ -462,7 +461,7 @@ class Core(Handler):
|
|
|
462
461
|
else:
|
|
463
462
|
RuntimeError(self.program, f'Error: {errorReason}')
|
|
464
463
|
retval['content'] = response.text
|
|
465
|
-
self.program.putSymbolValue(target, retval)
|
|
464
|
+
self.program.putSymbolValue(target, retval)
|
|
466
465
|
return self.nextPC()
|
|
467
466
|
|
|
468
467
|
# Go to a label
|
|
@@ -553,15 +552,45 @@ class Core(Handler):
|
|
|
553
552
|
self.program.pc += 1
|
|
554
553
|
return self.program.pc
|
|
555
554
|
|
|
556
|
-
# Import
|
|
557
|
-
# import {class} from {source}
|
|
555
|
+
# Import one or more variables
|
|
558
556
|
def k_import(self, command):
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
self.
|
|
563
|
-
|
|
564
|
-
|
|
557
|
+
imports = []
|
|
558
|
+
while True:
|
|
559
|
+
keyword = self.nextToken()
|
|
560
|
+
name = self.nextToken()
|
|
561
|
+
item = [keyword, name]
|
|
562
|
+
imports.append(item)
|
|
563
|
+
self.symbols[name] = self.getPC()
|
|
564
|
+
variable = {}
|
|
565
|
+
variable['domain'] = None
|
|
566
|
+
variable['name'] = name
|
|
567
|
+
variable['keyword'] = keyword
|
|
568
|
+
variable['import'] = None
|
|
569
|
+
self.addCommand(variable)
|
|
570
|
+
if self.peek() != 'and':
|
|
571
|
+
break
|
|
572
|
+
self.nextToken()
|
|
573
|
+
command['imports'] = json.dumps(imports)
|
|
574
|
+
self.add(command)
|
|
575
|
+
return True
|
|
576
|
+
|
|
577
|
+
def r_import(self, command):
|
|
578
|
+
exports = self.program.exports
|
|
579
|
+
imports = json.loads(command['imports'])
|
|
580
|
+
if len(imports) < len(exports):
|
|
581
|
+
RuntimeError(self.program, 'Too few imports')
|
|
582
|
+
elif len(imports) > len(exports):
|
|
583
|
+
RuntimeError(self.program, 'Too many imports')
|
|
584
|
+
for n in range(0, len(imports)):
|
|
585
|
+
exportRecord = exports[n]
|
|
586
|
+
exportKeyword = exportRecord['keyword']
|
|
587
|
+
name = imports[n][1]
|
|
588
|
+
symbolRecord = self.program.getSymbolRecord(name)
|
|
589
|
+
symbolKeyword = symbolRecord['keyword']
|
|
590
|
+
if symbolKeyword != exportKeyword:
|
|
591
|
+
RuntimeError(self.program, f'Import {n} ({symbolKeyword}) does not match export {n} ({exportKeyword})')
|
|
592
|
+
symbolRecord['import'] = exportRecord
|
|
593
|
+
return self.nextPC()
|
|
565
594
|
|
|
566
595
|
# Increment a variable
|
|
567
596
|
def k_increment(self, command):
|
|
@@ -646,6 +675,60 @@ class Core(Handler):
|
|
|
646
675
|
self.putSymbolValue(symbolRecord, value)
|
|
647
676
|
return self.nextPC()
|
|
648
677
|
|
|
678
|
+
# 1 Load a plugin. This is done at compile time.
|
|
679
|
+
# 2 Load text from a file
|
|
680
|
+
def k_load(self, command):
|
|
681
|
+
self.nextToken()
|
|
682
|
+
if self.tokenIs('plugin'):
|
|
683
|
+
clazz = self.nextToken()
|
|
684
|
+
if self.nextIs('from'):
|
|
685
|
+
source = self.nextToken()
|
|
686
|
+
self.program.importPlugin(f'{source}:{clazz}')
|
|
687
|
+
return True
|
|
688
|
+
elif self.isSymbol():
|
|
689
|
+
command['target'] = self.getToken()
|
|
690
|
+
if self.nextIs('from'):
|
|
691
|
+
command['file'] = self.nextValue()
|
|
692
|
+
self.add(command)
|
|
693
|
+
return True
|
|
694
|
+
return False
|
|
695
|
+
|
|
696
|
+
def r_load(self, command):
|
|
697
|
+
print(command)
|
|
698
|
+
target = self.getVariable(command['target'])
|
|
699
|
+
print(target)
|
|
700
|
+
file = self.getRuntimeValue(command['file'])
|
|
701
|
+
print(file)
|
|
702
|
+
f = open(file, 'r')
|
|
703
|
+
content = f.read()
|
|
704
|
+
f.close()
|
|
705
|
+
value = {}
|
|
706
|
+
value['type'] = 'text'
|
|
707
|
+
value['content'] = content
|
|
708
|
+
self.putSymbolValue(target, value)
|
|
709
|
+
return self.nextPC()
|
|
710
|
+
|
|
711
|
+
# Lock a variable
|
|
712
|
+
def k_lock(self, command):
|
|
713
|
+
if self.nextIsSymbol():
|
|
714
|
+
symbolRecord = self.getSymbolRecord()
|
|
715
|
+
command['target'] = symbolRecord['name']
|
|
716
|
+
self.add(command)
|
|
717
|
+
return True
|
|
718
|
+
return False
|
|
719
|
+
|
|
720
|
+
def r_lock(self, command):
|
|
721
|
+
target = self.getVariable(command['target'])
|
|
722
|
+
target['locked'] = True
|
|
723
|
+
return self.nextPC()
|
|
724
|
+
|
|
725
|
+
# Declare a module variable
|
|
726
|
+
def k_module(self, command):
|
|
727
|
+
return self.compileVariable(command)
|
|
728
|
+
|
|
729
|
+
def r_module(self, command):
|
|
730
|
+
return self.nextPC()
|
|
731
|
+
|
|
649
732
|
# Arithmetic multiply
|
|
650
733
|
# multiply {variable} by {value}[ giving {variable}]}
|
|
651
734
|
def k_multiply(self, command):
|
|
@@ -1008,6 +1091,16 @@ class Core(Handler):
|
|
|
1008
1091
|
self.putSymbolValue(templateRecord, value)
|
|
1009
1092
|
return self.nextPC()
|
|
1010
1093
|
|
|
1094
|
+
# Release the parent script
|
|
1095
|
+
def k_release(self, command):
|
|
1096
|
+
if self.nextIs('parent'):
|
|
1097
|
+
self.add(command)
|
|
1098
|
+
return True
|
|
1099
|
+
|
|
1100
|
+
def r_release(self, command):
|
|
1101
|
+
self.program.releaseParent()
|
|
1102
|
+
return self.nextPC()
|
|
1103
|
+
|
|
1011
1104
|
# Return from subroutine
|
|
1012
1105
|
def k_return(self, command):
|
|
1013
1106
|
self.add(command)
|
|
@@ -1016,11 +1109,65 @@ class Core(Handler):
|
|
|
1016
1109
|
def r_return(self, command):
|
|
1017
1110
|
return self.stack.pop()
|
|
1018
1111
|
|
|
1112
|
+
# Compile and run a script
|
|
1113
|
+
def k_run(self, command):
|
|
1114
|
+
if self.nextIsSymbol():
|
|
1115
|
+
record = self.getSymbolRecord()
|
|
1116
|
+
if record['keyword'] == 'module':
|
|
1117
|
+
command['target'] = record['name']
|
|
1118
|
+
if self.nextIs('as'):
|
|
1119
|
+
command['path'] = self.nextValue()
|
|
1120
|
+
exports = []
|
|
1121
|
+
if self.nextIs('with'):
|
|
1122
|
+
while True:
|
|
1123
|
+
name = self.nextToken()
|
|
1124
|
+
record = self.getSymbolRecord()
|
|
1125
|
+
exports.append(name)
|
|
1126
|
+
if self.peek() != 'and':
|
|
1127
|
+
break
|
|
1128
|
+
self.nextToken()
|
|
1129
|
+
command['exports'] = json.dumps(exports)
|
|
1130
|
+
self.add(command)
|
|
1131
|
+
return True
|
|
1132
|
+
return False
|
|
1133
|
+
|
|
1134
|
+
def r_run(self, command):
|
|
1135
|
+
target = self.getVariable(command['target'])
|
|
1136
|
+
path = self.getRuntimeValue(command['path'])
|
|
1137
|
+
exports = json.loads(command['exports'])
|
|
1138
|
+
for n in range(0, len(exports)):
|
|
1139
|
+
exports[n] = self.getVariable(exports[n])
|
|
1140
|
+
target['path'] = path
|
|
1141
|
+
parent = Object()
|
|
1142
|
+
parent.program = self.program
|
|
1143
|
+
parent.pc = self.nextPC()
|
|
1144
|
+
parent.waiting = True
|
|
1145
|
+
p = self.program.__class__
|
|
1146
|
+
p(path).start(parent, exports)
|
|
1147
|
+
return 0
|
|
1148
|
+
|
|
1019
1149
|
# Provide a name for the script
|
|
1020
1150
|
def k_script(self, command):
|
|
1021
1151
|
self.program.name = self.nextToken()
|
|
1022
1152
|
return True
|
|
1023
1153
|
|
|
1154
|
+
# Save a value to a file
|
|
1155
|
+
def k_save(self, command):
|
|
1156
|
+
command['content'] = self.nextValue()
|
|
1157
|
+
if self.nextIs('to'):
|
|
1158
|
+
command['file'] = self.nextValue()
|
|
1159
|
+
self.add(command)
|
|
1160
|
+
return True
|
|
1161
|
+
return False
|
|
1162
|
+
|
|
1163
|
+
def r_save(self, command):
|
|
1164
|
+
content = self.getRuntimeValue(command['content'])
|
|
1165
|
+
file = self.getRuntimeValue(command['file'])
|
|
1166
|
+
f = open(file, 'w')
|
|
1167
|
+
f.write(content)
|
|
1168
|
+
f.close()
|
|
1169
|
+
return self.nextPC()
|
|
1170
|
+
|
|
1024
1171
|
# Set a value
|
|
1025
1172
|
# set {variable}
|
|
1026
1173
|
# set the elements of {variable} to {value}
|
|
@@ -1325,6 +1472,20 @@ class Core(Handler):
|
|
|
1325
1472
|
fileRecord['file'].truncate()
|
|
1326
1473
|
return self.nextPC()
|
|
1327
1474
|
|
|
1475
|
+
# Unlock a variable
|
|
1476
|
+
def k_unlock(self, command):
|
|
1477
|
+
if self.nextIsSymbol():
|
|
1478
|
+
symbolRecord = self.getSymbolRecord()
|
|
1479
|
+
command['target'] = symbolRecord['name']
|
|
1480
|
+
self.add(command)
|
|
1481
|
+
return True
|
|
1482
|
+
return False
|
|
1483
|
+
|
|
1484
|
+
def r_unlock(self, command):
|
|
1485
|
+
target = self.getVariable(command['target'])
|
|
1486
|
+
target['locked'] = False
|
|
1487
|
+
return self.nextPC()
|
|
1488
|
+
|
|
1328
1489
|
# Declare a general-purpose variable
|
|
1329
1490
|
def k_variable(self, command):
|
|
1330
1491
|
return self.compileVariable(command, True)
|
|
@@ -2021,19 +2182,12 @@ class Core(Handler):
|
|
|
2021
2182
|
value['content'] = json.dumps(item)
|
|
2022
2183
|
return value
|
|
2023
2184
|
|
|
2185
|
+
# This is used by the expression evaluator to get the value of a symbol
|
|
2024
2186
|
def v_symbol(self, symbolRecord):
|
|
2025
2187
|
result = {}
|
|
2026
2188
|
if symbolRecord['keyword'] == 'variable':
|
|
2027
2189
|
symbolValue = self.getSymbolValue(symbolRecord)
|
|
2028
2190
|
return symbolValue
|
|
2029
|
-
# if symbolValue == None:
|
|
2030
|
-
# return None
|
|
2031
|
-
# result['type'] = symbolValue['type']
|
|
2032
|
-
# content = symbolValue['content']
|
|
2033
|
-
# if content == None:
|
|
2034
|
-
# return ''
|
|
2035
|
-
# result['content'] = content
|
|
2036
|
-
# return result
|
|
2037
2191
|
else:
|
|
2038
2192
|
return None
|
|
2039
2193
|
|
easycoder/ec_graphics.py
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import sys, threading, json
|
|
1
2
|
from .ec_classes import FatalError, RuntimeError, Object
|
|
2
3
|
from .ec_handler import Handler
|
|
3
4
|
from .ec_screenspec import ScreenSpec
|
|
4
5
|
from .ec_renderer import Renderer
|
|
6
|
+
from .ec_program import flush
|
|
5
7
|
|
|
6
8
|
class Graphics(Handler):
|
|
7
9
|
|
|
@@ -173,7 +175,7 @@ class Graphics(Handler):
|
|
|
173
175
|
if type == 'window':
|
|
174
176
|
self.windowSpec = Object()
|
|
175
177
|
self.windowSpec.title = command['title']['content']
|
|
176
|
-
self.windowSpec.flush =
|
|
178
|
+
self.windowSpec.flush = flush
|
|
177
179
|
self.windowSpec.finish = self.program.finish
|
|
178
180
|
self.windowSpec.pos = (self.getRuntimeValue(command['pos'][0]), self.getRuntimeValue(command['pos'][1]))
|
|
179
181
|
self.windowSpec.size = (self.getRuntimeValue(command['size'][0]), self.getRuntimeValue(command['size'][1]))
|
|
@@ -219,7 +221,7 @@ class Graphics(Handler):
|
|
|
219
221
|
if self.nextIsSymbol():
|
|
220
222
|
record = self.getSymbolRecord()
|
|
221
223
|
type = record['keyword']
|
|
222
|
-
if type
|
|
224
|
+
if self.isGraphicType(type):
|
|
223
225
|
command['target'] = record['id']
|
|
224
226
|
token = self.nextToken()
|
|
225
227
|
if token == 'to':
|
|
@@ -283,7 +285,7 @@ class Graphics(Handler):
|
|
|
283
285
|
if command['type'] == 'tap':
|
|
284
286
|
record = self.getVariable(command['target'])
|
|
285
287
|
keyword = record['keyword']
|
|
286
|
-
if keyword
|
|
288
|
+
if self.isGraphicType(keyword):
|
|
287
289
|
id = record['value'][record['index']]['content']
|
|
288
290
|
self.ui.setOnClick(id, lambda: self.run(pc))
|
|
289
291
|
else:
|
|
@@ -296,12 +298,6 @@ class Graphics(Handler):
|
|
|
296
298
|
def r_rectangle(self, command):
|
|
297
299
|
return self.nextPC()
|
|
298
300
|
|
|
299
|
-
def k_text(self, command):
|
|
300
|
-
return self.compileVariable(command)
|
|
301
|
-
|
|
302
|
-
def r_text(self, command):
|
|
303
|
-
return self.nextPC()
|
|
304
|
-
|
|
305
301
|
# render {spec}
|
|
306
302
|
def k_render(self, command):
|
|
307
303
|
command['spec'] = self.nextValue()
|
|
@@ -332,6 +328,7 @@ class Graphics(Handler):
|
|
|
332
328
|
def r_run(self, command):
|
|
333
329
|
self.renderer = Renderer()
|
|
334
330
|
self.renderer.init(self.windowSpec)
|
|
331
|
+
self.ui = self.renderer.getUI()
|
|
335
332
|
self.program.setExternalControl()
|
|
336
333
|
self.program.run(self.nextPC())
|
|
337
334
|
self.renderer.run()
|
|
@@ -343,7 +340,7 @@ class Graphics(Handler):
|
|
|
343
340
|
if self.nextIs('of'):
|
|
344
341
|
if self.nextIsSymbol():
|
|
345
342
|
record = self.getSymbolRecord()
|
|
346
|
-
if record['keyword']
|
|
343
|
+
if self.isGraphicType(record['keyword']):
|
|
347
344
|
command['target'] = record['name']
|
|
348
345
|
if self.nextIs('to'):
|
|
349
346
|
command['value'] = self.nextValue()
|
|
@@ -363,6 +360,12 @@ class Graphics(Handler):
|
|
|
363
360
|
self.ui.setAttribute(id, attribute, value)
|
|
364
361
|
return self.nextPC()
|
|
365
362
|
|
|
363
|
+
def k_text(self, command):
|
|
364
|
+
return self.compileVariable(command)
|
|
365
|
+
|
|
366
|
+
def r_text(self, command):
|
|
367
|
+
return self.nextPC()
|
|
368
|
+
|
|
366
369
|
#############################################################################
|
|
367
370
|
# Modify a value or leave it unchanged.
|
|
368
371
|
def modifyValue(self, value):
|
|
@@ -373,6 +376,16 @@ class Graphics(Handler):
|
|
|
373
376
|
def compileValue(self):
|
|
374
377
|
value = {}
|
|
375
378
|
value['domain'] = self.getName()
|
|
379
|
+
token = self.getToken()
|
|
380
|
+
if self.isSymbol():
|
|
381
|
+
value['name'] = token
|
|
382
|
+
symbolRecord = self.getSymbolRecord()
|
|
383
|
+
keyword = symbolRecord['keyword']
|
|
384
|
+
if keyword == 'graphic':
|
|
385
|
+
value['type'] = 'symbol'
|
|
386
|
+
return value
|
|
387
|
+
return None
|
|
388
|
+
|
|
376
389
|
if self.tokenIs('the'):
|
|
377
390
|
self.nextToken()
|
|
378
391
|
kwd = self.getToken()
|
|
@@ -382,7 +395,7 @@ class Graphics(Handler):
|
|
|
382
395
|
if self.nextIs('of'):
|
|
383
396
|
if self.nextIsSymbol():
|
|
384
397
|
record = self.getSymbolRecord()
|
|
385
|
-
if record['keyword']
|
|
398
|
+
if self.isGraphicType(record['keyword']):
|
|
386
399
|
value['attribute'] = attribute
|
|
387
400
|
value['target'] = record['name']
|
|
388
401
|
return value
|
|
@@ -393,6 +406,12 @@ class Graphics(Handler):
|
|
|
393
406
|
return value
|
|
394
407
|
return None
|
|
395
408
|
|
|
409
|
+
#############################################################################
|
|
410
|
+
# Test if a graphic type
|
|
411
|
+
|
|
412
|
+
def isGraphicType(self, type):
|
|
413
|
+
return type in ['ellipse', 'rectangle', 'text', 'image']
|
|
414
|
+
|
|
396
415
|
#############################################################################
|
|
397
416
|
# Value handlers
|
|
398
417
|
|
|
@@ -409,6 +428,15 @@ class Graphics(Handler):
|
|
|
409
428
|
except Exception as e:
|
|
410
429
|
RuntimeError(self.program, e)
|
|
411
430
|
|
|
431
|
+
# This is used by the expression evaluator to get the value of a symbol
|
|
432
|
+
def v_symbol(self, symbolRecord):
|
|
433
|
+
result = {}
|
|
434
|
+
if symbolRecord['keyword'] == 'graphic':
|
|
435
|
+
symbolValue = self.getSymbolValue(symbolRecord)
|
|
436
|
+
return symbolValue
|
|
437
|
+
else:
|
|
438
|
+
return None
|
|
439
|
+
|
|
412
440
|
def v_window(self, v):
|
|
413
441
|
try:
|
|
414
442
|
attribute = v['attribute']
|
easycoder/ec_program.py
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import time, json, sys
|
|
2
2
|
from copy import deepcopy
|
|
3
3
|
from collections import deque
|
|
4
|
-
from .ec_classes import Script, Token, FatalError, RuntimeError
|
|
4
|
+
from .ec_classes import Script, Token, FatalError, RuntimeError, Object
|
|
5
5
|
from .ec_compiler import Compiler
|
|
6
6
|
from .ec_core import Core
|
|
7
7
|
import importlib
|
|
8
8
|
from importlib.metadata import version
|
|
9
9
|
|
|
10
|
+
queue = deque()
|
|
11
|
+
|
|
12
|
+
# Flush the queue
|
|
13
|
+
def flush():
|
|
14
|
+
global queue
|
|
15
|
+
while len(queue):
|
|
16
|
+
item = queue.popleft()
|
|
17
|
+
item.program.flush(item.pc)
|
|
18
|
+
|
|
10
19
|
class Program:
|
|
11
20
|
|
|
12
21
|
def __init__(self, argv):
|
|
@@ -15,7 +24,7 @@ class Program:
|
|
|
15
24
|
print('No script supplied')
|
|
16
25
|
exit()
|
|
17
26
|
self.classes=[Core]
|
|
18
|
-
scriptName = argv
|
|
27
|
+
scriptName = argv
|
|
19
28
|
if scriptName.endswith('.ecg'):
|
|
20
29
|
from .ec_graphics import Graphics
|
|
21
30
|
self.classes.append(Graphics)
|
|
@@ -23,6 +32,7 @@ class Program:
|
|
|
23
32
|
f = open(scriptName, 'r')
|
|
24
33
|
source = f.read()
|
|
25
34
|
f.close()
|
|
35
|
+
self.argv = argv
|
|
26
36
|
self.domains = []
|
|
27
37
|
self.domainIndex = {}
|
|
28
38
|
self.name = '<anon>'
|
|
@@ -37,11 +47,12 @@ class Program:
|
|
|
37
47
|
self.value = self.compiler.value
|
|
38
48
|
self.condition = self.compiler.condition
|
|
39
49
|
self.processClasses()
|
|
40
|
-
self.queue = deque()
|
|
41
50
|
self.externalControl = False
|
|
42
|
-
self.
|
|
51
|
+
self.finished = False
|
|
43
52
|
|
|
44
|
-
def start(self):
|
|
53
|
+
def start(self, parent=None, exports=[]):
|
|
54
|
+
self.parent = parent
|
|
55
|
+
self.exports = exports
|
|
45
56
|
startCompile = time.time()
|
|
46
57
|
self.tokenise(self.script)
|
|
47
58
|
if self.compiler.compileFrom(0, []):
|
|
@@ -98,11 +109,11 @@ class Program:
|
|
|
98
109
|
def getSymbolRecord(self, name):
|
|
99
110
|
try:
|
|
100
111
|
target = self.code[self.symbols[name]]
|
|
112
|
+
if target['import'] != None:
|
|
113
|
+
target = target['import']
|
|
114
|
+
return target
|
|
101
115
|
except:
|
|
102
|
-
RuntimeError(self
|
|
103
|
-
return None
|
|
104
|
-
|
|
105
|
-
return target
|
|
116
|
+
RuntimeError(self, f'Unknown symbol \'{name}\'')
|
|
106
117
|
|
|
107
118
|
def doValue(self, value):
|
|
108
119
|
if value == None:
|
|
@@ -184,6 +195,8 @@ class Program:
|
|
|
184
195
|
return copy
|
|
185
196
|
|
|
186
197
|
def putSymbolValue(self, symbolRecord, value):
|
|
198
|
+
if symbolRecord['locked']:
|
|
199
|
+
RuntimeError(self, f'Symbol \'{symbolRecord['name']}\' is locked')
|
|
187
200
|
if symbolRecord['value'] == None or symbolRecord['value'] == []:
|
|
188
201
|
symbolRecord['value'] = [value]
|
|
189
202
|
else:
|
|
@@ -192,11 +205,11 @@ class Program:
|
|
|
192
205
|
index = 0
|
|
193
206
|
symbolRecord['value'][index] = value
|
|
194
207
|
|
|
195
|
-
def encode(self, value
|
|
196
|
-
return value
|
|
208
|
+
def encode(self, value):
|
|
209
|
+
return value
|
|
197
210
|
|
|
198
|
-
def decode(self, value
|
|
199
|
-
return value
|
|
211
|
+
def decode(self, value):
|
|
212
|
+
return value
|
|
200
213
|
|
|
201
214
|
# Tokenise the script
|
|
202
215
|
def tokenise(self, script):
|
|
@@ -256,48 +269,60 @@ class Program:
|
|
|
256
269
|
token = ''
|
|
257
270
|
return
|
|
258
271
|
|
|
259
|
-
def
|
|
260
|
-
self.
|
|
272
|
+
def releaseParent(self):
|
|
273
|
+
if self.parent.waiting and self.parent.program.running:
|
|
274
|
+
self.parent.waiting = False
|
|
275
|
+
self.parent.program.run(self.parent.pc)
|
|
261
276
|
|
|
262
277
|
# Flush the queue
|
|
263
|
-
def flush(self):
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
278
|
+
def flush(self, pc):
|
|
279
|
+
global queue
|
|
280
|
+
self.running = True
|
|
281
|
+
self.pc = pc
|
|
282
|
+
while True:
|
|
283
|
+
command = self.code[self.pc]
|
|
284
|
+
domainName = command['domain']
|
|
285
|
+
if domainName == None:
|
|
286
|
+
self.pc += 1
|
|
287
|
+
else:
|
|
288
|
+
keyword = command['keyword']
|
|
289
|
+
if self.debugStep and command['debug']:
|
|
290
|
+
lino = command['lino'] + 1
|
|
291
|
+
line = self.script.lines[command['lino']].strip()
|
|
292
|
+
print(f'{self.name}: Line {lino}: {domainName}:{keyword}: {line}')
|
|
293
|
+
domain = self.domainIndex[domainName]
|
|
294
|
+
handler = domain.runHandler(keyword)
|
|
295
|
+
if handler:
|
|
296
|
+
command = self.code[self.pc]
|
|
297
|
+
command['program'] = self
|
|
298
|
+
self.pc = handler(command)
|
|
299
|
+
# Deal with 'exit'
|
|
300
|
+
if self.pc == -1:
|
|
301
|
+
queue = deque()
|
|
302
|
+
self.running = False
|
|
303
|
+
if self.parent != None:
|
|
304
|
+
self.releaseParent()
|
|
305
|
+
sys.exit()
|
|
306
|
+
elif self.pc == None or self.pc == 0 or self.pc >= len(self.code):
|
|
307
|
+
break
|
|
293
308
|
|
|
294
309
|
# Run the script
|
|
295
310
|
def run(self, pc):
|
|
296
|
-
|
|
297
|
-
|
|
311
|
+
global queue
|
|
312
|
+
length = len(queue)
|
|
313
|
+
item = Object()
|
|
314
|
+
item.program = self
|
|
315
|
+
item.pc = pc
|
|
316
|
+
queue.append(item)
|
|
298
317
|
if not self.externalControl:
|
|
299
318
|
if length == 0:
|
|
300
|
-
return
|
|
319
|
+
return flush()
|
|
320
|
+
|
|
321
|
+
def finish(self):
|
|
322
|
+
self.running = False
|
|
323
|
+
|
|
324
|
+
def setExternalControl(self):
|
|
325
|
+
self.externalControl = True
|
|
301
326
|
|
|
302
327
|
def nonNumericValueError(self):
|
|
303
328
|
FatalError(self.compiler, 'Non-numeric value')
|
|
@@ -343,3 +368,10 @@ class Program:
|
|
|
343
368
|
if v1 < v2:
|
|
344
369
|
return -1
|
|
345
370
|
return 0
|
|
371
|
+
|
|
372
|
+
# This is the program launcher
|
|
373
|
+
def Main():
|
|
374
|
+
if (len(sys.argv) > 1):
|
|
375
|
+
Program(sys.argv[1]).start()
|
|
376
|
+
else:
|
|
377
|
+
print('Syntax: easycoder <scriptname> [plugins]')
|
easycoder/ec_renderer.py
CHANGED
|
@@ -232,10 +232,10 @@ class Renderer(App):
|
|
|
232
232
|
|
|
233
233
|
def build(self):
|
|
234
234
|
Clock.schedule_interval(self.flushQueue, 0.01)
|
|
235
|
-
self.ui = UI()
|
|
236
235
|
return self.ui
|
|
237
236
|
|
|
238
237
|
def init(self, spec):
|
|
238
|
+
self.ui = UI()
|
|
239
239
|
self.title = spec.title
|
|
240
240
|
self.flush = spec.flush
|
|
241
241
|
Window.size = spec.size
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: easycoder
|
|
3
|
-
Version:
|
|
3
|
+
Version: 250104.1
|
|
4
4
|
Summary: Rapid scripting in English
|
|
5
5
|
Keywords: compiler,scripting,prototyping,programming,coding,python,low code,hypertalk,computer language,learn to code
|
|
6
6
|
Author-email: Graham Trott <gtanyware@gmail.com>
|
|
@@ -10,12 +10,13 @@ Requires-Dist: pytz
|
|
|
10
10
|
Project-URL: Home, https://github.com/easycoder/easycoder-py
|
|
11
11
|
|
|
12
12
|
# Introduction
|
|
13
|
-
**_EasyCoder_** is a high-level English-like scripting language suited for prototyping and rapid testing of ideas. It operates on the command line and a graphics module is under construction. This version of the language is written in Python and
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
**_EasyCoder_** is a high-level English-like scripting language suited for prototyping and rapid testing of ideas. It operates on the command line and a graphics module is under construction. This version of the language is written in Python and it acts as a fairly thin wrapper around Python functions, giving fast compilation and good runtime performance for general applications.
|
|
14
|
+
<hr>
|
|
15
|
+
For the JavaScript version of **_EasyCoder_**, which provides a full set of graphical features to run in a browser, please visit
|
|
16
16
|
|
|
17
17
|
Repository: [https://github.com/easycoder/easycoder.github.io](https://github.com/easycoder/easycoder.github.io)
|
|
18
18
|
Website: [https://easycoder.github.io](https://easycoder.github.io)
|
|
19
|
+
<hr>
|
|
19
20
|
|
|
20
21
|
## Quick Start
|
|
21
22
|
Install **_EasyCoder_** in your Python environment:
|
|
@@ -28,7 +29,7 @@ print `Hello, world!`
|
|
|
28
29
|
```
|
|
29
30
|
This is traditionally the first program to be written in virtually any language. To run it, use `easycoder hello.ecs`.
|
|
30
31
|
|
|
31
|
-
The output will look like this:
|
|
32
|
+
The output will look like this (the version number will differ):
|
|
32
33
|
|
|
33
34
|
```
|
|
34
35
|
EasyCoder version 250101.1
|
|
@@ -72,6 +73,19 @@ A couple of demo graphical scripts are included in the `scripts` directory:
|
|
|
72
73
|
|
|
73
74
|
**_EasyCoder_** graphics are handled by a library module, `ec_renderer` that can be used outside of the **_EasyCoder_** environment, in other Python programs.
|
|
74
75
|
|
|
76
|
+
## Significant features
|
|
77
|
+
|
|
78
|
+
- English-like syntax based on vocabulary rather than structure. Scripts can be read as English
|
|
79
|
+
- Comprehensive feature set
|
|
80
|
+
- Runs directly from source scripts, using a fast compiler to create efficient intermediate runtime code that is run immediately
|
|
81
|
+
- Low memory requirements
|
|
82
|
+
- Minimim dependency on other 3rd-party packages
|
|
83
|
+
- Built-in co-operative multitasking
|
|
84
|
+
- Dynamic loading of scripts on demand
|
|
85
|
+
- The language can be extended seamlessly using plugin function modules
|
|
86
|
+
- Plays well with any Python code
|
|
87
|
+
- Fully Open Source
|
|
88
|
+
|
|
75
89
|
## Programming reference
|
|
76
90
|
|
|
77
91
|
**_EasyCoder_** comprises a set of modules to handle tokenisation, compilation and runtime control. Syntax and grammar are defined by [packages](doc/README.md), of which there are currently two; the [core](doc/core/README.md) package, which implements a comprehensive set of command-line programming features, and and the [graphics](doc/graphics/README.md) package, which adds graphical features in a windowing environment.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
easycoder/README.md,sha256=PYqOc_SkIGiFbyCNs90y7JqoqWe4aO1xYIW-6bOnFKU,573
|
|
2
|
+
easycoder/__init__.py,sha256=a3GF7mJ6MDX_VMS0m8eVDkxAksYnIfCeb4Rw6KgV2ys,283
|
|
3
|
+
easycoder/ec.py,sha256=Nj5PRl8GsKjfGJKq0FOM1a7FeK3cN68CoIFg8lswQEg,221
|
|
4
|
+
easycoder/ec_classes.py,sha256=xnWBNak8oKydkFoxHLlq9wo3lIsB3aMnTDrqbtCfoWo,1512
|
|
5
|
+
easycoder/ec_compiler.py,sha256=_xBh2L47mz_WOMYdruMYSHyyz2wfh7Hf28q559AWVSU,4781
|
|
6
|
+
easycoder/ec_condition.py,sha256=WSbONo4zs2sX1icOVpscZDFSCAEFmTsquoc2RGcLx_k,763
|
|
7
|
+
easycoder/ec_core.py,sha256=VtsjZ0r3OKxgF-nnQoRJItbjhSHRUso84SwSz3EubG4,84152
|
|
8
|
+
easycoder/ec_graphics.py,sha256=JLd5w1_RYVmSVmdWhxltMGfdQuKHroFl0HG7MCZ7E2E,16431
|
|
9
|
+
easycoder/ec_handler.py,sha256=IJvxcrJJSR53d6DS_8H5qPHKhp9y5-GV4WXAjhZxu_o,2250
|
|
10
|
+
easycoder/ec_program.py,sha256=4I7tICiY9zkigA15-K8zdHkH-H-UOr4W1liy0sfMtu8,9440
|
|
11
|
+
easycoder/ec_renderer.py,sha256=1zdIXqk-Sfnu3ErU193iem0Y-r6GeVc8D1HsTB_G2bU,7981
|
|
12
|
+
easycoder/ec_screenspec.py,sha256=TeXgccfYoE--r7Rf9t9drV1V3fU-p-iBnZwtjHzIh8M,2524
|
|
13
|
+
easycoder/ec_timestamp.py,sha256=_3QFJPzIWZ9Rzk3SQOQJ-gwmvB07pg78k23SPntoZtY,288
|
|
14
|
+
easycoder/ec_value.py,sha256=XIBtGhcCgh1abrzAn-Wy4l_xH_3cTWakMVIiSlBAZjM,2386
|
|
15
|
+
easycoder-250104.1.dist-info/entry_points.txt,sha256=JXAZbenl0TnsIft2FcGJbJ-4qoztVu2FuT8PFmWFexM,44
|
|
16
|
+
easycoder-250104.1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
17
|
+
easycoder-250104.1.dist-info/WHEEL,sha256=ssQ84EZ5gH1pCOujd3iW7HClo_O_aDaClUbX4B8bjKY,100
|
|
18
|
+
easycoder-250104.1.dist-info/METADATA,sha256=MsBtZS8mH5qcs5vLAB4PSdnwIF51g7q0uxiKhCRQgo8,5817
|
|
19
|
+
easycoder-250104.1.dist-info/RECORD,,
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
easycoder/README.md,sha256=PYqOc_SkIGiFbyCNs90y7JqoqWe4aO1xYIW-6bOnFKU,573
|
|
2
|
-
easycoder/__init__.py,sha256=5hieaJUWovLn09r1Tf2I2hBLjfYGXMKuBb6usyd9sYc,283
|
|
3
|
-
easycoder/ec.py,sha256=Nj5PRl8GsKjfGJKq0FOM1a7FeK3cN68CoIFg8lswQEg,221
|
|
4
|
-
easycoder/ec_classes.py,sha256=xnWBNak8oKydkFoxHLlq9wo3lIsB3aMnTDrqbtCfoWo,1512
|
|
5
|
-
easycoder/ec_compiler.py,sha256=2r6Nk7px9UMYqIpYc6dAbYOAFu-CoWPy-iqlsed49Lo,4690
|
|
6
|
-
easycoder/ec_condition.py,sha256=WSbONo4zs2sX1icOVpscZDFSCAEFmTsquoc2RGcLx_k,763
|
|
7
|
-
easycoder/ec_core.py,sha256=1rYUGd5EXpjJkfYnnvJNjvMD_JfTGZRMEV0lLbYrzAU,78939
|
|
8
|
-
easycoder/ec_graphics.py,sha256=o70BdQ-Y3uIo5nheQYwJUmM3gYVerKD9_5arQ8JTP-Y,15556
|
|
9
|
-
easycoder/ec_handler.py,sha256=IJvxcrJJSR53d6DS_8H5qPHKhp9y5-GV4WXAjhZxu_o,2250
|
|
10
|
-
easycoder/ec_program.py,sha256=TUKQo56vURtx_UO7avIJZhz0EeOe2lNxQQz8EOOnCZ4,8685
|
|
11
|
-
easycoder/ec_renderer.py,sha256=ejVFemHGuFBwGA__6VfZQZeZMnw4Ilvf_y9I34k04LM,7981
|
|
12
|
-
easycoder/ec_screenspec.py,sha256=TeXgccfYoE--r7Rf9t9drV1V3fU-p-iBnZwtjHzIh8M,2524
|
|
13
|
-
easycoder/ec_timestamp.py,sha256=_3QFJPzIWZ9Rzk3SQOQJ-gwmvB07pg78k23SPntoZtY,288
|
|
14
|
-
easycoder/ec_value.py,sha256=XIBtGhcCgh1abrzAn-Wy4l_xH_3cTWakMVIiSlBAZjM,2386
|
|
15
|
-
easycoder-250103.1.dist-info/entry_points.txt,sha256=JXAZbenl0TnsIft2FcGJbJ-4qoztVu2FuT8PFmWFexM,44
|
|
16
|
-
easycoder-250103.1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
17
|
-
easycoder-250103.1.dist-info/WHEEL,sha256=ssQ84EZ5gH1pCOujd3iW7HClo_O_aDaClUbX4B8bjKY,100
|
|
18
|
-
easycoder-250103.1.dist-info/METADATA,sha256=6X8NoMG3Px2cLNDqWYxoMfki71O06qYk8qILNM_49VI,5178
|
|
19
|
-
easycoder-250103.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|