easycoder 241211.2__py2.py3-none-any.whl → 250116.1__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of easycoder might be problematic. Click here for more details.
- easycoder/README.md +6 -0
- easycoder/__init__.py +1 -1
- easycoder/ec_classes.py +8 -2
- easycoder/ec_compiler.py +10 -6
- easycoder/ec_core.py +493 -208
- easycoder/ec_graphics.py +326 -0
- easycoder/ec_gutils.py +52 -0
- easycoder/ec_handler.py +1 -0
- easycoder/ec_program.py +156 -79
- easycoder/ec_value.py +21 -14
- easycoder-250116.1.dist-info/METADATA +102 -0
- easycoder-250116.1.dist-info/RECORD +17 -0
- {easycoder-241211.2.dist-info → easycoder-250116.1.dist-info}/WHEEL +1 -1
- easycoder-241211.2.dist-info/METADATA +0 -71
- easycoder-241211.2.dist-info/RECORD +0 -14
- {easycoder-241211.2.dist-info → easycoder-250116.1.dist-info}/LICENSE +0 -0
- {easycoder-241211.2.dist-info → easycoder-250116.1.dist-info}/entry_points.txt +0 -0
easycoder/ec_program.py
CHANGED
|
@@ -1,29 +1,38 @@
|
|
|
1
1
|
import time, json, sys
|
|
2
2
|
from copy import deepcopy
|
|
3
3
|
from collections import deque
|
|
4
|
-
from .ec_classes import Script, Token, FatalError, RuntimeError
|
|
4
|
+
from .ec_classes import Script, Token, FatalError, RuntimeError, Object
|
|
5
5
|
from .ec_compiler import Compiler
|
|
6
6
|
from .ec_core import Core
|
|
7
7
|
import importlib
|
|
8
8
|
from importlib.metadata import version
|
|
9
9
|
|
|
10
|
+
# Flush the queue
|
|
11
|
+
def flush():
|
|
12
|
+
global queue
|
|
13
|
+
while len(queue):
|
|
14
|
+
item = queue.popleft()
|
|
15
|
+
item.program.flush(item.pc)
|
|
16
|
+
|
|
10
17
|
class Program:
|
|
11
18
|
|
|
12
19
|
def __init__(self, argv):
|
|
20
|
+
global queue
|
|
13
21
|
print(f'EasyCoder version {version("easycoder")}')
|
|
14
|
-
|
|
15
|
-
if len(argv)>0:
|
|
16
|
-
scriptName = argv[0]
|
|
17
|
-
else:
|
|
22
|
+
if len(argv) == 0:
|
|
18
23
|
print('No script supplied')
|
|
19
|
-
exit()
|
|
24
|
+
exit()
|
|
25
|
+
self.classes=[Core]
|
|
26
|
+
scriptName = argv
|
|
27
|
+
if scriptName.endswith('.ecg'):
|
|
28
|
+
from .ec_graphics import Graphics
|
|
29
|
+
self.classes.append(Graphics)
|
|
20
30
|
|
|
21
|
-
# print('Domains:',domains)
|
|
22
31
|
f = open(scriptName, 'r')
|
|
23
32
|
source = f.read()
|
|
24
33
|
f.close()
|
|
34
|
+
queue = deque()
|
|
25
35
|
self.argv = argv
|
|
26
|
-
self.classes=[Core]
|
|
27
36
|
self.domains = []
|
|
28
37
|
self.domainIndex = {}
|
|
29
38
|
self.name = '<anon>'
|
|
@@ -38,8 +47,14 @@ class Program:
|
|
|
38
47
|
self.value = self.compiler.value
|
|
39
48
|
self.condition = self.compiler.condition
|
|
40
49
|
self.processClasses()
|
|
41
|
-
self.
|
|
50
|
+
self.externalControl = False
|
|
51
|
+
self.running = True
|
|
42
52
|
|
|
53
|
+
def start(self, parent=None, module = None, exports=[]):
|
|
54
|
+
self.parent = parent
|
|
55
|
+
self.exports = exports
|
|
56
|
+
if module != None:
|
|
57
|
+
module['child'] = self
|
|
43
58
|
startCompile = time.time()
|
|
44
59
|
self.tokenise(self.script)
|
|
45
60
|
if self.compiler.compileFrom(0, []):
|
|
@@ -57,13 +72,24 @@ class Program:
|
|
|
57
72
|
self.run(0)
|
|
58
73
|
else:
|
|
59
74
|
self.compiler.showWarnings()
|
|
60
|
-
|
|
75
|
+
|
|
76
|
+
# If this is the main script and there's no graphics, run a main loop
|
|
77
|
+
if parent == None and self.externalControl == False:
|
|
78
|
+
while True:
|
|
79
|
+
if self.running == True:
|
|
80
|
+
flush()
|
|
81
|
+
time.sleep(0.1)
|
|
82
|
+
else:
|
|
83
|
+
break
|
|
61
84
|
|
|
62
85
|
# Import a plugin
|
|
63
86
|
def importPlugin(self, source):
|
|
64
87
|
args=source.split(':')
|
|
88
|
+
if len(args)<2:
|
|
89
|
+
RuntimeError(None, f'Invalid plugin spec "{source}"')
|
|
65
90
|
idx=args[0].rfind('/')
|
|
66
91
|
if idx<0:
|
|
92
|
+
sys.path.append('.')
|
|
67
93
|
module=args[0]
|
|
68
94
|
else:
|
|
69
95
|
sys.path.append(args[0][0:idx])
|
|
@@ -81,7 +107,7 @@ class Program:
|
|
|
81
107
|
handler = clazz(self.compiler)
|
|
82
108
|
self.domains.append(handler)
|
|
83
109
|
self.domainIndex[handler.getName()] = handler
|
|
84
|
-
|
|
110
|
+
|
|
85
111
|
# Get the domain list
|
|
86
112
|
def getDomains(self):
|
|
87
113
|
return self.domains
|
|
@@ -93,11 +119,11 @@ class Program:
|
|
|
93
119
|
def getSymbolRecord(self, name):
|
|
94
120
|
try:
|
|
95
121
|
target = self.code[self.symbols[name]]
|
|
122
|
+
if target['import'] != None:
|
|
123
|
+
target = target['import']
|
|
124
|
+
return target
|
|
96
125
|
except:
|
|
97
|
-
RuntimeError(self
|
|
98
|
-
return None
|
|
99
|
-
|
|
100
|
-
return target
|
|
126
|
+
RuntimeError(self, f'Unknown symbol \'{name}\'')
|
|
101
127
|
|
|
102
128
|
def doValue(self, value):
|
|
103
129
|
if value == None:
|
|
@@ -124,7 +150,7 @@ class Program:
|
|
|
124
150
|
name = value['name']
|
|
125
151
|
symbolRecord = self.getSymbolRecord(name)
|
|
126
152
|
if symbolRecord['value'] == [None]:
|
|
127
|
-
RuntimeWarning(self.
|
|
153
|
+
RuntimeWarning(self.program, f'Variable "{name}" has no value')
|
|
128
154
|
return None
|
|
129
155
|
handler = self.domainIndex[symbolRecord['domain']].valueHandler('symbol')
|
|
130
156
|
result = handler(symbolRecord)
|
|
@@ -179,6 +205,9 @@ class Program:
|
|
|
179
205
|
return copy
|
|
180
206
|
|
|
181
207
|
def putSymbolValue(self, symbolRecord, value):
|
|
208
|
+
if symbolRecord['locked']:
|
|
209
|
+
name = symbolRecord['name']
|
|
210
|
+
RuntimeError(self, f'Symbol "{name}" is locked')
|
|
182
211
|
if symbolRecord['value'] == None or symbolRecord['value'] == []:
|
|
183
212
|
symbolRecord['value'] = [value]
|
|
184
213
|
else:
|
|
@@ -195,80 +224,115 @@ class Program:
|
|
|
195
224
|
|
|
196
225
|
# Tokenise the script
|
|
197
226
|
def tokenise(self, script):
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
for
|
|
227
|
+
token = ''
|
|
228
|
+
literal = False
|
|
229
|
+
for lino in range(0, len(script.lines)):
|
|
230
|
+
line = script.lines[lino]
|
|
201
231
|
length = len(line)
|
|
202
|
-
|
|
203
|
-
|
|
232
|
+
if length == 0:
|
|
233
|
+
continue
|
|
234
|
+
# Look for the first non-space
|
|
204
235
|
n = 0
|
|
205
|
-
while n < length:
|
|
236
|
+
while n < length and line[n].isspace():
|
|
237
|
+
n += 1
|
|
238
|
+
# The whole line may be empty
|
|
239
|
+
if n == length:
|
|
240
|
+
if literal:
|
|
241
|
+
token += '\n'
|
|
242
|
+
continue
|
|
243
|
+
# If in an unfinished literal, the first char must be a backtick to continue adding to it
|
|
244
|
+
if literal:
|
|
245
|
+
if line[n] != '`':
|
|
246
|
+
# Close the current token
|
|
247
|
+
if len(token) > 0:
|
|
248
|
+
script.tokens.append(Token(lino, token))
|
|
249
|
+
token = ''
|
|
250
|
+
literal = False
|
|
251
|
+
n += 1
|
|
252
|
+
for n in range(n, length):
|
|
206
253
|
c = line[n]
|
|
207
|
-
if
|
|
208
|
-
|
|
209
|
-
|
|
254
|
+
# Test if we are in a literal
|
|
255
|
+
if not literal:
|
|
256
|
+
if c.isspace():
|
|
257
|
+
if len(token) > 0:
|
|
258
|
+
script.tokens.append(Token(lino, token))
|
|
259
|
+
token = ''
|
|
210
260
|
continue
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
inSpace = True
|
|
215
|
-
n += 1
|
|
216
|
-
continue
|
|
217
|
-
inSpace = False
|
|
261
|
+
elif c == '!':
|
|
262
|
+
break
|
|
263
|
+
# Test for the start or end of a literal
|
|
218
264
|
if c == '`':
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
elif c == '!':
|
|
228
|
-
break
|
|
265
|
+
if literal:
|
|
266
|
+
token += c
|
|
267
|
+
literal = False
|
|
268
|
+
else:
|
|
269
|
+
token += c
|
|
270
|
+
literal = True
|
|
271
|
+
m = n
|
|
272
|
+
continue
|
|
229
273
|
else:
|
|
230
274
|
token += c
|
|
231
|
-
n += 1
|
|
232
275
|
if len(token) > 0:
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
276
|
+
if literal:
|
|
277
|
+
token += '\n'
|
|
278
|
+
else:
|
|
279
|
+
script.tokens.append(Token(lino, token))
|
|
280
|
+
token = ''
|
|
236
281
|
return
|
|
237
282
|
|
|
283
|
+
def releaseParent(self):
|
|
284
|
+
if self.parent.waiting and self.parent.program.running:
|
|
285
|
+
self.parent.waiting = False
|
|
286
|
+
self.parent.program.run(self.parent.pc)
|
|
287
|
+
|
|
288
|
+
def flushCB(self):
|
|
289
|
+
flush()
|
|
290
|
+
|
|
291
|
+
# Flush the queue
|
|
292
|
+
def flush(self, pc):
|
|
293
|
+
global queue
|
|
294
|
+
self.pc = pc
|
|
295
|
+
while self.running:
|
|
296
|
+
command = self.code[self.pc]
|
|
297
|
+
domainName = command['domain']
|
|
298
|
+
if domainName == None:
|
|
299
|
+
self.pc += 1
|
|
300
|
+
else:
|
|
301
|
+
keyword = command['keyword']
|
|
302
|
+
if self.debugStep and command['debug']:
|
|
303
|
+
lino = command['lino'] + 1
|
|
304
|
+
line = self.script.lines[command['lino']].strip()
|
|
305
|
+
print(f'{self.name}: Line {lino}: {domainName}:{keyword}: {line}')
|
|
306
|
+
domain = self.domainIndex[domainName]
|
|
307
|
+
handler = domain.runHandler(keyword)
|
|
308
|
+
if handler:
|
|
309
|
+
command = self.code[self.pc]
|
|
310
|
+
command['program'] = self
|
|
311
|
+
self.pc = handler(command)
|
|
312
|
+
# Deal with 'exit'
|
|
313
|
+
if self.pc == -1:
|
|
314
|
+
queue = deque()
|
|
315
|
+
if self.parent != None:
|
|
316
|
+
self.releaseParent()
|
|
317
|
+
else:
|
|
318
|
+
self.running = False
|
|
319
|
+
break
|
|
320
|
+
elif self.pc == None or self.pc == 0 or self.pc >= len(self.code):
|
|
321
|
+
break
|
|
322
|
+
|
|
238
323
|
# Run the script
|
|
239
324
|
def run(self, pc):
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
self
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
if domainName == None:
|
|
252
|
-
self.pc += 1
|
|
253
|
-
else:
|
|
254
|
-
keyword = command['keyword']
|
|
255
|
-
if self.debugStep and command['debug']:
|
|
256
|
-
lino = command['lino'] + 1
|
|
257
|
-
line = self.script.lines[command['lino']].strip()
|
|
258
|
-
print(f'{self.name}: Line {lino}: {domainName}:{keyword}: {line}')
|
|
259
|
-
domain = self.domainIndex[domainName]
|
|
260
|
-
handler = domain.runHandler(keyword)
|
|
261
|
-
if handler:
|
|
262
|
-
command = self.code[self.pc]
|
|
263
|
-
command['program'] = self
|
|
264
|
-
self.pc = handler(command)
|
|
265
|
-
try:
|
|
266
|
-
if self.pc == 0 or self.pc >= len(self.code):
|
|
267
|
-
return 0
|
|
268
|
-
except:
|
|
269
|
-
return 0
|
|
270
|
-
if self.pc < 0:
|
|
271
|
-
return -1
|
|
325
|
+
global queue
|
|
326
|
+
item = Object()
|
|
327
|
+
item.program = self
|
|
328
|
+
item.pc = pc
|
|
329
|
+
queue.append(item)
|
|
330
|
+
|
|
331
|
+
def kill(self):
|
|
332
|
+
self.running = False
|
|
333
|
+
|
|
334
|
+
def setExternalControl(self):
|
|
335
|
+
self.externalControl = True
|
|
272
336
|
|
|
273
337
|
def nonNumericValueError(self):
|
|
274
338
|
FatalError(self.compiler, 'Non-numeric value')
|
|
@@ -315,9 +379,22 @@ class Program:
|
|
|
315
379
|
return -1
|
|
316
380
|
return 0
|
|
317
381
|
|
|
382
|
+
# Set up a message handler
|
|
383
|
+
def onMessage(self, pc):
|
|
384
|
+
self.onMessagePC = pc
|
|
385
|
+
|
|
386
|
+
# Handle a message from our parent program
|
|
387
|
+
def handleMessage(self, message):
|
|
388
|
+
self.message = message
|
|
389
|
+
self.run(self.onMessagePC)
|
|
390
|
+
|
|
318
391
|
# This is the program launcher
|
|
319
392
|
def Main():
|
|
320
393
|
if (len(sys.argv) > 1):
|
|
321
|
-
Program(sys.argv[1
|
|
394
|
+
Program(sys.argv[1]).start()
|
|
322
395
|
else:
|
|
323
396
|
print('Syntax: easycoder <scriptname> [plugins]')
|
|
397
|
+
|
|
398
|
+
if __name__ == '__main__':
|
|
399
|
+
Main()
|
|
400
|
+
|
easycoder/ec_value.py
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
from .ec_classes import FatalError
|
|
2
2
|
|
|
3
|
+
# Create a constant
|
|
4
|
+
def getConstant(str):
|
|
5
|
+
value = {}
|
|
6
|
+
value['type'] = 'text'
|
|
7
|
+
value['content'] = str
|
|
8
|
+
return value
|
|
9
|
+
|
|
3
10
|
class Value:
|
|
4
11
|
|
|
5
12
|
def __init__(self, compiler):
|
|
@@ -15,7 +22,7 @@ class Value:
|
|
|
15
22
|
return None
|
|
16
23
|
|
|
17
24
|
value = {}
|
|
18
|
-
|
|
25
|
+
|
|
19
26
|
if token == 'true':
|
|
20
27
|
value['type'] = 'boolean'
|
|
21
28
|
value['content'] = True
|
|
@@ -51,14 +58,14 @@ class Value:
|
|
|
51
58
|
if item != None:
|
|
52
59
|
return item
|
|
53
60
|
self.compiler.rewindTo(mark)
|
|
54
|
-
|
|
61
|
+
# self.compiler.warning(f'I don\'t understand \'{token}\'')
|
|
55
62
|
return None
|
|
56
63
|
|
|
57
64
|
def compileValue(self):
|
|
58
65
|
token = self.getToken()
|
|
59
66
|
item = self.getItem()
|
|
60
67
|
if item == None:
|
|
61
|
-
|
|
68
|
+
self.compiler.warning(f'ec_value.compileValue: Cannot get the value of "{token}"')
|
|
62
69
|
return None
|
|
63
70
|
|
|
64
71
|
value = {}
|
|
@@ -80,19 +87,19 @@ class Value:
|
|
|
80
87
|
value = domain.modifyValue(value)
|
|
81
88
|
|
|
82
89
|
return value
|
|
83
|
-
|
|
90
|
+
|
|
84
91
|
def compileConstant(self, token):
|
|
85
92
|
value = {}
|
|
86
|
-
if token
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
93
|
+
if type(token) == 'str':
|
|
94
|
+
token = eval(token)
|
|
95
|
+
if isinstance(token, int):
|
|
96
|
+
value['type'] = 'int'
|
|
97
|
+
value['content'] = token
|
|
98
|
+
return value
|
|
99
|
+
if isinstance(token, float):
|
|
100
|
+
value['type'] = 'float'
|
|
101
|
+
value['content'] = token
|
|
102
|
+
return value
|
|
96
103
|
value['type'] = 'text'
|
|
97
104
|
value['content'] = token
|
|
98
105
|
return value
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: easycoder
|
|
3
|
+
Version: 250116.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 it acts as a fairly thin wrapper around Python functions, giving fast compilation and good runtime performance for general applications.
|
|
14
|
+
<hr>
|
|
15
|
+
|
|
16
|
+
There is also a JavaScript version of **_EasyCoder_**, which provides a full set of graphical features to run in a browser. For this, please visit
|
|
17
|
+
|
|
18
|
+
Repository: [https://github.com/easycoder/easycoder.github.io](https://github.com/easycoder/easycoder.github.io)
|
|
19
|
+
Website: [https://easycoder.github.io](https://easycoder.github.io)
|
|
20
|
+
<hr>
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
Install **_EasyCoder_** in your Python environment:
|
|
24
|
+
```
|
|
25
|
+
pip install easycoder
|
|
26
|
+
```
|
|
27
|
+
You may also need to install `pytz`, as some commands need it.
|
|
28
|
+
|
|
29
|
+
Write a test script, 'hello.ecs', containing the following:
|
|
30
|
+
```
|
|
31
|
+
print `Hello, world!`
|
|
32
|
+
```
|
|
33
|
+
This is traditionally the first program to be written in virtually any language. To run it, use `easycoder hello.ecs`.
|
|
34
|
+
|
|
35
|
+
The output will look like this (the version number will differ):
|
|
36
|
+
```
|
|
37
|
+
EasyCoder version 250101.1
|
|
38
|
+
Compiled <anon>: 1 lines (2 tokens) in 0 ms
|
|
39
|
+
Run <anon>
|
|
40
|
+
1-> Hello, world!
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
It's conventional to add a program title to a script:
|
|
44
|
+
```
|
|
45
|
+
! Test script
|
|
46
|
+
script Test
|
|
47
|
+
print `Hello, world!`
|
|
48
|
+
```
|
|
49
|
+
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
|
|
50
|
+
```
|
|
51
|
+
EasyCoder version 250101.1
|
|
52
|
+
Compiled Test: 3 lines (4 tokens) in 0 ms
|
|
53
|
+
Run Test
|
|
54
|
+
3-> Hello, world!
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
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.
|
|
58
|
+
|
|
59
|
+
Here in the repository is a folder called `scripts` containing some sample scripts:
|
|
60
|
+
|
|
61
|
+
`fizzbuzz.ecs` is a simple programming challenge often given at job interviews
|
|
62
|
+
`tests.ecs` is a test program containing many of the **_EasyCoder_** features
|
|
63
|
+
`benchmark.ecs` allows the performance of **_EasyCoder_** to be compared to other languages if a similar script is written for each one.
|
|
64
|
+
|
|
65
|
+
## Graphical programmming
|
|
66
|
+
**_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`.
|
|
67
|
+
|
|
68
|
+
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.
|
|
69
|
+
|
|
70
|
+
Some demo graphical scripts are included in the `scripts` directory:
|
|
71
|
+
|
|
72
|
+
`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.
|
|
73
|
+
|
|
74
|
+
`wave.ecg` is a "Mexican Wave" simulation.
|
|
75
|
+
|
|
76
|
+
`keyboard.ecg` creates an on-screen keyboard (currently a 4-function calculator keypad) that responds to clicks on its keys. It uses a plugin module (see below) to add extra vocabulary and syntax to the language. This is currently under development so its features are likely to change. The intention is to support a wide range of keyboard styles with the minimum mount of coding. The plugin (`ec_keyword.py`) can be downloaded from the repository.
|
|
77
|
+
|
|
78
|
+
**_EasyCoder_** graphics are handled by a library module, `ec_renderer` that can be used outside of the **_EasyCoder_** environment, in other Python programs. The renderer works with JSON-formatted specifications of the itens to be displayed.
|
|
79
|
+
|
|
80
|
+
## Significant features
|
|
81
|
+
|
|
82
|
+
- English-like syntax based on vocabulary rather than structure. Scripts can be read as English
|
|
83
|
+
- Comprehensive feature set
|
|
84
|
+
- Runs directly from source scripts. A fast compiler creates efficient intermediate code that runs immediately after compilation
|
|
85
|
+
- Low memory requirements
|
|
86
|
+
- Minimim dependency on other 3rd-party packages
|
|
87
|
+
- Built-in co-operative multitasking
|
|
88
|
+
- Dynamic loading of scripts on demand
|
|
89
|
+
- The language can be extended seamlessly using plugin function modules
|
|
90
|
+
- Plays well with any Python code
|
|
91
|
+
- Fully Open Source
|
|
92
|
+
|
|
93
|
+
## Programming reference
|
|
94
|
+
|
|
95
|
+
**_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.
|
|
96
|
+
|
|
97
|
+
## Extending the language
|
|
98
|
+
|
|
99
|
+
**_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.
|
|
100
|
+
|
|
101
|
+
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_**.
|
|
102
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
easycoder/README.md,sha256=PYqOc_SkIGiFbyCNs90y7JqoqWe4aO1xYIW-6bOnFKU,573
|
|
2
|
+
easycoder/__init__.py,sha256=6tfI5jOPMiZDuD7BsvqLihJFFijWgyIr-EKAapPxT-s,262
|
|
3
|
+
easycoder/ec_classes.py,sha256=xnWBNak8oKydkFoxHLlq9wo3lIsB3aMnTDrqbtCfoWo,1512
|
|
4
|
+
easycoder/ec_compiler.py,sha256=f3zZRtbNsegBuRHTvTLK8BOdnuRq5p_p-1vtJYb-LiY,4800
|
|
5
|
+
easycoder/ec_condition.py,sha256=WSbONo4zs2sX1icOVpscZDFSCAEFmTsquoc2RGcLx_k,763
|
|
6
|
+
easycoder/ec_core.py,sha256=yO7d5OyEFHBDGKSaC1Fhf1uGjzsttAl6VCvR1W5X5YE,86279
|
|
7
|
+
easycoder/ec_graphics.py,sha256=R1LVI-heohCM_uNwHas8VuTIOdxtT6-RMjhca_B5l4Q,11335
|
|
8
|
+
easycoder/ec_gutils.py,sha256=fqh0VKfm2ry5yjHoOE1ufF7uu741lOU7EEwTUEabJ4k,1624
|
|
9
|
+
easycoder/ec_handler.py,sha256=IJvxcrJJSR53d6DS_8H5qPHKhp9y5-GV4WXAjhZxu_o,2250
|
|
10
|
+
easycoder/ec_program.py,sha256=wU-vWRWAYK2Ie4EFnp8HeSPUL0bxz-j9HLQSNplObcc,9919
|
|
11
|
+
easycoder/ec_timestamp.py,sha256=_3QFJPzIWZ9Rzk3SQOQJ-gwmvB07pg78k23SPntoZtY,288
|
|
12
|
+
easycoder/ec_value.py,sha256=zgDJTJhIg3yOvmnnKIfccIizmIhGbtvL_ghLTL1T5fg,2516
|
|
13
|
+
easycoder-250116.1.dist-info/entry_points.txt,sha256=JXAZbenl0TnsIft2FcGJbJ-4qoztVu2FuT8PFmWFexM,44
|
|
14
|
+
easycoder-250116.1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
15
|
+
easycoder-250116.1.dist-info/WHEEL,sha256=Sgu64hAMa6g5FdzHxXv9Xdse9yxpGGMeagVtPMWpJQY,99
|
|
16
|
+
easycoder-250116.1.dist-info/METADATA,sha256=L9ZijU5ykpK7eHLHghThRQcJ_xqxM3BKQfsLn1kcDAo,6426
|
|
17
|
+
easycoder-250116.1.dist-info/RECORD,,
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.3
|
|
2
|
-
Name: easycoder
|
|
3
|
-
Version: 241211.2
|
|
4
|
-
Summary: EasyCoder for Python
|
|
5
|
-
Author-email: Graham Trott <gtanyware@gmail.com>
|
|
6
|
-
Description-Content-Type: text/markdown
|
|
7
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
8
|
-
Requires-Dist: pytz
|
|
9
|
-
Project-URL: Home, https://github.com/easycoder
|
|
10
|
-
|
|
11
|
-
# Introduction
|
|
12
|
-
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.
|
|
13
|
-
|
|
14
|
-
The JavaScript version of **_EasyCoder_**, which provides a full set of graphical features to run in a browser, is at
|
|
15
|
-
|
|
16
|
-
Repository: [https://github.com/easycoder/easycoder.github.io](https://github.com/easycoder/easycoder.github.io)
|
|
17
|
-
Website: [https://easycoder.github.io](https://easycoder.github.io)
|
|
18
|
-
|
|
19
|
-
## Quick Start
|
|
20
|
-
Install **_EasyCoder_** in your Python environment:
|
|
21
|
-
```
|
|
22
|
-
pip install easycoder
|
|
23
|
-
```
|
|
24
|
-
Write a test script, 'hello.ecs', containing the following:
|
|
25
|
-
```
|
|
26
|
-
print `Hello, world!`
|
|
27
|
-
```
|
|
28
|
-
This is traditionally the first program to be written in virtually any language. To run it, use `easycoder hello.ecs`.
|
|
29
|
-
|
|
30
|
-
The output will look like this:
|
|
31
|
-
|
|
32
|
-
```
|
|
33
|
-
EasyCoder version 5
|
|
34
|
-
Compiled <anon>: 1 lines (2 tokens) in 0 ms
|
|
35
|
-
Run <anon>
|
|
36
|
-
1-> Hello, world!
|
|
37
|
-
```
|
|
38
|
-
It's conventional to add a program title to a script:
|
|
39
|
-
|
|
40
|
-
```
|
|
41
|
-
! Test script
|
|
42
|
-
script Test
|
|
43
|
-
print `Hello, world!`
|
|
44
|
-
```
|
|
45
|
-
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
|
|
46
|
-
|
|
47
|
-
```
|
|
48
|
-
EasyCoder version 5
|
|
49
|
-
Compiled Test: 5 lines (4 tokens) in 0 ms
|
|
50
|
-
Run Test
|
|
51
|
-
5-> Hello, world!
|
|
52
|
-
```
|
|
53
|
-
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.
|
|
54
|
-
|
|
55
|
-
Here in the repository is a folder called `scripts` containing some sample scripts:
|
|
56
|
-
|
|
57
|
-
`benchmark.ecs` allows the performance of EasyCoder to be compared to other languages if a similar program is written for each one
|
|
58
|
-
`tests.ecs` is a test program containing many of the EasyCoder features
|
|
59
|
-
`fizzbuzz.ecs` is a simple programming challenge often given at job interviews
|
|
60
|
-
|
|
61
|
-
## The EasyCoder programming language
|
|
62
|
-
There are three primary components to the language:
|
|
63
|
-
|
|
64
|
-
- Keywords
|
|
65
|
-
- Values
|
|
66
|
-
- Conditions
|
|
67
|
-
|
|
68
|
-
The language comprises a general-purpose core package, which can be enhanced by plugins to provide special features on demand.
|
|
69
|
-
|
|
70
|
-
[The core package](doc/core.md)
|
|
71
|
-
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
easycoder/__init__.py,sha256=LIhu5HcPlI3Zt29F96x0rEbK1NwA4gqMYpkKxtvK3aI,262
|
|
2
|
-
easycoder/ec_classes.py,sha256=onBKF6Lj8BZKNuJKacx4HyhOrVLXsoHdzl6RnMf77uM,1413
|
|
3
|
-
easycoder/ec_compiler.py,sha256=1z5U92uzUdCOO5-k0VXLnU581iAhwzQga04kfdTlpMY,4629
|
|
4
|
-
easycoder/ec_condition.py,sha256=WSbONo4zs2sX1icOVpscZDFSCAEFmTsquoc2RGcLx_k,763
|
|
5
|
-
easycoder/ec_core.py,sha256=AnPrSJ4oUIOFGV0iF6KxE3AmEb9NG77ae0KwoyvafYs,76175
|
|
6
|
-
easycoder/ec_handler.py,sha256=WDDIz0awD3vSQZ149rgbUWsClt6zXqED8ByXQJ5p1Ds,2200
|
|
7
|
-
easycoder/ec_program.py,sha256=U5QRxcyYycTugyu1ew8prk6NUEqnvcGuFJSY9stN8vY,7870
|
|
8
|
-
easycoder/ec_timestamp.py,sha256=_3QFJPzIWZ9Rzk3SQOQJ-gwmvB07pg78k23SPntoZtY,288
|
|
9
|
-
easycoder/ec_value.py,sha256=aOvSF6bM1iKpcLLm0zyGerxHixBkyjE3iYl1Bx6jmzU,2381
|
|
10
|
-
easycoder-241211.2.dist-info/entry_points.txt,sha256=JXAZbenl0TnsIft2FcGJbJ-4qoztVu2FuT8PFmWFexM,44
|
|
11
|
-
easycoder-241211.2.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
12
|
-
easycoder-241211.2.dist-info/WHEEL,sha256=ssQ84EZ5gH1pCOujd3iW7HClo_O_aDaClUbX4B8bjKY,100
|
|
13
|
-
easycoder-241211.2.dist-info/METADATA,sha256=nzof97vblfpCCdjDl9S0ZuOPHr5L2z58uBpTm61QjEs,2511
|
|
14
|
-
easycoder-241211.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|