easycoder 250103.1__py2.py3-none-any.whl → 250104.1__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of easycoder might be problematic. Click here for more details.

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