easycoder 241227.1__py2.py3-none-any.whl → 250102.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/README.md +6 -0
- easycoder/__init__.py +1 -1
- easycoder/ec_core.py +191 -127
- easycoder/ec_graphics.py +93 -35
- easycoder/ec_program.py +50 -34
- easycoder/ec_renderer.py +78 -18
- easycoder/ec_screenspec.py +0 -1
- easycoder-250102.1.dist-info/METADATA +84 -0
- easycoder-250102.1.dist-info/RECORD +19 -0
- easycoder-241227.1.dist-info/METADATA +0 -78
- easycoder-241227.1.dist-info/RECORD +0 -18
- {easycoder-241227.1.dist-info → easycoder-250102.1.dist-info}/LICENSE +0 -0
- {easycoder-241227.1.dist-info → easycoder-250102.1.dist-info}/WHEEL +0 -0
- {easycoder-241227.1.dist-info → easycoder-250102.1.dist-info}/entry_points.txt +0 -0
easycoder/README.md
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# EasyCode source code
|
|
2
|
+
These are the Python files that comprise **_EasyCoder_**.
|
|
3
|
+
|
|
4
|
+
**_EasyCoder_** has a small number of third-party dependencies. A minor one is `pytz`, which handles timezones. The biggest one by far is `kivy`, a comprehensive Python graphics library.
|
|
5
|
+
|
|
6
|
+
If an **_EasyCoder_** script filename ends with `.ecs` it's a command-line script. If it ends with `.ecg` it's a script for a graphical application and will cause `kivy` to be imported. Obviously this will only work on a GUI-based system, whereas command-line scripts will run anywhere there is Python.
|
easycoder/__init__.py
CHANGED
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'
|
|
@@ -464,23 +465,6 @@ class Core(Handler):
|
|
|
464
465
|
self.program.putSymbolValue(target, retval);
|
|
465
466
|
return self.nextPC()
|
|
466
467
|
|
|
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
468
|
# Go to a label
|
|
485
469
|
def k_go(self, command):
|
|
486
470
|
if self.peek() == 'to':
|
|
@@ -506,6 +490,23 @@ class Core(Handler):
|
|
|
506
490
|
def r_gotoPC(self, command):
|
|
507
491
|
return command['goto']
|
|
508
492
|
|
|
493
|
+
# Call a subroutine
|
|
494
|
+
def k_gosub(self, command):
|
|
495
|
+
if self.peek() == 'to':
|
|
496
|
+
self.nextToken()
|
|
497
|
+
command['gosub'] = self.nextToken()
|
|
498
|
+
self.add(command)
|
|
499
|
+
return True
|
|
500
|
+
|
|
501
|
+
def r_gosub(self, command):
|
|
502
|
+
label = command['gosub'] + ':'
|
|
503
|
+
address = self.symbols[label]
|
|
504
|
+
if address != None:
|
|
505
|
+
self.stack.append(self.nextPC())
|
|
506
|
+
return address
|
|
507
|
+
RuntimeError(self.program, f'There is no label "{label + ":"}"')
|
|
508
|
+
return None
|
|
509
|
+
|
|
509
510
|
# if <condition> <action> [else <action>]
|
|
510
511
|
def k_if(self, command):
|
|
511
512
|
command['condition'] = self.nextCondition()
|
|
@@ -696,6 +697,29 @@ class Core(Handler):
|
|
|
696
697
|
self.putSymbolValue(target, value)
|
|
697
698
|
return self.nextPC()
|
|
698
699
|
|
|
700
|
+
# Negate a variable
|
|
701
|
+
def k_negate(self, command):
|
|
702
|
+
if self.nextIsSymbol():
|
|
703
|
+
symbolRecord = self.getSymbolRecord()
|
|
704
|
+
if symbolRecord['valueHolder']:
|
|
705
|
+
command['target'] = self.getToken()
|
|
706
|
+
self.add(command)
|
|
707
|
+
return True
|
|
708
|
+
self.warning(f'Core.negate: Variable "{symbolRecord["name"]}" does not hold a value')
|
|
709
|
+
return False
|
|
710
|
+
|
|
711
|
+
def r_negate(self, command):
|
|
712
|
+
symbolRecord = self.getVariable(command['target'])
|
|
713
|
+
if not symbolRecord['valueHolder']:
|
|
714
|
+
RuntimeError(self.program, f'{symbolRecord["name"]} does not hold a value')
|
|
715
|
+
return None
|
|
716
|
+
value = self.getSymbolValue(symbolRecord)
|
|
717
|
+
if value == None:
|
|
718
|
+
RuntimeError(self.program, f'{symbolRecord["name"]} has not been initialised')
|
|
719
|
+
value['content'] *= -1
|
|
720
|
+
self.putSymbolValue(symbolRecord, value)
|
|
721
|
+
return self.nextPC()
|
|
722
|
+
|
|
699
723
|
# Define an object variable
|
|
700
724
|
def k_object(self, command):
|
|
701
725
|
return self.compileVariable(command)
|
|
@@ -976,7 +1000,7 @@ class Core(Handler):
|
|
|
976
1000
|
content = self.getSymbolValue(templateRecord)['content']
|
|
977
1001
|
original = self.getRuntimeValue(command['original'])
|
|
978
1002
|
replacement = self.getRuntimeValue(command['replacement'])
|
|
979
|
-
content = content.replace(original, replacement)
|
|
1003
|
+
content = content.replace(original, str(replacement))
|
|
980
1004
|
value = {}
|
|
981
1005
|
value['type'] = 'text'
|
|
982
1006
|
value['numeric'] = False
|
|
@@ -1009,25 +1033,32 @@ class Core(Handler):
|
|
|
1009
1033
|
command['target'] = target['name']
|
|
1010
1034
|
self.add(command)
|
|
1011
1035
|
return True
|
|
1036
|
+
return False
|
|
1012
1037
|
|
|
1013
1038
|
token = self.getToken()
|
|
1014
1039
|
if token == 'the':
|
|
1015
1040
|
token = self.nextToken()
|
|
1041
|
+
command['type'] = token
|
|
1042
|
+
|
|
1016
1043
|
if token == 'elements':
|
|
1017
1044
|
self.nextToken()
|
|
1018
1045
|
if self.peek() == 'of':
|
|
1019
1046
|
self.nextToken()
|
|
1020
1047
|
if self.nextIsSymbol():
|
|
1021
|
-
command['type'] = 'elements'
|
|
1022
1048
|
command['name'] = self.getToken()
|
|
1023
1049
|
if self.peek() == 'to':
|
|
1024
1050
|
self.nextToken()
|
|
1025
1051
|
command['elements'] = self.nextValue()
|
|
1026
1052
|
self.add(command)
|
|
1027
1053
|
return True
|
|
1054
|
+
|
|
1055
|
+
elif token == 'encoding':
|
|
1056
|
+
if self.nextIs('to'):
|
|
1057
|
+
command['encoding'] = self.nextValue()
|
|
1058
|
+
self.add(command)
|
|
1059
|
+
return True
|
|
1028
1060
|
|
|
1029
|
-
|
|
1030
|
-
command['type'] = 'property'
|
|
1061
|
+
elif token == 'property':
|
|
1031
1062
|
command['name'] = self.nextValue()
|
|
1032
1063
|
if self.nextIs('of'):
|
|
1033
1064
|
if self.nextIsSymbol():
|
|
@@ -1037,8 +1068,7 @@ class Core(Handler):
|
|
|
1037
1068
|
self.add(command)
|
|
1038
1069
|
return True
|
|
1039
1070
|
|
|
1040
|
-
|
|
1041
|
-
command['type'] = 'element'
|
|
1071
|
+
elif token == 'element':
|
|
1042
1072
|
command['index'] = self.nextValue()
|
|
1043
1073
|
if self.nextIs('of'):
|
|
1044
1074
|
if self.nextIsSymbol():
|
|
@@ -1047,7 +1077,6 @@ class Core(Handler):
|
|
|
1047
1077
|
command['value'] = self.nextValue()
|
|
1048
1078
|
self.add(command)
|
|
1049
1079
|
return True
|
|
1050
|
-
|
|
1051
1080
|
return False
|
|
1052
1081
|
|
|
1053
1082
|
def r_set(self, command):
|
|
@@ -1060,7 +1089,7 @@ class Core(Handler):
|
|
|
1060
1089
|
self.putSymbolValue(target, val)
|
|
1061
1090
|
return self.nextPC()
|
|
1062
1091
|
|
|
1063
|
-
|
|
1092
|
+
elif cmdType == 'elements':
|
|
1064
1093
|
symbolRecord = self.getVariable(command['name'])
|
|
1065
1094
|
elements = self.getRuntimeValue(command['elements'])
|
|
1066
1095
|
currentElements = symbolRecord['elements']
|
|
@@ -1079,7 +1108,7 @@ class Core(Handler):
|
|
|
1079
1108
|
symbolRecord['value'] = newValue
|
|
1080
1109
|
return self.nextPC()
|
|
1081
1110
|
|
|
1082
|
-
|
|
1111
|
+
elif cmdType == 'element':
|
|
1083
1112
|
value = self.getRuntimeValue(command['value'])
|
|
1084
1113
|
index = self.getRuntimeValue(command['index'])
|
|
1085
1114
|
target = self.getVariable(command['target'])
|
|
@@ -1094,7 +1123,11 @@ class Core(Handler):
|
|
|
1094
1123
|
self.putSymbolValue(target, val)
|
|
1095
1124
|
return self.nextPC()
|
|
1096
1125
|
|
|
1097
|
-
|
|
1126
|
+
elif cmdType == 'encoding':
|
|
1127
|
+
self.encoding = self.getRuntimeValue(command['encoding'])
|
|
1128
|
+
return self.nextPC()
|
|
1129
|
+
|
|
1130
|
+
elif cmdType == 'property':
|
|
1098
1131
|
value = self.getRuntimeValue(command['value'])
|
|
1099
1132
|
name = self.getRuntimeValue(command['name'])
|
|
1100
1133
|
target = command['target']
|
|
@@ -1417,7 +1450,7 @@ class Core(Handler):
|
|
|
1417
1450
|
# Compile a value in this domain
|
|
1418
1451
|
def compileValue(self):
|
|
1419
1452
|
value = {}
|
|
1420
|
-
value['domain'] =
|
|
1453
|
+
value['domain'] = self.getName()
|
|
1421
1454
|
token = self.getToken()
|
|
1422
1455
|
if self.isSymbol():
|
|
1423
1456
|
value['name'] = token
|
|
@@ -1446,10 +1479,10 @@ class Core(Handler):
|
|
|
1446
1479
|
return value
|
|
1447
1480
|
return None
|
|
1448
1481
|
|
|
1449
|
-
if token in ['now', 'today', 'newline', '
|
|
1482
|
+
if token in ['now', 'today', 'newline', 'tab', 'empty']:
|
|
1450
1483
|
return value
|
|
1451
1484
|
|
|
1452
|
-
if token in ['
|
|
1485
|
+
if token in ['stringify', 'json', 'lowercase', 'uppercase', 'hash', 'random', 'float', 'integer', 'encode', 'decode']:
|
|
1453
1486
|
value['content'] = self.nextValue()
|
|
1454
1487
|
return value
|
|
1455
1488
|
|
|
@@ -1532,7 +1565,9 @@ class Core(Handler):
|
|
|
1532
1565
|
if token == 'index':
|
|
1533
1566
|
if self.nextIs('of'):
|
|
1534
1567
|
if self.nextIsSymbol():
|
|
1568
|
+
value['variable'] = self.getSymbolRecord()['name']
|
|
1535
1569
|
if self.peek() == 'in':
|
|
1570
|
+
value['value'] = None
|
|
1536
1571
|
value['type'] = 'indexOf'
|
|
1537
1572
|
if self.nextIsSymbol():
|
|
1538
1573
|
value['target'] = self.getSymbolRecord()['name']
|
|
@@ -1541,8 +1576,9 @@ class Core(Handler):
|
|
|
1541
1576
|
value['name'] = self.getToken()
|
|
1542
1577
|
return value
|
|
1543
1578
|
else:
|
|
1544
|
-
value['
|
|
1579
|
+
value['value'] = self.getValue()
|
|
1545
1580
|
if self.nextIs('in'):
|
|
1581
|
+
value['variable'] = None
|
|
1546
1582
|
value['type'] = 'indexOf'
|
|
1547
1583
|
if self.nextIsSymbol():
|
|
1548
1584
|
value['target'] = self.getSymbolRecord()['name']
|
|
@@ -1608,7 +1644,8 @@ class Core(Handler):
|
|
|
1608
1644
|
return value
|
|
1609
1645
|
|
|
1610
1646
|
if token == 'files':
|
|
1611
|
-
|
|
1647
|
+
token = self.nextToken()
|
|
1648
|
+
if token in ['in', 'of']:
|
|
1612
1649
|
value['target'] = self.nextValue()
|
|
1613
1650
|
return value
|
|
1614
1651
|
return None
|
|
@@ -1693,6 +1730,14 @@ class Core(Handler):
|
|
|
1693
1730
|
value['content'] = round(math.cos(angle * 0.01745329) * radius)
|
|
1694
1731
|
return value
|
|
1695
1732
|
|
|
1733
|
+
def v_count(self, v):
|
|
1734
|
+
variable = self.getVariable(v['name'])
|
|
1735
|
+
content = variable['value'][variable['index']]['content']
|
|
1736
|
+
value = {}
|
|
1737
|
+
value['type'] = 'int'
|
|
1738
|
+
value['content'] = len(content)
|
|
1739
|
+
return value
|
|
1740
|
+
|
|
1696
1741
|
def v_datime(self, v):
|
|
1697
1742
|
ts = self.getRuntimeValue(v['timestamp'])
|
|
1698
1743
|
fmt = v['format']
|
|
@@ -1706,9 +1751,17 @@ class Core(Handler):
|
|
|
1706
1751
|
return value
|
|
1707
1752
|
|
|
1708
1753
|
def v_decode(self, v):
|
|
1754
|
+
content = self.getRuntimeValue(v['content'])
|
|
1709
1755
|
value = {}
|
|
1710
1756
|
value['type'] = 'text'
|
|
1711
|
-
|
|
1757
|
+
if self.encoding == 'utf-8':
|
|
1758
|
+
value['content'] = content.decode('utf-8')
|
|
1759
|
+
elif self.encoding == 'base64':
|
|
1760
|
+
base64_bytes = content.encode('ascii')
|
|
1761
|
+
message_bytes = base64.b64decode(base64_bytes)
|
|
1762
|
+
value['content'] = message_bytes.decode('ascii')
|
|
1763
|
+
else:
|
|
1764
|
+
value = v
|
|
1712
1765
|
return value
|
|
1713
1766
|
|
|
1714
1767
|
def v_element(self, v):
|
|
@@ -1731,18 +1784,9 @@ class Core(Handler):
|
|
|
1731
1784
|
var = self.getVariable(v['name'])
|
|
1732
1785
|
value = {}
|
|
1733
1786
|
value['type'] = 'int'
|
|
1734
|
-
# value['content'] = self.getVariable(v['name'])['elements']
|
|
1735
1787
|
value['content'] = var['elements']
|
|
1736
1788
|
return value
|
|
1737
1789
|
|
|
1738
|
-
def v_count(self, v):
|
|
1739
|
-
variable = self.getVariable(v['name'])
|
|
1740
|
-
content = variable['value'][variable['index']]['content']
|
|
1741
|
-
value = {}
|
|
1742
|
-
value['type'] = 'int'
|
|
1743
|
-
value['content'] = len(content)
|
|
1744
|
-
return value
|
|
1745
|
-
|
|
1746
1790
|
def v_empty(self, v):
|
|
1747
1791
|
value = {}
|
|
1748
1792
|
value['type'] = 'text'
|
|
@@ -1750,9 +1794,17 @@ class Core(Handler):
|
|
|
1750
1794
|
return value
|
|
1751
1795
|
|
|
1752
1796
|
def v_encode(self, v):
|
|
1797
|
+
content = self.getRuntimeValue(v['content'])
|
|
1753
1798
|
value = {}
|
|
1754
1799
|
value['type'] = 'text'
|
|
1755
|
-
|
|
1800
|
+
if self.encoding == 'utf-8':
|
|
1801
|
+
value['content'] = content.encode('utf-8')
|
|
1802
|
+
elif self.encoding == 'base64':
|
|
1803
|
+
data_bytes = content.encode('ascii')
|
|
1804
|
+
base64_bytes = base64.b64encode(data_bytes)
|
|
1805
|
+
value['content'] = base64_bytes.decode('ascii')
|
|
1806
|
+
else:
|
|
1807
|
+
value = v
|
|
1756
1808
|
return value
|
|
1757
1809
|
|
|
1758
1810
|
def v_error(self, v):
|
|
@@ -1766,21 +1818,22 @@ class Core(Handler):
|
|
|
1766
1818
|
value['content'] = errorReason
|
|
1767
1819
|
return value
|
|
1768
1820
|
|
|
1769
|
-
def
|
|
1770
|
-
|
|
1821
|
+
def v_files(self, v):
|
|
1822
|
+
v = self.getRuntimeValue(v['target'])
|
|
1771
1823
|
value = {}
|
|
1772
1824
|
value['type'] = 'text'
|
|
1773
|
-
value['content'] =
|
|
1825
|
+
value['content'] = os.listdir(v)
|
|
1774
1826
|
return value
|
|
1775
1827
|
|
|
1776
|
-
def
|
|
1777
|
-
|
|
1828
|
+
def v_float(self, v):
|
|
1829
|
+
val = self.getRuntimeValue(v['content'])
|
|
1778
1830
|
value = {}
|
|
1779
|
-
value['type'] = '
|
|
1831
|
+
value['type'] = 'float'
|
|
1780
1832
|
try:
|
|
1781
|
-
value['content'] =
|
|
1833
|
+
value['content'] = float(val)
|
|
1782
1834
|
except:
|
|
1783
|
-
|
|
1835
|
+
RuntimeWarning(self.program, f'Value cannot be parsed as floating-point')
|
|
1836
|
+
value['content'] = 0.0
|
|
1784
1837
|
return value
|
|
1785
1838
|
|
|
1786
1839
|
def v_from(self, v):
|
|
@@ -1804,17 +1857,6 @@ class Core(Handler):
|
|
|
1804
1857
|
value['content'] = hashlib.sha256(hashval.encode('utf-8')).hexdigest()
|
|
1805
1858
|
return value
|
|
1806
1859
|
|
|
1807
|
-
def v_float(self, v):
|
|
1808
|
-
val = self.getRuntimeValue(v['content'])
|
|
1809
|
-
value = {}
|
|
1810
|
-
value['type'] = 'float'
|
|
1811
|
-
try:
|
|
1812
|
-
value['content'] = float(val)
|
|
1813
|
-
except:
|
|
1814
|
-
RuntimeWarning(self.program, f'Value cannot be parsed as floating-point')
|
|
1815
|
-
value['content'] = 0.0
|
|
1816
|
-
return value
|
|
1817
|
-
|
|
1818
1860
|
def v_index(self, v):
|
|
1819
1861
|
value = {}
|
|
1820
1862
|
value['type'] = 'int'
|
|
@@ -1822,16 +1864,22 @@ class Core(Handler):
|
|
|
1822
1864
|
return value
|
|
1823
1865
|
|
|
1824
1866
|
def v_indexOf(self, v):
|
|
1825
|
-
|
|
1867
|
+
value = v['value']
|
|
1868
|
+
if value == None:
|
|
1869
|
+
value = self.getSymbolValue(v['variable'])['content']
|
|
1870
|
+
else:
|
|
1871
|
+
value = self.getRuntimeValue(value)
|
|
1826
1872
|
target = self.getVariable(v['target'])
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1873
|
+
data = self.getSymbolValue(target)['content']
|
|
1874
|
+
index = -1
|
|
1875
|
+
for n in range(0, len(data)):
|
|
1876
|
+
if data[n] == value:
|
|
1877
|
+
index = n
|
|
1878
|
+
break
|
|
1879
|
+
retval = {}
|
|
1880
|
+
retval['type'] = 'int'
|
|
1881
|
+
retval['content'] = index
|
|
1882
|
+
return retval
|
|
1835
1883
|
|
|
1836
1884
|
def v_integer(self, v):
|
|
1837
1885
|
val = self.getRuntimeValue(v['content'])
|
|
@@ -1840,6 +1888,16 @@ class Core(Handler):
|
|
|
1840
1888
|
value['content'] = int(val)
|
|
1841
1889
|
return value
|
|
1842
1890
|
|
|
1891
|
+
def v_json(self, v):
|
|
1892
|
+
item = self.getRuntimeValue(v['content'])
|
|
1893
|
+
value = {}
|
|
1894
|
+
value['type'] = 'object'
|
|
1895
|
+
try:
|
|
1896
|
+
value['content'] = json.loads(item)
|
|
1897
|
+
except:
|
|
1898
|
+
RuntimeError(self.program, 'Cannot encode value')
|
|
1899
|
+
return value
|
|
1900
|
+
|
|
1843
1901
|
def v_keys(self, v):
|
|
1844
1902
|
value = {}
|
|
1845
1903
|
value['type'] = 'int'
|
|
@@ -1870,18 +1928,20 @@ class Core(Handler):
|
|
|
1870
1928
|
value['content'] = content.lower()
|
|
1871
1929
|
return value
|
|
1872
1930
|
|
|
1873
|
-
def
|
|
1874
|
-
|
|
1931
|
+
def v_memory(self, v):
|
|
1932
|
+
process: Process = Process(os.getpid())
|
|
1933
|
+
megabytes: float = process.memory_info().rss / (1024 * 1024)
|
|
1875
1934
|
value = {}
|
|
1876
|
-
value['type'] = '
|
|
1877
|
-
value['content'] =
|
|
1935
|
+
value['type'] = 'float'
|
|
1936
|
+
value['content'] = megabytes
|
|
1878
1937
|
return value
|
|
1879
1938
|
|
|
1880
|
-
def
|
|
1881
|
-
|
|
1939
|
+
def v_modification(self, v):
|
|
1940
|
+
fileName = self.getRuntimeValue(v['fileName'])
|
|
1941
|
+
ts = int(os.stat(fileName).st_mtime)
|
|
1882
1942
|
value = {}
|
|
1883
1943
|
value['type'] = 'int'
|
|
1884
|
-
value['content'] =
|
|
1944
|
+
value['content'] = ts
|
|
1885
1945
|
return value
|
|
1886
1946
|
|
|
1887
1947
|
def v_modulo(self, v):
|
|
@@ -1931,6 +1991,13 @@ class Core(Handler):
|
|
|
1931
1991
|
value['type'] = 'text'
|
|
1932
1992
|
return value
|
|
1933
1993
|
|
|
1994
|
+
def v_random(self, v):
|
|
1995
|
+
limit = self.getRuntimeValue(v['content'])
|
|
1996
|
+
value = {}
|
|
1997
|
+
value['type'] = 'int'
|
|
1998
|
+
value['content'] = randrange(0, limit)
|
|
1999
|
+
return value
|
|
2000
|
+
|
|
1934
2001
|
def v_right(self, v):
|
|
1935
2002
|
content = self.getRuntimeValue(v['content'])
|
|
1936
2003
|
count = self.getRuntimeValue(v['count'])
|
|
@@ -1947,32 +2014,11 @@ class Core(Handler):
|
|
|
1947
2014
|
value['content'] = round(math.sin(angle * 0.01745329) * radius)
|
|
1948
2015
|
return value
|
|
1949
2016
|
|
|
1950
|
-
def
|
|
1951
|
-
|
|
1952
|
-
radius = self.getRuntimeValue(v['radius'])
|
|
1953
|
-
value = {}
|
|
1954
|
-
value['type'] = 'int'
|
|
1955
|
-
value['content'] = round(math.tan(angle * 0.01745329) * radius)
|
|
1956
|
-
return value
|
|
1957
|
-
|
|
1958
|
-
def v_timestamp(self, v):
|
|
1959
|
-
value = {}
|
|
1960
|
-
value['type'] = 'int'
|
|
1961
|
-
fmt = v['format']
|
|
1962
|
-
if fmt == None:
|
|
1963
|
-
value['content'] = int(time.time())
|
|
1964
|
-
else:
|
|
1965
|
-
fmt = self.getRuntimeValue(fmt)
|
|
1966
|
-
dt = self.getRuntimeValue(v['datime'])
|
|
1967
|
-
spec = datetime.strptime(dt, fmt)
|
|
1968
|
-
t = datetime.now().replace(hour=spec.hour, minute=spec.minute, second=spec.second, microsecond=0)
|
|
1969
|
-
value['content'] = int(t.timestamp())
|
|
1970
|
-
return value
|
|
1971
|
-
|
|
1972
|
-
def v_today(self, v):
|
|
2017
|
+
def v_stringify(self, v):
|
|
2018
|
+
item = self.getRuntimeValue(v['content'])
|
|
1973
2019
|
value = {}
|
|
1974
|
-
value['type'] = '
|
|
1975
|
-
value['content'] =
|
|
2020
|
+
value['type'] = 'text'
|
|
2021
|
+
value['content'] = json.dumps(item)
|
|
1976
2022
|
return value
|
|
1977
2023
|
|
|
1978
2024
|
def v_symbol(self, symbolRecord):
|
|
@@ -1991,39 +2037,45 @@ class Core(Handler):
|
|
|
1991
2037
|
else:
|
|
1992
2038
|
return None
|
|
1993
2039
|
|
|
1994
|
-
def
|
|
1995
|
-
v = self.getRuntimeValue(v['content'])
|
|
2040
|
+
def v_tab(self, v):
|
|
1996
2041
|
value = {}
|
|
1997
|
-
value['type'] = '
|
|
1998
|
-
value['content'] =
|
|
2042
|
+
value['type'] = 'text'
|
|
2043
|
+
value['content'] = '\t'
|
|
1999
2044
|
return value
|
|
2000
2045
|
|
|
2001
|
-
def
|
|
2002
|
-
|
|
2046
|
+
def v_tan(self, v):
|
|
2047
|
+
angle = self.getRuntimeValue(v['angle'])
|
|
2048
|
+
radius = self.getRuntimeValue(v['radius'])
|
|
2003
2049
|
value = {}
|
|
2004
|
-
value['type'] = '
|
|
2005
|
-
value['content'] =
|
|
2050
|
+
value['type'] = 'int'
|
|
2051
|
+
value['content'] = round(math.tan(angle * 0.01745329) * radius)
|
|
2006
2052
|
return value
|
|
2007
2053
|
|
|
2008
|
-
def
|
|
2009
|
-
v = self.getRuntimeValue(v['content'])
|
|
2054
|
+
def v_timestamp(self, v):
|
|
2010
2055
|
value = {}
|
|
2011
|
-
value['type'] = '
|
|
2012
|
-
|
|
2056
|
+
value['type'] = 'int'
|
|
2057
|
+
fmt = v['format']
|
|
2058
|
+
if fmt == None:
|
|
2059
|
+
value['content'] = int(time.time())
|
|
2060
|
+
else:
|
|
2061
|
+
fmt = self.getRuntimeValue(fmt)
|
|
2062
|
+
dt = self.getRuntimeValue(v['datime'])
|
|
2063
|
+
spec = datetime.strptime(dt, fmt)
|
|
2064
|
+
t = datetime.now().replace(hour=spec.hour, minute=spec.minute, second=spec.second, microsecond=0)
|
|
2065
|
+
value['content'] = int(t.timestamp())
|
|
2013
2066
|
return value
|
|
2014
2067
|
|
|
2015
|
-
def
|
|
2068
|
+
def v_today(self, v):
|
|
2016
2069
|
value = {}
|
|
2017
2070
|
value['type'] = 'int'
|
|
2018
|
-
value['content'] = datetime.
|
|
2071
|
+
value['content'] = int(datetime.combine(datetime.now().date(),datetime.min.time()).timestamp())*1000
|
|
2019
2072
|
return value
|
|
2020
2073
|
|
|
2021
|
-
def
|
|
2022
|
-
|
|
2023
|
-
megabytes: float = process.memory_info().rss / (1024 * 1024)
|
|
2074
|
+
def v_trim(self, v):
|
|
2075
|
+
v = self.getRuntimeValue(v['content'])
|
|
2024
2076
|
value = {}
|
|
2025
|
-
value['type'] = '
|
|
2026
|
-
value['content'] =
|
|
2077
|
+
value['type'] = 'text'
|
|
2078
|
+
value['content'] = v.strip()
|
|
2027
2079
|
return value
|
|
2028
2080
|
|
|
2029
2081
|
def v_type(self, v):
|
|
@@ -2044,12 +2096,24 @@ class Core(Handler):
|
|
|
2044
2096
|
value['content'] = 'object'
|
|
2045
2097
|
return value
|
|
2046
2098
|
|
|
2047
|
-
def
|
|
2048
|
-
|
|
2049
|
-
|
|
2099
|
+
def v_uppercase(self, v):
|
|
2100
|
+
content = self.getRuntimeValue(v['content'])
|
|
2101
|
+
value = {}
|
|
2102
|
+
value['type'] = 'text'
|
|
2103
|
+
value['content'] = content.upper()
|
|
2104
|
+
return value
|
|
2105
|
+
|
|
2106
|
+
def v_valueOf(self, v):
|
|
2107
|
+
v = self.getRuntimeValue(v['content'])
|
|
2050
2108
|
value = {}
|
|
2051
2109
|
value['type'] = 'int'
|
|
2052
|
-
value['content'] =
|
|
2110
|
+
value['content'] = int(v)
|
|
2111
|
+
return value
|
|
2112
|
+
|
|
2113
|
+
def v_weekday(self, v):
|
|
2114
|
+
value = {}
|
|
2115
|
+
value['type'] = 'int'
|
|
2116
|
+
value['content'] = datetime.today().weekday()
|
|
2053
2117
|
return value
|
|
2054
2118
|
|
|
2055
2119
|
#############################################################################
|
easycoder/ec_graphics.py
CHANGED
|
@@ -9,7 +9,7 @@ class Graphics(Handler):
|
|
|
9
9
|
Handler.__init__(self, compiler)
|
|
10
10
|
|
|
11
11
|
def getName(self):
|
|
12
|
-
return '
|
|
12
|
+
return 'graphics'
|
|
13
13
|
|
|
14
14
|
#############################################################################
|
|
15
15
|
# Keyword handlers
|
|
@@ -204,12 +204,47 @@ class Graphics(Handler):
|
|
|
204
204
|
def r_ellipse(self, command):
|
|
205
205
|
return self.nextPC()
|
|
206
206
|
|
|
207
|
+
def r_getui(self, command):
|
|
208
|
+
self.ui = self.renderer.getUI()
|
|
209
|
+
return self.nextPC()
|
|
210
|
+
|
|
207
211
|
def k_image(self, command):
|
|
208
212
|
return self.compileVariable(command)
|
|
209
213
|
|
|
210
214
|
def r_image(self, command):
|
|
211
215
|
return self.nextPC()
|
|
212
216
|
|
|
217
|
+
# move an element
|
|
218
|
+
def k_move(self, command):
|
|
219
|
+
if self.nextIsSymbol():
|
|
220
|
+
record = self.getSymbolRecord()
|
|
221
|
+
type = record['keyword']
|
|
222
|
+
if type in ['ellipse', 'rectangle']:
|
|
223
|
+
command['target'] = record['id']
|
|
224
|
+
token = self.nextToken()
|
|
225
|
+
if token == 'to':
|
|
226
|
+
command['x'] = self.nextValue()
|
|
227
|
+
command['y'] = self.nextValue()
|
|
228
|
+
self.add(command)
|
|
229
|
+
return True
|
|
230
|
+
elif token == 'by':
|
|
231
|
+
command['keyword'] = 'moveBy'
|
|
232
|
+
command['dx'] = self.nextValue()
|
|
233
|
+
command['dy'] = self.nextValue()
|
|
234
|
+
self.add(command)
|
|
235
|
+
return True
|
|
236
|
+
return False
|
|
237
|
+
|
|
238
|
+
def r_move(self, command):
|
|
239
|
+
pos = (self.getRuntimeValue(command['x']), self.getRuntimeValue(command['y']))
|
|
240
|
+
self.ui.moveElementTo(self.getRuntimeValue(command['target']), pos)
|
|
241
|
+
return self.nextPC()
|
|
242
|
+
|
|
243
|
+
def r_moveBy(self, command):
|
|
244
|
+
dist = (self.getRuntimeValue(command['dx']), self.getRuntimeValue(command['dy']))
|
|
245
|
+
self.ui.moveElementBy(self.getRuntimeValue(command['target']), dist)
|
|
246
|
+
return self.nextPC()
|
|
247
|
+
|
|
213
248
|
def k_on(self, command):
|
|
214
249
|
token = self.nextToken()
|
|
215
250
|
if token in ['click', 'tap']:
|
|
@@ -255,37 +290,6 @@ class Graphics(Handler):
|
|
|
255
290
|
RuntimeError(self.program, f'{record['name']} is not a clickable object')
|
|
256
291
|
return self.nextPC()
|
|
257
292
|
|
|
258
|
-
# move an element
|
|
259
|
-
def k_move(self, command):
|
|
260
|
-
if self.nextIsSymbol():
|
|
261
|
-
record = self.getSymbolRecord()
|
|
262
|
-
type = record['keyword']
|
|
263
|
-
if type in ['ellipse', 'rectangle']:
|
|
264
|
-
command['target'] = record['id']
|
|
265
|
-
token = self.nextToken()
|
|
266
|
-
if token == 'to':
|
|
267
|
-
command['x'] = self.nextValue()
|
|
268
|
-
command['y'] = self.nextValue()
|
|
269
|
-
self.add(command)
|
|
270
|
-
return True
|
|
271
|
-
elif token == 'by':
|
|
272
|
-
command['keyword'] = 'moveBy'
|
|
273
|
-
command['dx'] = self.nextValue()
|
|
274
|
-
command['dy'] = self.nextValue()
|
|
275
|
-
self.add(command)
|
|
276
|
-
return True
|
|
277
|
-
return False
|
|
278
|
-
|
|
279
|
-
def r_move(self, command):
|
|
280
|
-
pos = (self.getRuntimeValue(command['x']), self.getRuntimeValue(command['y']))
|
|
281
|
-
self.ui.moveElementTo(self.getRuntimeValue(command['target']), pos)
|
|
282
|
-
return self.nextPC()
|
|
283
|
-
|
|
284
|
-
def r_moveBy(self, command):
|
|
285
|
-
dist = (self.getRuntimeValue(command['dx']), self.getRuntimeValue(command['dy']))
|
|
286
|
-
self.ui.moveElementBy(self.getRuntimeValue(command['target']), dist)
|
|
287
|
-
return self.nextPC()
|
|
288
|
-
|
|
289
293
|
def k_rectangle(self, command):
|
|
290
294
|
return self.compileVariable(command)
|
|
291
295
|
|
|
@@ -306,13 +310,22 @@ class Graphics(Handler):
|
|
|
306
310
|
|
|
307
311
|
def r_render(self, command):
|
|
308
312
|
self.ui = self.renderer.getUI()
|
|
309
|
-
|
|
313
|
+
try:
|
|
314
|
+
ScreenSpec().render(self.getRuntimeValue(command['spec']), self.ui)
|
|
315
|
+
except Exception as e:
|
|
316
|
+
RuntimeError(self.program, e)
|
|
310
317
|
return self.nextPC()
|
|
311
318
|
|
|
312
319
|
# run graphics
|
|
313
320
|
def k_run(self, command):
|
|
314
321
|
if self.nextIs('graphics'):
|
|
315
322
|
self.add(command)
|
|
323
|
+
cmd = {}
|
|
324
|
+
cmd['domain'] = 'graphics'
|
|
325
|
+
cmd['lino'] = command['lino'] + 1
|
|
326
|
+
cmd['keyword'] = 'getui'
|
|
327
|
+
cmd['debug'] = False
|
|
328
|
+
self.addCommand(cmd)
|
|
316
329
|
return True
|
|
317
330
|
return False
|
|
318
331
|
|
|
@@ -323,6 +336,33 @@ class Graphics(Handler):
|
|
|
323
336
|
self.program.run(self.nextPC())
|
|
324
337
|
self.renderer.run()
|
|
325
338
|
|
|
339
|
+
# Set something
|
|
340
|
+
def k_set(self, command):
|
|
341
|
+
if self.nextIs('attribute'):
|
|
342
|
+
command['attribute'] = self.nextValue()
|
|
343
|
+
if self.nextIs('of'):
|
|
344
|
+
if self.nextIsSymbol():
|
|
345
|
+
record = self.getSymbolRecord()
|
|
346
|
+
if record['keyword'] in ['ellipse', 'rectangle', 'text', 'image']:
|
|
347
|
+
command['target'] = record['name']
|
|
348
|
+
if self.nextIs('to'):
|
|
349
|
+
command['value'] = self.nextValue()
|
|
350
|
+
self.addCommand(command)
|
|
351
|
+
return True
|
|
352
|
+
else:
|
|
353
|
+
FatalError(self.program.compiler, f'Invalid type: {record['keyword']}')
|
|
354
|
+
else:
|
|
355
|
+
FatalError(self.program.compiler, f'\'{self.getToken()}\' is not a variable')
|
|
356
|
+
return False
|
|
357
|
+
|
|
358
|
+
def r_set(self, command):
|
|
359
|
+
attribute = self.getRuntimeValue(command['attribute'])
|
|
360
|
+
target = self.getVariable(command['target'])
|
|
361
|
+
id = target['value'][target['index']]['content']
|
|
362
|
+
value = self.getRuntimeValue(command['value'])
|
|
363
|
+
self.ui.setAttribute(id, attribute, value)
|
|
364
|
+
return self.nextPC()
|
|
365
|
+
|
|
326
366
|
#############################################################################
|
|
327
367
|
# Modify a value or leave it unchanged.
|
|
328
368
|
def modifyValue(self, value):
|
|
@@ -333,16 +373,24 @@ class Graphics(Handler):
|
|
|
333
373
|
def compileValue(self):
|
|
334
374
|
value = {}
|
|
335
375
|
value['domain'] = self.getName()
|
|
336
|
-
if self.tokenIs('
|
|
376
|
+
if self.tokenIs('the'):
|
|
377
|
+
self.nextToken()
|
|
378
|
+
kwd = self.getToken()
|
|
379
|
+
value['type'] = kwd
|
|
380
|
+
if kwd == 'attribute':
|
|
337
381
|
attribute = self.nextValue()
|
|
338
382
|
if self.nextIs('of'):
|
|
339
383
|
if self.nextIsSymbol():
|
|
340
384
|
record = self.getSymbolRecord()
|
|
341
385
|
if record['keyword'] in ['ellipse', 'rectangle']:
|
|
342
|
-
value['type'] = 'attribute'
|
|
343
386
|
value['attribute'] = attribute
|
|
344
387
|
value['target'] = record['name']
|
|
345
388
|
return value
|
|
389
|
+
elif kwd == 'window':
|
|
390
|
+
attribute = self.nextToken()
|
|
391
|
+
if attribute in ['left', 'top', 'width', 'height']:
|
|
392
|
+
value['attribute'] = attribute
|
|
393
|
+
return value
|
|
346
394
|
return None
|
|
347
395
|
|
|
348
396
|
#############################################################################
|
|
@@ -361,6 +409,16 @@ class Graphics(Handler):
|
|
|
361
409
|
except Exception as e:
|
|
362
410
|
RuntimeError(self.program, e)
|
|
363
411
|
|
|
412
|
+
def v_window(self, v):
|
|
413
|
+
try:
|
|
414
|
+
attribute = v['attribute']
|
|
415
|
+
value = {}
|
|
416
|
+
value['type'] = 'int'
|
|
417
|
+
value['content'] = int(round(self.ui.getWindowAttribute(attribute)))
|
|
418
|
+
return value
|
|
419
|
+
except Exception as e:
|
|
420
|
+
RuntimeError(self.program, e)
|
|
421
|
+
|
|
364
422
|
#############################################################################
|
|
365
423
|
# Compile a condition
|
|
366
424
|
def compileCondition(self):
|
easycoder/ec_program.py
CHANGED
|
@@ -192,52 +192,68 @@ class Program:
|
|
|
192
192
|
index = 0
|
|
193
193
|
symbolRecord['value'][index] = value
|
|
194
194
|
|
|
195
|
-
def encode(self, value):
|
|
196
|
-
return value
|
|
195
|
+
def encode(self, value, encoding='UTF-8'):
|
|
196
|
+
return value.encode(encoding)
|
|
197
197
|
|
|
198
|
-
def decode(self, value):
|
|
199
|
-
return value
|
|
198
|
+
def decode(self, value, encoding='UTF-8'):
|
|
199
|
+
return value.decode(encoding)
|
|
200
200
|
|
|
201
201
|
# Tokenise the script
|
|
202
202
|
def tokenise(self, script):
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
for
|
|
203
|
+
token = ''
|
|
204
|
+
literal = False
|
|
205
|
+
for lino in range(0, len(script.lines)):
|
|
206
|
+
line = script.lines[lino]
|
|
206
207
|
length = len(line)
|
|
207
|
-
|
|
208
|
-
|
|
208
|
+
if length == 0:
|
|
209
|
+
continue
|
|
210
|
+
# Look for the first non-space
|
|
209
211
|
n = 0
|
|
210
|
-
while n < length:
|
|
212
|
+
while n < length and line[n].isspace():
|
|
213
|
+
n += 1
|
|
214
|
+
# The whole line may be empty
|
|
215
|
+
if n == length:
|
|
216
|
+
if literal:
|
|
217
|
+
token += '\n'
|
|
218
|
+
continue
|
|
219
|
+
# If in an unfinished literal, the first char must be a backtick to continue adding to it
|
|
220
|
+
if literal:
|
|
221
|
+
if line[n] != '`':
|
|
222
|
+
# Close the current token
|
|
223
|
+
if len(token) > 0:
|
|
224
|
+
script.tokens.append(Token(lino, token))
|
|
225
|
+
token = ''
|
|
226
|
+
literal = False
|
|
227
|
+
n += 1
|
|
228
|
+
for n in range(n, length):
|
|
211
229
|
c = line[n]
|
|
212
|
-
if
|
|
213
|
-
|
|
214
|
-
|
|
230
|
+
# Test if we are in a literal
|
|
231
|
+
if not literal:
|
|
232
|
+
if c.isspace():
|
|
233
|
+
if len(token) > 0:
|
|
234
|
+
script.tokens.append(Token(lino, token))
|
|
235
|
+
token = ''
|
|
215
236
|
continue
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
inSpace = True
|
|
220
|
-
n += 1
|
|
221
|
-
continue
|
|
222
|
-
inSpace = False
|
|
237
|
+
elif c == '!':
|
|
238
|
+
break
|
|
239
|
+
# Test for the start or end of a literal
|
|
223
240
|
if c == '`':
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
elif c == '!':
|
|
233
|
-
break
|
|
241
|
+
if literal:
|
|
242
|
+
token += c
|
|
243
|
+
literal = False
|
|
244
|
+
else:
|
|
245
|
+
token += c
|
|
246
|
+
literal = True
|
|
247
|
+
m = n
|
|
248
|
+
continue
|
|
234
249
|
else:
|
|
235
250
|
token += c
|
|
236
|
-
n += 1
|
|
237
251
|
if len(token) > 0:
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
252
|
+
if literal:
|
|
253
|
+
token += '\n'
|
|
254
|
+
else:
|
|
255
|
+
script.tokens.append(Token(lino, token))
|
|
256
|
+
token = ''
|
|
241
257
|
return
|
|
242
258
|
|
|
243
259
|
def finish(self):
|
easycoder/ec_renderer.py
CHANGED
|
@@ -24,6 +24,13 @@ class Element():
|
|
|
24
24
|
def getID(self):
|
|
25
25
|
return self.spec.id
|
|
26
26
|
|
|
27
|
+
def getRealPos(self):
|
|
28
|
+
spec = self.spec
|
|
29
|
+
pos = spec.realpos
|
|
30
|
+
if spec.parent != None:
|
|
31
|
+
pos = Vector(pos) + spec.parent.realpos
|
|
32
|
+
return pos
|
|
33
|
+
|
|
27
34
|
def getPos(self):
|
|
28
35
|
spec = self.spec
|
|
29
36
|
pos = spec.pos
|
|
@@ -32,13 +39,16 @@ class Element():
|
|
|
32
39
|
return pos
|
|
33
40
|
|
|
34
41
|
def setPos(self, pos):
|
|
35
|
-
self.spec.
|
|
42
|
+
self.spec.realpos = pos
|
|
36
43
|
self.spec.item.pos = pos
|
|
37
44
|
|
|
38
45
|
# Called when the parent moves
|
|
39
46
|
def repos(self):
|
|
40
47
|
spec = self.spec
|
|
41
|
-
spec.item.pos = Vector(spec.
|
|
48
|
+
spec.item.pos = Vector(spec.realpos) + spec.parent.realpos
|
|
49
|
+
|
|
50
|
+
def getRealSize(self):
|
|
51
|
+
return self.spec.realsize
|
|
42
52
|
|
|
43
53
|
def getSize(self):
|
|
44
54
|
return self.spec.size
|
|
@@ -68,6 +78,25 @@ class UI(Widget):
|
|
|
68
78
|
self.zlist.append(element)
|
|
69
79
|
|
|
70
80
|
def createElement(self, spec):
|
|
81
|
+
# Get a real position or size value
|
|
82
|
+
def getReal(val):
|
|
83
|
+
if isinstance(val, str):
|
|
84
|
+
c = val[-1]
|
|
85
|
+
if c in ['w', 'h']:
|
|
86
|
+
val = int(val[0:len(val)-1])
|
|
87
|
+
if spec.parent == None:
|
|
88
|
+
if c == 'w':
|
|
89
|
+
n = Window.width
|
|
90
|
+
else:
|
|
91
|
+
n = Window.height
|
|
92
|
+
else:
|
|
93
|
+
if c == 'w':
|
|
94
|
+
n = spec.parent.realsize[0]
|
|
95
|
+
else:
|
|
96
|
+
n = spec.parent.realsize[1]
|
|
97
|
+
return val * n / 100
|
|
98
|
+
return val
|
|
99
|
+
|
|
71
100
|
with self.canvas:
|
|
72
101
|
if hasattr(spec, 'fill'):
|
|
73
102
|
c = spec.fill
|
|
@@ -76,13 +105,16 @@ class UI(Widget):
|
|
|
76
105
|
Color(c[0], c[1], c[2])
|
|
77
106
|
else:
|
|
78
107
|
Color(c[0]/255, c[1]/255, c[2]/255)
|
|
79
|
-
pos = spec.pos
|
|
108
|
+
pos = (getReal(spec.pos[0]), getReal(spec.pos[1]))
|
|
109
|
+
spec.realpos = pos
|
|
110
|
+
size = (getReal(spec.size[0]), getReal(spec.size[1]))
|
|
111
|
+
spec.realsize = size
|
|
80
112
|
if spec.parent != None:
|
|
81
|
-
pos = Vector(pos) + spec.parent.
|
|
113
|
+
pos = Vector(pos) + spec.parent.realpos
|
|
82
114
|
if spec.type == 'ellipse':
|
|
83
|
-
item = Ellipse(pos=pos, size=
|
|
115
|
+
item = Ellipse(pos=pos, size=size)
|
|
84
116
|
elif spec.type == 'rectangle':
|
|
85
|
-
item = Rectangle(pos=pos, size=
|
|
117
|
+
item = Rectangle(pos=pos, size=size)
|
|
86
118
|
elif spec.type == 'text':
|
|
87
119
|
if hasattr(spec, 'color'):
|
|
88
120
|
c = spec.color
|
|
@@ -96,16 +128,16 @@ class UI(Widget):
|
|
|
96
128
|
label = CoreLabel(text=spec.text, font_size=1000, halign='center', valign='center')
|
|
97
129
|
label.refresh()
|
|
98
130
|
text = label.texture
|
|
99
|
-
item = Rectangle(pos=
|
|
131
|
+
item = Rectangle(pos=pos, size=size, texture=text)
|
|
100
132
|
elif spec.type == 'image':
|
|
101
|
-
item = AsyncImage(pos=
|
|
133
|
+
item = AsyncImage(pos=pos, size=size, source=spec.source)
|
|
102
134
|
spec.item = item
|
|
103
135
|
self.addElement(spec.id, spec)
|
|
104
136
|
|
|
105
137
|
def moveElementBy(self, id, dist):
|
|
106
138
|
element = self.getElement(id)
|
|
107
139
|
if element != None:
|
|
108
|
-
element.setPos(Vector(element.
|
|
140
|
+
element.setPos(Vector(element.getRealPos()) + dist)
|
|
109
141
|
for id in element.getChildren():
|
|
110
142
|
self.getElement(id).repos()
|
|
111
143
|
return
|
|
@@ -113,7 +145,7 @@ class UI(Widget):
|
|
|
113
145
|
def moveElementTo(self, id, pos):
|
|
114
146
|
element = self.getElement(id)
|
|
115
147
|
if element != None:
|
|
116
|
-
self.moveElementBy(id, Vector(pos) - element.
|
|
148
|
+
self.moveElementBy(id, Vector(pos) - element.getRealPos())
|
|
117
149
|
return
|
|
118
150
|
|
|
119
151
|
def on_touch_down(self, touch):
|
|
@@ -123,9 +155,9 @@ class UI(Widget):
|
|
|
123
155
|
for element in reversed(self.zlist):
|
|
124
156
|
if element.cb != None:
|
|
125
157
|
spec = element.spec
|
|
126
|
-
pos =
|
|
158
|
+
pos = self.getRealPos()
|
|
127
159
|
if spec.parent != None:
|
|
128
|
-
pos = Vector(pos) + spec.parent.
|
|
160
|
+
pos = Vector(pos) + spec.parent.getRealPos()
|
|
129
161
|
size = spec.size
|
|
130
162
|
if spec.type == 'ellipse':
|
|
131
163
|
a = size[0]/2
|
|
@@ -144,19 +176,47 @@ class UI(Widget):
|
|
|
144
176
|
def setOnClick(self, id, callback):
|
|
145
177
|
self.getElement(id).cb = callback
|
|
146
178
|
|
|
179
|
+
def getWindowAttribute(self, attribute):
|
|
180
|
+
if attribute == 'left':
|
|
181
|
+
return Window.left
|
|
182
|
+
elif attribute == 'top':
|
|
183
|
+
return Window.top
|
|
184
|
+
elif attribute == 'width':
|
|
185
|
+
return Window.size[0]
|
|
186
|
+
elif attribute == 'height':
|
|
187
|
+
return Window.size[1]
|
|
188
|
+
else:
|
|
189
|
+
raise Exception(f'Unknown attribute: {attribute}')
|
|
190
|
+
|
|
147
191
|
def getAttribute(self, id, attribute):
|
|
148
192
|
spec = self.getElement(id).spec
|
|
149
193
|
if attribute == 'left':
|
|
150
|
-
return spec.
|
|
194
|
+
return spec.realpos[0]
|
|
151
195
|
elif attribute == 'bottom':
|
|
152
|
-
return spec.
|
|
196
|
+
return spec.realpos[1]
|
|
153
197
|
elif attribute == 'width':
|
|
154
|
-
return spec.
|
|
198
|
+
return spec.realsize[0]
|
|
155
199
|
elif attribute == 'height':
|
|
156
|
-
return spec.
|
|
200
|
+
return spec.realsize[1]
|
|
201
|
+
else:
|
|
202
|
+
raise Exception(f'Unknown attribute: {attribute}')
|
|
203
|
+
|
|
204
|
+
def setAttribute(self, id, attribute, value):
|
|
205
|
+
spec = self.getElement(id).spec
|
|
206
|
+
if attribute == 'left':
|
|
207
|
+
spec.realpos = (value, spec.realsize[0])
|
|
208
|
+
spec.item.pos = (value, spec.realsize[0])
|
|
209
|
+
elif attribute == 'bottom':
|
|
210
|
+
spec.realpos = (spec.realsize[0], value)
|
|
211
|
+
spec.item.pos = (spec.realsize[0], value)
|
|
212
|
+
elif attribute == 'width':
|
|
213
|
+
spec.realsize = (value, spec.realsize[0])
|
|
214
|
+
spec.item.size = (value, spec.realsize[0])
|
|
215
|
+
elif attribute == 'height':
|
|
216
|
+
spec.realsize = (spec.realsize[0], value)
|
|
217
|
+
spec.item.size = (spec.realsize[0], value)
|
|
157
218
|
else:
|
|
158
219
|
raise Exception(f'Unknown attribute: {attribute}')
|
|
159
|
-
|
|
160
220
|
|
|
161
221
|
class Renderer(App):
|
|
162
222
|
|
|
@@ -171,7 +231,7 @@ class Renderer(App):
|
|
|
171
231
|
self.flush()
|
|
172
232
|
|
|
173
233
|
def build(self):
|
|
174
|
-
Clock.schedule_interval(self.flushQueue, 0.
|
|
234
|
+
Clock.schedule_interval(self.flushQueue, 0.01)
|
|
175
235
|
self.ui = UI()
|
|
176
236
|
return self.ui
|
|
177
237
|
|
easycoder/ec_screenspec.py
CHANGED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: easycoder
|
|
3
|
+
Version: 250102.1
|
|
4
|
+
Summary: Rapid scripting in English
|
|
5
|
+
Keywords: compiler,scripting,prototyping,programming,coding,python,low code,hypertalk,computer language,learn to code
|
|
6
|
+
Author-email: Graham Trott <gtanyware@gmail.com>
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Requires-Dist: pytz
|
|
10
|
+
Project-URL: Home, https://github.com/easycoder/easycoder-py
|
|
11
|
+
|
|
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 its runtime acts as a fairly thin wrapper around Python functions, giving good performance for general applications.
|
|
14
|
+
|
|
15
|
+
The JavaScript version of **_EasyCoder_**, which provides a full set of graphical features to run in a browser, is at
|
|
16
|
+
|
|
17
|
+
Repository: [https://github.com/easycoder/easycoder.github.io](https://github.com/easycoder/easycoder.github.io)
|
|
18
|
+
Website: [https://easycoder.github.io](https://easycoder.github.io)
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
Install **_EasyCoder_** in your Python environment:
|
|
22
|
+
```
|
|
23
|
+
pip install easycoder
|
|
24
|
+
```
|
|
25
|
+
Write a test script, 'hello.ecs', containing the following:
|
|
26
|
+
```
|
|
27
|
+
print `Hello, world!`
|
|
28
|
+
```
|
|
29
|
+
This is traditionally the first program to be written in virtually any language. To run it, use `easycoder hello.ecs`.
|
|
30
|
+
|
|
31
|
+
The output will look like this:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
EasyCoder version 250101.1
|
|
35
|
+
Compiled <anon>: 1 lines (2 tokens) in 0 ms
|
|
36
|
+
Run <anon>
|
|
37
|
+
1-> Hello, world!
|
|
38
|
+
```
|
|
39
|
+
It's conventional to add a program title to a script:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
! Test script
|
|
43
|
+
script Test
|
|
44
|
+
print `Hello, world!`
|
|
45
|
+
```
|
|
46
|
+
The first line here is just a comment and has no effect on the running of the script. The second line gives the script a name, which is useful in debugging as it says which script was running. When run, the output is now
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
EasyCoder version 250101.1
|
|
50
|
+
Compiled Test: 3 lines (4 tokens) in 0 ms
|
|
51
|
+
Run Test
|
|
52
|
+
3-> Hello, world!
|
|
53
|
+
```
|
|
54
|
+
As you might guess from the above, the print command shows the line in the script it was called from. This is very useful in tracking down debugging print commands in large scripts.
|
|
55
|
+
|
|
56
|
+
Here in the repository is a folder called `scripts` containing some sample scripts:
|
|
57
|
+
|
|
58
|
+
`fizzbuzz.ecs` is a simple programming challenge often given at job interviews
|
|
59
|
+
`tests.ecs` is a test program containing many of the **_EasyCoder_** features
|
|
60
|
+
`benchmark.ecs` allows the performance of **_EasyCoder_** to be compared to other languages if a similar script is written for each one.
|
|
61
|
+
|
|
62
|
+
## Graphical programmming
|
|
63
|
+
**_EasyCoder_** includes a graphical programming environment that is in the early stages of development. A couple of demo scripts are included in the `scripts` directory. To run them, first install the Python `kivy` graphics library if it's not already present on your system. This is done with `pip install kivy`. Then run your **_EasyCoder_** script using `easycoder {scriptname}.ecg`.
|
|
64
|
+
|
|
65
|
+
Graphical scripts look much like any other script but their file names must use the extension `.ecg` to signal to **_EasyCoder_** that it needs to load the graphics module. Non-graphical applications can use any extension but `.ecs` is recommended. This allows the **_EasyCoder_** application to be used wherever Python is installed, in either a command-line or a graphical environment, but graphics will of course not be available in the former.
|
|
66
|
+
|
|
67
|
+
A couple of demo graphical scripts are included in the `scripts` directory:
|
|
68
|
+
|
|
69
|
+
`graphics-demo.ecg` shows some of the elements that can be created, and demonstrates a variety of the graphical features of the language such as detecting when elements are clicked.
|
|
70
|
+
|
|
71
|
+
`wave.ecg` is a "Mexican Wave" simulation.
|
|
72
|
+
|
|
73
|
+
**_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
|
+
## Programming reference
|
|
76
|
+
|
|
77
|
+
**_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.
|
|
78
|
+
|
|
79
|
+
## Extending the language
|
|
80
|
+
|
|
81
|
+
**_EasyCoder_** can be extended to add new functionality with the use of 'plugins'. These contain compiler and runtime modules for the added language features. **_EasyCoder_** can use the added keywords, values and conditions freely; the effect is completely seamless. There is an outline example in the `plugins` directory called `example.py`, which comprises a module called `Points` with new language syntax to deal with two-valued items such as coordinates. In the `scripts` directory there is `points.ecs`, which exercises the new functionality.
|
|
82
|
+
|
|
83
|
+
A plugin can act as a wrapper around any Python functionality that has a sensible API, thereby hiding its complexity. The only challenge is to devise an unambiguous syntax that doesn't clash with anything already existing in **_EasyCoder_**.
|
|
84
|
+
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
easycoder/README.md,sha256=PYqOc_SkIGiFbyCNs90y7JqoqWe4aO1xYIW-6bOnFKU,573
|
|
2
|
+
easycoder/__init__.py,sha256=W4OVpn0u8D0l1986sfIOeYbyIh-u4cA3pN00Dd3iPTE,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=YGEEfnzPi8NQX-F7zWM-aic4FzDcAbuKalFQp0YIzKY,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-250102.1.dist-info/entry_points.txt,sha256=JXAZbenl0TnsIft2FcGJbJ-4qoztVu2FuT8PFmWFexM,44
|
|
16
|
+
easycoder-250102.1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
17
|
+
easycoder-250102.1.dist-info/WHEEL,sha256=ssQ84EZ5gH1pCOujd3iW7HClo_O_aDaClUbX4B8bjKY,100
|
|
18
|
+
easycoder-250102.1.dist-info/METADATA,sha256=Sq25qn0s0MFnqadz35dmOedro1p235uwVXPxHO-hXJE,5178
|
|
19
|
+
easycoder-250102.1.dist-info/RECORD,,
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.3
|
|
2
|
-
Name: easycoder
|
|
3
|
-
Version: 241227.1
|
|
4
|
-
Summary: Rapid scripting in English
|
|
5
|
-
Keywords: compiler,scripting,prototyping,programming,coding,python,low code,hypertalk,computer language,learn to code
|
|
6
|
-
Author-email: Graham Trott <gtanyware@gmail.com>
|
|
7
|
-
Description-Content-Type: text/markdown
|
|
8
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
-
Requires-Dist: pytz
|
|
10
|
-
Project-URL: Home, https://github.com/easycoder/easycoder-py
|
|
11
|
-
|
|
12
|
-
# Introduction
|
|
13
|
-
This is the Python version of **_EasyCoder_**, a high-level English-like scripting language suited for prototyping and rapid testing of ideas. It operates on the command line.
|
|
14
|
-
|
|
15
|
-
The JavaScript version of **_EasyCoder_**, which provides a full set of graphical features to run in a browser, is at
|
|
16
|
-
|
|
17
|
-
Repository: [https://github.com/easycoder/easycoder.github.io](https://github.com/easycoder/easycoder.github.io)
|
|
18
|
-
Website: [https://easycoder.github.io](https://easycoder.github.io)
|
|
19
|
-
|
|
20
|
-
## Quick Start
|
|
21
|
-
Install **_EasyCoder_** in your Python environment:
|
|
22
|
-
```
|
|
23
|
-
pip install easycoder
|
|
24
|
-
```
|
|
25
|
-
Write a test script, 'hello.ecs', containing the following:
|
|
26
|
-
```
|
|
27
|
-
print `Hello, world!`
|
|
28
|
-
```
|
|
29
|
-
This is traditionally the first program to be written in virtually any language. To run it, use `easycoder hello.ecs`.
|
|
30
|
-
|
|
31
|
-
The output will look like this:
|
|
32
|
-
|
|
33
|
-
```
|
|
34
|
-
EasyCoder version 5
|
|
35
|
-
Compiled <anon>: 1 lines (2 tokens) in 0 ms
|
|
36
|
-
Run <anon>
|
|
37
|
-
1-> Hello, world!
|
|
38
|
-
```
|
|
39
|
-
It's conventional to add a program title to a script:
|
|
40
|
-
|
|
41
|
-
```
|
|
42
|
-
! Test script
|
|
43
|
-
script Test
|
|
44
|
-
print `Hello, world!`
|
|
45
|
-
```
|
|
46
|
-
The first line here is just a comment and has no effect on the running of the script. The second line gives the script a name, which is useful in debugging as it says which script was running. When run, the output is now
|
|
47
|
-
|
|
48
|
-
```
|
|
49
|
-
EasyCoder version 5
|
|
50
|
-
Compiled Test: 5 lines (4 tokens) in 0 ms
|
|
51
|
-
Run Test
|
|
52
|
-
5-> Hello, world!
|
|
53
|
-
```
|
|
54
|
-
As you can guess from the above, the print command gives the line in the script it was called from. This is very useful in tracking down debugging print commands in large scripts.
|
|
55
|
-
|
|
56
|
-
Here in the repository is a folder called `scripts` containing some sample scripts:
|
|
57
|
-
|
|
58
|
-
`benchmark.ecs` allows the performance of EasyCoder to be compared to other languages if a similar program is written for each one
|
|
59
|
-
`tests.ecs` is a test program containing many of the EasyCoder features
|
|
60
|
-
`fizzbuzz.ecs` is a simple programming challenge often given at job interviews
|
|
61
|
-
|
|
62
|
-
## Graphical programmming
|
|
63
|
-
**_EasyCoder_** is currently being extended to include a graphical programming environment. A single demo script `graphics-demo.ecs` is included in the `scripts` directory. To run it, first install the Python graphics library if it's not already present on your system. On Linux this is done with `sudo apt install python3-tk`. On Windows it's `pip install tk`. Then give the command `easycoder -g scripts/graphics-demo.ecs`.
|
|
64
|
-
|
|
65
|
-
As development progresses this demo script will be extended to include new features as they are added. **_EasyCoder_** graphics are handled by a library module, `ec_renderer` that can be used outside of the **_EasyCoder_** environment, in other Python programs.
|
|
66
|
-
|
|
67
|
-
## EasyCoder programming reference
|
|
68
|
-
|
|
69
|
-
The language comprises a general-purpose core package, which can be enhanced by plugins to provide special features on demand.
|
|
70
|
-
|
|
71
|
-
[The core package](doc/README.md)
|
|
72
|
-
|
|
73
|
-
## Extending the language
|
|
74
|
-
|
|
75
|
-
**_EasyCoder_** can be extended to add new functionality with the use of 'plugins'. These contain compiler and runtime modules for the added language features. **_EasyCoder_** can use the added keywords, values and conditions freely; the effect is completely seamless. There is an outline example in the `plugins` directory called `example.py`, which comprises a module called `Points` with new language syntax to deal with two-valued items such as coordinates. In the `scripts` directory there is `points.ecs`, which exercises the new functionality.
|
|
76
|
-
|
|
77
|
-
A plugin can act as a wrapper around any Python functionality that has a sensible API, thereby hiding its complexity. The only challenge is to devise an unambiguous syntax that doesn't clash with anything already existing in **_EasyCoder_**.
|
|
78
|
-
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
easycoder/__init__.py,sha256=l4J8ZzYaQ2L6tojyFFqc47eck2zDXoR8sUqlCyvanBs,283
|
|
2
|
-
easycoder/ec.py,sha256=Nj5PRl8GsKjfGJKq0FOM1a7FeK3cN68CoIFg8lswQEg,221
|
|
3
|
-
easycoder/ec_classes.py,sha256=xnWBNak8oKydkFoxHLlq9wo3lIsB3aMnTDrqbtCfoWo,1512
|
|
4
|
-
easycoder/ec_compiler.py,sha256=2r6Nk7px9UMYqIpYc6dAbYOAFu-CoWPy-iqlsed49Lo,4690
|
|
5
|
-
easycoder/ec_condition.py,sha256=WSbONo4zs2sX1icOVpscZDFSCAEFmTsquoc2RGcLx_k,763
|
|
6
|
-
easycoder/ec_core.py,sha256=Q-E2TX_yn9OhdV6HvUzYgiKX9fEQ_ro1-VxSQ5Xl-4Y,76508
|
|
7
|
-
easycoder/ec_graphics.py,sha256=Sy1seMMEZ5KmkDKPhTKIkoGjXl5loYArvAS2YpdsFH8,13347
|
|
8
|
-
easycoder/ec_handler.py,sha256=IJvxcrJJSR53d6DS_8H5qPHKhp9y5-GV4WXAjhZxu_o,2250
|
|
9
|
-
easycoder/ec_program.py,sha256=j3eveYucPQX6E1flDwf1OpkPCh9OtDri88z8baXjvqI,8062
|
|
10
|
-
easycoder/ec_renderer.py,sha256=UZk-VSyN4But0fRTs7wUnPwRGrCF6XA7LxhPxgZaYgU,5705
|
|
11
|
-
easycoder/ec_screenspec.py,sha256=gmYYi0Q6S2qSQzCW0lMPB61EC7ZZ1mNQX8B1knxrTCg,2525
|
|
12
|
-
easycoder/ec_timestamp.py,sha256=_3QFJPzIWZ9Rzk3SQOQJ-gwmvB07pg78k23SPntoZtY,288
|
|
13
|
-
easycoder/ec_value.py,sha256=XIBtGhcCgh1abrzAn-Wy4l_xH_3cTWakMVIiSlBAZjM,2386
|
|
14
|
-
easycoder-241227.1.dist-info/entry_points.txt,sha256=JXAZbenl0TnsIft2FcGJbJ-4qoztVu2FuT8PFmWFexM,44
|
|
15
|
-
easycoder-241227.1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
16
|
-
easycoder-241227.1.dist-info/WHEEL,sha256=ssQ84EZ5gH1pCOujd3iW7HClo_O_aDaClUbX4B8bjKY,100
|
|
17
|
-
easycoder-241227.1.dist-info/METADATA,sha256=-1vKmMw26mJSHmztn_O049rpIJqAgJ4OQWPC-lDO9ms,4098
|
|
18
|
-
easycoder-241227.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|