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 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
@@ -10,4 +10,4 @@ from .ec_program import *
10
10
  from .ec_timestamp import *
11
11
  from .ec_value import *
12
12
 
13
- __version__ = "241227.1"
13
+ __version__ = "250102.1"
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
- if token == 'property':
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
- if token == 'element':
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
- if cmdType == 'elements':
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
- if cmdType == 'element':
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
- if cmdType == 'property':
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'] = 'core'
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', 'break', 'empty']:
1482
+ if token in ['now', 'today', 'newline', 'tab', 'empty']:
1450
1483
  return value
1451
1484
 
1452
- if token in ['date', 'encode', 'decode', 'stringify', 'json', 'lowercase', 'uppercase', 'hash', 'random', 'float', 'integer']:
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['value1'] = self.getValue()
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
- if self.nextIs('of'):
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
- value['content'] = self.program.decode(v['content'])
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
- value['content'] = self.program.encode(v['content'])
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 v_stringify(self, v):
1770
- item = self.getRuntimeValue(v['content'])
1821
+ def v_files(self, v):
1822
+ v = self.getRuntimeValue(v['target'])
1771
1823
  value = {}
1772
1824
  value['type'] = 'text'
1773
- value['content'] = json.dumps(item)
1825
+ value['content'] = os.listdir(v)
1774
1826
  return value
1775
1827
 
1776
- def v_json(self, v):
1777
- item = self.getRuntimeValue(v['content'])
1828
+ def v_float(self, v):
1829
+ val = self.getRuntimeValue(v['content'])
1778
1830
  value = {}
1779
- value['type'] = 'object'
1831
+ value['type'] = 'float'
1780
1832
  try:
1781
- value['content'] = json.loads(item)
1833
+ value['content'] = float(val)
1782
1834
  except:
1783
- RuntimeError(self.program, 'Cannot encode value')
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
- value1 = v['value1']
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
- try:
1828
- index = target['value'].index(value1)
1829
- except:
1830
- index = -1
1831
- value = {}
1832
- value['type'] = 'int'
1833
- value['content'] = index
1834
- return value
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 v_uppercase(self, v):
1874
- content = self.getRuntimeValue(v['content'])
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'] = 'text'
1877
- value['content'] = content.upper()
1935
+ value['type'] = 'float'
1936
+ value['content'] = megabytes
1878
1937
  return value
1879
1938
 
1880
- def v_random(self, v):
1881
- limit = self.getRuntimeValue(v['content'])
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'] = randrange(0, limit)
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 v_tan(self, v):
1951
- angle = self.getRuntimeValue(v['angle'])
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'] = 'int'
1975
- value['content'] = int(datetime.combine(datetime.now().date(),datetime.min.time()).timestamp())*1000
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 v_valueOf(self, v):
1995
- v = self.getRuntimeValue(v['content'])
2040
+ def v_tab(self, v):
1996
2041
  value = {}
1997
- value['type'] = 'int'
1998
- value['content'] = int(v)
2042
+ value['type'] = 'text'
2043
+ value['content'] = '\t'
1999
2044
  return value
2000
2045
 
2001
- def v_files(self, v):
2002
- v = self.getRuntimeValue(v['target'])
2046
+ def v_tan(self, v):
2047
+ angle = self.getRuntimeValue(v['angle'])
2048
+ radius = self.getRuntimeValue(v['radius'])
2003
2049
  value = {}
2004
- value['type'] = 'text'
2005
- value['content'] = os.listdir(v)
2050
+ value['type'] = 'int'
2051
+ value['content'] = round(math.tan(angle * 0.01745329) * radius)
2006
2052
  return value
2007
2053
 
2008
- def v_trim(self, v):
2009
- v = self.getRuntimeValue(v['content'])
2054
+ def v_timestamp(self, v):
2010
2055
  value = {}
2011
- value['type'] = 'text'
2012
- value['content'] = v.strip()
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 v_weekday(self, v):
2068
+ def v_today(self, v):
2016
2069
  value = {}
2017
2070
  value['type'] = 'int'
2018
- value['content'] = datetime.today().weekday()
2071
+ value['content'] = int(datetime.combine(datetime.now().date(),datetime.min.time()).timestamp())*1000
2019
2072
  return value
2020
2073
 
2021
- def v_memory(self, v):
2022
- process: Process = Process(os.getpid())
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'] = 'float'
2026
- value['content'] = megabytes
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 v_modification(self, v):
2048
- fileName = self.getRuntimeValue(v['fileName'])
2049
- ts = int(os.stat(fileName).st_mtime)
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'] = ts
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 'kivy'
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
- ScreenSpec().render(self.getRuntimeValue(command['spec']), self.ui)
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('attribute'):
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
- index = 0
204
- lino = 0
205
- for line in script.lines:
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
- token = ''
208
- inSpace = True
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 len(c.strip()) == 0:
213
- if (inSpace):
214
- n += 1
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
- script.tokens.append(Token(lino, token))
217
- index += 1
218
- token = ''
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
- m = n
225
- n += 1
226
- while n < len(line) - 1:
227
- if line[n] == '`':
228
- break
229
- n += 1
230
- # n += 1
231
- token = line[m:n+1]
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
- script.tokens.append(Token(lino, token))
239
- index += 1
240
- lino += 1
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.pos = pos
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.pos) + spec.parent.pos
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.pos
113
+ pos = Vector(pos) + spec.parent.realpos
82
114
  if spec.type == 'ellipse':
83
- item = Ellipse(pos=pos, size=spec.size)
115
+ item = Ellipse(pos=pos, size=size)
84
116
  elif spec.type == 'rectangle':
85
- item = Rectangle(pos=pos, size=spec.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=spec.pos, size=spec.size, texture=text)
131
+ item = Rectangle(pos=pos, size=size, texture=text)
100
132
  elif spec.type == 'image':
101
- item = AsyncImage(pos=spec.pos, size=spec.size, source=spec.source)
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.getPos()) + dist)
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.getPos())
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 = spec.pos
158
+ pos = self.getRealPos()
127
159
  if spec.parent != None:
128
- pos = Vector(pos) + spec.parent.pos
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.pos[0]
194
+ return spec.realpos[0]
151
195
  elif attribute == 'bottom':
152
- return spec.pos[1]
196
+ return spec.realpos[1]
153
197
  elif attribute == 'width':
154
- return spec.size[0]
198
+ return spec.realsize[0]
155
199
  elif attribute == 'height':
156
- return spec.size[1]
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.05)
234
+ Clock.schedule_interval(self.flushQueue, 0.01)
175
235
  self.ui = UI()
176
236
  return self.ui
177
237
 
@@ -75,4 +75,3 @@ class ScreenSpec():
75
75
 
76
76
  else:
77
77
  raise Exception('Spec is an unknown type')
78
-
@@ -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,,