easycoder 241227.1__tar.gz → 241231.1__tar.gz

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.

Files changed (77) hide show
  1. {easycoder-241227.1 → easycoder-241231.1}/PKG-INFO +11 -3
  2. {easycoder-241227.1 → easycoder-241231.1}/README.md +10 -2
  3. easycoder-241231.1/easycoder/README.md +6 -0
  4. {easycoder-241227.1 → easycoder-241231.1}/easycoder/__init__.py +1 -1
  5. {easycoder-241227.1 → easycoder-241231.1}/easycoder/ec_core.py +25 -2
  6. {easycoder-241227.1 → easycoder-241231.1}/easycoder/ec_graphics.py +93 -35
  7. {easycoder-241227.1 → easycoder-241231.1}/easycoder/ec_program.py +46 -30
  8. {easycoder-241227.1 → easycoder-241231.1}/easycoder/ec_renderer.py +78 -18
  9. {easycoder-241227.1 → easycoder-241231.1}/easycoder/ec_screenspec.py +0 -1
  10. {easycoder-241227.1 → easycoder-241231.1}/json/graphics-demo.json +12 -13
  11. easycoder-241231.1/scripts/README.md +16 -0
  12. easycoder-241231.1/scripts/wave.ecg +118 -0
  13. {easycoder-241227.1 → easycoder-241231.1}/LICENSE +0 -0
  14. {easycoder-241227.1 → easycoder-241231.1}/doc/README.md +0 -0
  15. {easycoder-241227.1 → easycoder-241231.1}/doc/core/add.md +0 -0
  16. {easycoder-241227.1 → easycoder-241231.1}/doc/core/append.md +0 -0
  17. {easycoder-241227.1 → easycoder-241231.1}/doc/core/assert.md +0 -0
  18. {easycoder-241227.1 → easycoder-241231.1}/doc/core/begin.md +0 -0
  19. {easycoder-241227.1 → easycoder-241231.1}/doc/core/clear.md +0 -0
  20. {easycoder-241227.1 → easycoder-241231.1}/doc/core/close.md +0 -0
  21. {easycoder-241227.1 → easycoder-241231.1}/doc/core/create.md +0 -0
  22. {easycoder-241227.1 → easycoder-241231.1}/doc/core/debug.md +0 -0
  23. {easycoder-241227.1 → easycoder-241231.1}/doc/core/decrement.md +0 -0
  24. {easycoder-241227.1 → easycoder-241231.1}/doc/core/delete.md +0 -0
  25. {easycoder-241227.1 → easycoder-241231.1}/doc/core/divide.md +0 -0
  26. {easycoder-241227.1 → easycoder-241231.1}/doc/core/exit.md +0 -0
  27. {easycoder-241227.1 → easycoder-241231.1}/doc/core/file.md +0 -0
  28. {easycoder-241227.1 → easycoder-241231.1}/doc/core/fork.md +0 -0
  29. {easycoder-241227.1 → easycoder-241231.1}/doc/core/get.md +0 -0
  30. {easycoder-241227.1 → easycoder-241231.1}/doc/core/go.md +0 -0
  31. {easycoder-241227.1 → easycoder-241231.1}/doc/core/gosub.md +0 -0
  32. {easycoder-241227.1 → easycoder-241231.1}/doc/core/if.md +0 -0
  33. {easycoder-241227.1 → easycoder-241231.1}/doc/core/import.md +0 -0
  34. {easycoder-241227.1 → easycoder-241231.1}/doc/core/increment.md +0 -0
  35. {easycoder-241227.1 → easycoder-241231.1}/doc/core/index.md +0 -0
  36. {easycoder-241227.1 → easycoder-241231.1}/doc/core/init.md +0 -0
  37. {easycoder-241227.1 → easycoder-241231.1}/doc/core/input.md +0 -0
  38. {easycoder-241227.1 → easycoder-241231.1}/doc/core/multiply.md +0 -0
  39. {easycoder-241227.1 → easycoder-241231.1}/doc/core/open.md +0 -0
  40. {easycoder-241227.1 → easycoder-241231.1}/doc/core/pop.md +0 -0
  41. {easycoder-241227.1 → easycoder-241231.1}/doc/core/post.md +0 -0
  42. {easycoder-241227.1 → easycoder-241231.1}/doc/core/print.md +0 -0
  43. {easycoder-241227.1 → easycoder-241231.1}/doc/core/push.md +0 -0
  44. {easycoder-241227.1 → easycoder-241231.1}/doc/core/put.md +0 -0
  45. {easycoder-241227.1 → easycoder-241231.1}/doc/core/read.md +0 -0
  46. {easycoder-241227.1 → easycoder-241231.1}/doc/core/replace.md +0 -0
  47. {easycoder-241227.1 → easycoder-241231.1}/doc/core/return.md +0 -0
  48. {easycoder-241227.1 → easycoder-241231.1}/doc/core/script.md +0 -0
  49. {easycoder-241227.1 → easycoder-241231.1}/doc/core/set.md +0 -0
  50. {easycoder-241227.1 → easycoder-241231.1}/doc/core/split.md +0 -0
  51. {easycoder-241227.1 → easycoder-241231.1}/doc/core/stack.md +0 -0
  52. {easycoder-241227.1 → easycoder-241231.1}/doc/core/stop.md +0 -0
  53. {easycoder-241227.1 → easycoder-241231.1}/doc/core/system.md +0 -0
  54. {easycoder-241227.1 → easycoder-241231.1}/doc/core/take.md +0 -0
  55. {easycoder-241227.1 → easycoder-241231.1}/doc/core/toggle.md +0 -0
  56. {easycoder-241227.1 → easycoder-241231.1}/doc/core/truncate.md +0 -0
  57. {easycoder-241227.1 → easycoder-241231.1}/doc/core/variable.md +0 -0
  58. {easycoder-241227.1 → easycoder-241231.1}/doc/core/wait.md +0 -0
  59. {easycoder-241227.1 → easycoder-241231.1}/doc/core/while.md +0 -0
  60. {easycoder-241227.1 → easycoder-241231.1}/doc/core/write.md +0 -0
  61. {easycoder-241227.1 → easycoder-241231.1}/easycoder/ec.py +0 -0
  62. {easycoder-241227.1 → easycoder-241231.1}/easycoder/ec_classes.py +0 -0
  63. {easycoder-241227.1 → easycoder-241231.1}/easycoder/ec_compiler.py +0 -0
  64. {easycoder-241227.1 → easycoder-241231.1}/easycoder/ec_condition.py +0 -0
  65. {easycoder-241227.1 → easycoder-241231.1}/easycoder/ec_handler.py +0 -0
  66. {easycoder-241227.1 → easycoder-241231.1}/easycoder/ec_timestamp.py +0 -0
  67. {easycoder-241227.1 → easycoder-241231.1}/easycoder/ec_value.py +0 -0
  68. {easycoder-241227.1 → easycoder-241231.1}/images/Semoigo Dawn.jpg +0 -0
  69. {easycoder-241227.1 → easycoder-241231.1}/plugins/ec_p100.py +0 -0
  70. {easycoder-241227.1 → easycoder-241231.1}/plugins/example.py +0 -0
  71. {easycoder-241227.1 → easycoder-241231.1}/pyproject.toml +0 -0
  72. {easycoder-241227.1 → easycoder-241231.1}/scripts/benchmark.ecs +0 -0
  73. {easycoder-241227.1 → easycoder-241231.1}/scripts/fizzbuzz.ecs +0 -0
  74. {easycoder-241227.1 → easycoder-241231.1}/scripts/graphics-demo.ecg +0 -0
  75. {easycoder-241227.1 → easycoder-241231.1}/scripts/hello.ecs +0 -0
  76. {easycoder-241227.1 → easycoder-241231.1}/scripts/points.ecs +0 -0
  77. {easycoder-241227.1 → easycoder-241231.1}/scripts/tests.ecs +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: easycoder
