easycoder 250103.2__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 +135 -13
- easycoder/ec_graphics.py +39 -11
- easycoder/ec_program.py +80 -48
- easycoder/ec_renderer.py +1 -1
- {easycoder-250103.2.dist-info → easycoder-250104.1.dist-info}/METADATA +19 -5
- easycoder-250104.1.dist-info/RECORD +19 -0
- easycoder-250103.2.dist-info/RECORD +0 -19
- {easycoder-250103.2.dist-info → easycoder-250104.1.dist-info}/LICENSE +0 -0
- {easycoder-250103.2.dist-info → easycoder-250104.1.dist-info}/WHEEL +0 -0
- {easycoder-250103.2.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,9 +675,17 @@ class Core(Handler):
|
|
|
646
675
|
self.putSymbolValue(symbolRecord, value)
|
|
647
676
|
return self.nextPC()
|
|
648
677
|
|
|
649
|
-
# Load a
|
|
678
|
+
# 1 Load a plugin. This is done at compile time.
|
|
679
|
+
# 2 Load text from a file
|
|
650
680
|
def k_load(self, command):
|
|
651
|
-
|
|
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():
|
|
652
689
|
command['target'] = self.getToken()
|
|
653
690
|
if self.nextIs('from'):
|
|
654
691
|
command['file'] = self.nextValue()
|
|
@@ -657,8 +694,11 @@ class Core(Handler):
|
|
|
657
694
|
return False
|
|
658
695
|
|
|
659
696
|
def r_load(self, command):
|
|
697
|
+
print(command)
|
|
660
698
|
target = self.getVariable(command['target'])
|
|
699
|
+
print(target)
|
|
661
700
|
file = self.getRuntimeValue(command['file'])
|
|
701
|
+
print(file)
|
|
662
702
|
f = open(file, 'r')
|
|
663
703
|
content = f.read()
|
|
664
704
|
f.close()
|
|
@@ -668,6 +708,27 @@ class Core(Handler):
|
|
|
668
708
|
self.putSymbolValue(target, value)
|
|
669
709
|
return self.nextPC()
|
|
670
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
|
+
|
|
671
732
|
# Arithmetic multiply
|
|
672
733
|
# multiply {variable} by {value}[ giving {variable}]}
|
|
673
734
|
def k_multiply(self, command):
|
|
@@ -1030,6 +1091,16 @@ class Core(Handler):
|
|
|
1030
1091
|
self.putSymbolValue(templateRecord, value)
|
|
1031
1092
|
return self.nextPC()
|
|
1032
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
|
+
|
|
1033
1104
|
# Return from subroutine
|
|
1034
1105
|
def k_return(self, command):
|
|
1035
1106
|
self.add(command)
|
|
@@ -1038,6 +1109,43 @@ class Core(Handler):
|
|
|
1038
1109
|
def r_return(self, command):
|
|
1039
1110
|
return self.stack.pop()
|
|
1040
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
|
+
|
|
1041
1149
|
# Provide a name for the script
|
|
1042
1150
|
def k_script(self, command):
|
|
1043
1151
|
self.program.name = self.nextToken()
|
|
@@ -1364,6 +1472,20 @@ class Core(Handler):
|
|
|
1364
1472
|
fileRecord['file'].truncate()
|
|
1365
1473
|
return self.nextPC()
|
|
1366
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
|
+
|
|
1367
1489
|
# Declare a general-purpose variable
|
|
1368
1490
|
def k_variable(self, command):
|
|
1369
1491
|
return self.compileVariable(command, True)
|
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=JT7KWbiZJzKjiWqUFbTt4PaWE-WxWQcMEBvq4al6KL0,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=rglL7s3f1Ewzc0wjUPZxoY8__DJscxjZU7-Pd6OCIZQ,79904
|
|
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.2.dist-info/entry_points.txt,sha256=JXAZbenl0TnsIft2FcGJbJ-4qoztVu2FuT8PFmWFexM,44
|
|
16
|
-
easycoder-250103.2.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
17
|
-
easycoder-250103.2.dist-info/WHEEL,sha256=ssQ84EZ5gH1pCOujd3iW7HClo_O_aDaClUbX4B8bjKY,100
|
|
18
|
-
easycoder-250103.2.dist-info/METADATA,sha256=UyIqZzD6XVImMRxZloXqyE_bUKKJRGCMztjXaaIPBTc,5178
|
|
19
|
-
easycoder-250103.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|