3
- Version: 241227.1
3
+ Version: 241231.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>
@@ -60,9 +60,17 @@ Here in the repository is a folder called `scripts` containing some sample scrip
60
60
  `fizzbuzz.ecs` is a simple programming challenge often given at job interviews
61
61
 
62
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`.
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 a script using `easycoder {scriptname}.ecg`.
64
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.
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. 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 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.
66
74
 
67
75
  ## EasyCoder programming reference
68
76
 
@@ -49,9 +49,17 @@ Here in the repository is a folder called `scripts` containing some sample scrip
49
49
  `fizzbuzz.ecs` is a simple programming challenge often given at job interviews
50
50
 
51
51
  ## Graphical programmming
52
- **_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`.
52
+ **_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 a script using `easycoder {scriptname}.ecg`.
53
53
 
54
- 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.
54
+ 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. 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).
55
+
56
+ A couple of demo scripts are included in the `scripts` directory:
57
+
58
+ `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.
59
+
60
+ `wave.ecg` is a "Mexican Wave" simulation.
61
+
62
+ **_EasyCoder_** graphics are handled by a library module, `ec_renderer` that can be used outside of the **_EasyCoder_** environment, in other Python programs.
55
63
 
56
64
  ## EasyCoder programming reference
57
65
 
@@ -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.
@@ -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__ = "241231.1"
@@ -696,6 +696,29 @@ class Core(Handler):
696
696
  self.putSymbolValue(target, value)
697
697
  return self.nextPC()
698
698
 
699
+ # Negate a variable
700
+ def k_negate(self, command):
701
+ if self.nextIsSymbol():
702
+ symbolRecord = self.getSymbolRecord()
703
+ if symbolRecord['valueHolder']:
704
+ command['target'] = self.getToken()
705
+ self.add(command)
706
+ return True
707
+ self.warning(f'Core.negate: Variable "{symbolRecord["name"]}" does not hold a value')
708
+ return False
709
+
710
+ def r_negate(self, command):
711
+ symbolRecord = self.getVariable(command['target'])
712
+ if not symbolRecord['valueHolder']:
713
+ RuntimeError(self.program, f'{symbolRecord["name"]} does not hold a value')
714
+ return None
715
+ value = self.getSymbolValue(symbolRecord)
716
+ if value == None:
717
+ RuntimeError(self.program, f'{symbolRecord["name"]} has not been initialised')
718
+ value['content'] *= -1
719
+ self.putSymbolValue(symbolRecord, value)
720
+ return self.nextPC()
721
+
699
722
  # Define an object variable
700
723
  def k_object(self, command):
701
724
  return self.compileVariable(command)
@@ -976,7 +999,7 @@ class Core(Handler):
976
999
  content = self.getSymbolValue(templateRecord)['content']
977
1000
  original = self.getRuntimeValue(command['original'])
978
1001
  replacement = self.getRuntimeValue(command['replacement'])
979
- content = content.replace(original, replacement)
1002
+ content = content.replace(original, str(replacement))
980
1003
  value = {}
981
1004
  value['type'] = 'text'
982
1005
  value['numeric'] = False
@@ -1417,7 +1440,7 @@ class Core(Handler):
1417
1440
  # Compile a value in this domain
1418
1441
  def compileValue(self):
1419
1442
  value = {}
1420
- value['domain'] = 'core'
1443
+ value['domain'] = self.getName()
1421
1444
  token = self.getToken()
1422
1445
  if self.isSymbol():
1423
1446
  value['name'] = token
@@ -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):
@@ -200,44 +200,60 @@ class Program:
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):
@@ -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
-
@@ -1,6 +1,5 @@
1
1
  {
2
2
  "#": [
3
-
4
3
  "BlackText",
5
4
  "Photo",
6
5
  "BlueRect",
@@ -8,10 +7,10 @@
8
7
  ],
9
8
  "BlueRect": {
10
9
  "type": "rectangle",
11
- "left": 100,
12
- "bottom": 100,
13
- "width": 100,
14
- "height": 100,
10
+ "left": "30w",
11
+ "bottom": "15h",
12
+ "width": "20w",
13
+ "height": "40h",
15
14
  "fill": "blue",
16
15
  "id": "bluerect",
17
16
  "#": [
@@ -19,10 +18,10 @@
19
18
  ],
20
19
  "GreenCircle": {
21
20
  "type": "ellipse",
22
- "left": 20,
23
- "bottom": 20,
24
- "width": 60,
25
- "height": 60,
21
+ "left": "10w",
22
+ "bottom": "10h",
23
+ "width": "80w",
24
+ "height": "80h",
26
25
  "fill": "green",
27
26
  "id": "greencircle"
28
27
  }
@@ -65,10 +64,10 @@
65
64
 
66
65
  "Photo": {
67
66
  "type": "image",
68
- "left": 70,
69
- "bottom": 150,
70
- "width": 500,
71
- "height": 300,
67
+ "left": "10w",
68
+ "bottom": "30h",
69
+ "width": "80w",
70
+ "height": "60h",
72
71
  "source": "images/Semoigo Dawn.jpg",
73
72
  "id": "dawn"
74
73
  }
@@ -0,0 +1,16 @@
1
+ # EasyCoder example scripts
2
+ The scripts in this folder are as follows:
3
+
4
+ `hello.ecs` is everybody's first program.
5
+
6
+ `fizzbuzz.ecs` is often set as a rather trivial programming challenge at job interviews.
7
+
8
+ `benchmark.ecs` is a program that can be translated into other languages and used to compare runtime performance.
9
+
10
+ `tests.ecs` is a selection of tests to verify the various language features. It could do with a major expansion to cover more of the language.
11
+
12
+ `points.ecs` shows how to use a plugin module, in this case one that manages points (pairs of values). This one is aimed at Python programmers wishing to extend the language.
13
+
14
+ `graphics-demo.ecg` demonstrates various features of the **_EasyCoder_** graphics system. Note that the filename extension is `.ecg` instead of `.ecs`, this being to signal to **_EasyCoder_** that it needs to call in the graphics module.
15
+
16
+ `wave.ecg` is a simulation of the "Mexican Wave".
@@ -0,0 +1,118 @@
1
+ ! Mexican Wave
2
+
3
+ script MexicanWave
4
+
5
+ rectangle Bar
6
+ variable Spec
7
+ variable Item
8
+ variable Angle
9
+ variable Height
10
+ variable Mid
11
+ variable Range
12
+ variable Step
13
+ variable H
14
+ variable L
15
+ variable N
16
+
17
+ create window title `Mexican Wave` at 300 300 size 640 480 fill color 255 255 200
18
+ run graphics
19
+
20
+ put `{
21
+ ` "#": [
22
+ ` "Bar0",
23
+ ` "Bar1",
24
+ ` "Bar2",
25
+ ` "Bar3",
26
+ ` "Bar4",
27
+ ` "Bar5",
28
+ ` "Bar6",
29
+ ` "Bar7",
30
+ ` "Bar8",
31
+ ` "Bar9"
32
+ ` ],
33
+ `
34
+ `` into Spec
35
+
36
+ put 0 into N
37
+ while N is less than 10
38
+ begin
39
+ put `
40
+ ` "Bar<N>": {
41
+ ` "type": "rectangle",
42
+ ` "left": "<L>w",
43
+ ` "bottom": 0,
44
+ ` "width": "8w",
45
+ ` "height": 0,
46
+ ` "fill": "blue",
47
+ ` "id": "bar<N>"
48
+ ` }` into Item
49
+
50
+ multiply N by 10 giving L
51
+ add 1 to L
52
+ replace `<L>` with L in Item
53
+ replace `<N>` with N in Item
54
+ put Spec cat Item into Spec
55
+ increment N
56
+ if N is less than 10 put Spec cat `,` cat newline into Spec
57
+ end
58
+ put Spec cat newline cat `}` cat newline into Spec
59
+
60
+ render Spec
61
+
62
+ divide the window height by 2 giving Mid
63
+ multiply Mid by 9 giving Range
64
+ divide Range by 10
65
+
66
+ set the elements of Bar to 10
67
+ set the elements of Angle to 10
68
+ put 0 into N
69
+ while N is less than 10
70
+ begin
71
+ index Bar to N
72
+ attach Bar to `bar` cat N
73
+ index Angle to N
74
+ multiply N by 36 giving Angle
75
+ increment N
76
+ end
77
+
78
+ wait 1
79
+ ! Run the setup
80
+ put 0 into N
81
+ while N is less than 10
82
+ begin
83
+ index Bar to N
84
+ index Angle to N
85
+ put sin Angle radius Range into Height
86
+ negate Height
87
+ add Mid to Height
88
+ divide Height by 10 giving Step
89
+ put 0 into H
90
+ while H is less than Height
91
+ begin
92
+ set attribute `height` of Bar to H
93
+ add Step to H
94
+ wait 1 milli
95
+ end
96
+ set attribute `height` of Bar to Height
97
+ increment N
98
+ end
99
+
100
+ wait 2
101
+ ! Run the main animation
102
+ while true
103
+ begin
104
+ put 0 into N
105
+ while N is less than 10
106
+ begin
107
+ index Bar to N
108
+ index Angle to N
109
+ put sin Angle radius Range into Height
110
+ negate Height
111
+ add Mid to Height
112
+ set attribute `height` of Bar to Height
113
+ if Angle is 0 put 360 into Angle
114
+ decrement Angle
115
+ increment N
116
+ end
117
+ wait 1 milli
118
+ end
File without changes
File without changes