easycoder 241211.3__tar.gz → 241218.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 (73) hide show
  1. easycoder-241211.3/README.md → easycoder-241218.1/PKG-INFO +19 -2
  2. easycoder-241211.3/PKG-INFO → easycoder-241218.1/README.md +7 -13
  3. {easycoder-241211.3 → easycoder-241218.1}/doc/README.md +1 -1
  4. {easycoder-241211.3 → easycoder-241218.1}/doc/core/if.md +1 -1
  5. easycoder-241218.1/doc/core/import.md +13 -0
  6. {easycoder-241211.3 → easycoder-241218.1}/doc/core/increment.md +1 -1
  7. {easycoder-241211.3 → easycoder-241218.1}/easycoder/__init__.py +2 -1
  8. {easycoder-241211.3 → easycoder-241218.1}/easycoder/ec_compiler.py +1 -1
  9. {easycoder-241211.3 → easycoder-241218.1}/easycoder/ec_core.py +16 -14
  10. easycoder-241218.1/easycoder/ec_graphics.py +376 -0
  11. {easycoder-241211.3 → easycoder-241218.1}/easycoder/ec_program.py +15 -7
  12. easycoder-241218.1/easycoder/ec_renderer.py +335 -0
  13. easycoder-241218.1/images/Semoigo Dawn.jpg +0 -0
  14. easycoder-241218.1/json/graphics-demo.json +60 -0
  15. {easycoder-241211.3 → easycoder-241218.1}/plugins/example.py +2 -1
  16. {easycoder-241211.3 → easycoder-241218.1}/pyproject.toml +4 -2
  17. easycoder-241218.1/scripts/graphics-demo.ecs +71 -0
  18. easycoder-241211.3/test.ecs +0 -10
  19. {easycoder-241211.3 → easycoder-241218.1}/LICENSE +0 -0
  20. {easycoder-241211.3 → easycoder-241218.1}/doc/core/add.md +0 -0
  21. {easycoder-241211.3 → easycoder-241218.1}/doc/core/append.md +0 -0
  22. {easycoder-241211.3 → easycoder-241218.1}/doc/core/assert.md +0 -0
  23. {easycoder-241211.3 → easycoder-241218.1}/doc/core/begin.md +0 -0
  24. {easycoder-241211.3 → easycoder-241218.1}/doc/core/clear.md +0 -0
  25. {easycoder-241211.3 → easycoder-241218.1}/doc/core/close.md +0 -0
  26. {easycoder-241211.3 → easycoder-241218.1}/doc/core/create.md +0 -0
  27. {easycoder-241211.3 → easycoder-241218.1}/doc/core/debug.md +0 -0
  28. {easycoder-241211.3 → easycoder-241218.1}/doc/core/decrement.md +0 -0
  29. {easycoder-241211.3 → easycoder-241218.1}/doc/core/delete.md +0 -0
  30. {easycoder-241211.3 → easycoder-241218.1}/doc/core/divide.md +0 -0
  31. {easycoder-241211.3 → easycoder-241218.1}/doc/core/exit.md +0 -0
  32. {easycoder-241211.3 → easycoder-241218.1}/doc/core/file.md +0 -0
  33. {easycoder-241211.3 → easycoder-241218.1}/doc/core/fork.md +0 -0
  34. {easycoder-241211.3 → easycoder-241218.1}/doc/core/get.md +0 -0
  35. {easycoder-241211.3 → easycoder-241218.1}/doc/core/go.md +0 -0
  36. {easycoder-241211.3 → easycoder-241218.1}/doc/core/gosub.md +0 -0
  37. {easycoder-241211.3 → easycoder-241218.1}/doc/core/index.md +0 -0
  38. {easycoder-241211.3 → easycoder-241218.1}/doc/core/init.md +0 -0
  39. {easycoder-241211.3 → easycoder-241218.1}/doc/core/input.md +0 -0
  40. {easycoder-241211.3 → easycoder-241218.1}/doc/core/multiply.md +0 -0
  41. {easycoder-241211.3 → easycoder-241218.1}/doc/core/open.md +0 -0
  42. {easycoder-241211.3 → easycoder-241218.1}/doc/core/pop.md +0 -0
  43. {easycoder-241211.3 → easycoder-241218.1}/doc/core/post.md +0 -0
  44. {easycoder-241211.3 → easycoder-241218.1}/doc/core/print.md +0 -0
  45. {easycoder-241211.3 → easycoder-241218.1}/doc/core/push.md +0 -0
  46. {easycoder-241211.3 → easycoder-241218.1}/doc/core/put.md +0 -0
  47. {easycoder-241211.3 → easycoder-241218.1}/doc/core/read.md +0 -0
  48. {easycoder-241211.3 → easycoder-241218.1}/doc/core/replace.md +0 -0
  49. {easycoder-241211.3 → easycoder-241218.1}/doc/core/return.md +0 -0
  50. {easycoder-241211.3 → easycoder-241218.1}/doc/core/script.md +0 -0
  51. {easycoder-241211.3 → easycoder-241218.1}/doc/core/set.md +0 -0
  52. {easycoder-241211.3 → easycoder-241218.1}/doc/core/split.md +0 -0
  53. {easycoder-241211.3 → easycoder-241218.1}/doc/core/stack.md +0 -0
  54. {easycoder-241211.3 → easycoder-241218.1}/doc/core/stop.md +0 -0
  55. {easycoder-241211.3 → easycoder-241218.1}/doc/core/system.md +0 -0
  56. {easycoder-241211.3 → easycoder-241218.1}/doc/core/take.md +0 -0
  57. {easycoder-241211.3 → easycoder-241218.1}/doc/core/toggle.md +0 -0
  58. {easycoder-241211.3 → easycoder-241218.1}/doc/core/truncate.md +0 -0
  59. {easycoder-241211.3 → easycoder-241218.1}/doc/core/variable.md +0 -0
  60. {easycoder-241211.3 → easycoder-241218.1}/doc/core/wait.md +0 -0
  61. {easycoder-241211.3 → easycoder-241218.1}/doc/core/while.md +0 -0
  62. {easycoder-241211.3 → easycoder-241218.1}/doc/core/write.md +0 -0
  63. {easycoder-241211.3 → easycoder-241218.1}/easycoder/ec_classes.py +0 -0
  64. {easycoder-241211.3 → easycoder-241218.1}/easycoder/ec_condition.py +0 -0
  65. {easycoder-241211.3 → easycoder-241218.1}/easycoder/ec_handler.py +0 -0
  66. {easycoder-241211.3 → easycoder-241218.1}/easycoder/ec_timestamp.py +0 -0
  67. {easycoder-241211.3 → easycoder-241218.1}/easycoder/ec_value.py +0 -0
  68. {easycoder-241211.3 → easycoder-241218.1}/plugins/ec_p100.py +0 -0
  69. {easycoder-241211.3 → easycoder-241218.1}/scripts/benchmark.ecs +0 -0
  70. {easycoder-241211.3 → easycoder-241218.1}/scripts/fizzbuzz.ecs +0 -0
  71. {easycoder-241211.3 → easycoder-241218.1}/scripts/hello.ecs +0 -0
  72. {easycoder-241211.3 → easycoder-241218.1}/scripts/points.ecs +0 -0
  73. {easycoder-241211.3 → easycoder-241218.1}/scripts/tests.ecs +0 -0
@@ -1,9 +1,20 @@
1
+ Metadata-Version: 2.3
2
+ Name: easycoder
3
+ Version: 241218.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
+
1
12
  # Introduction
2
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.
3
14
 
4
15
  The JavaScript version of **_EasyCoder_**, which provides a full set of graphical features to run in a browser, is at
5
16
 
6
- Repository: [https://github.com/easycoder/easycoder.github.io](https://github.com/easycoder/easycoder.github.io)
17
+ Repository: [https://github.com/easycoder/easycoder.github.io](https://github.com/easycoder/easycoder.github.io)
7
18
  Website: [https://easycoder.github.io](https://easycoder.github.io)
8
19
 
9
20
  ## Quick Start
@@ -48,6 +59,11 @@ Here in the repository is a folder called `scripts` containing some sample scrip
48
59
  `tests.ecs` is a test program containing many of the EasyCoder features
49
60
  `fizzbuzz.ecs` is a simple programming challenge often given at job interviews
50
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
+
51
67
  ## EasyCoder programming reference
52
68
 
53
69
  The language comprises a general-purpose core package, which can be enhanced by plugins to provide special features on demand.
@@ -58,4 +74,5 @@ The language comprises a general-purpose core package, which can be enhanced by
58
74
 
59
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.
60
76
 
61
- 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_**
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,19 +1,9 @@
1
- Metadata-Version: 2.3
2
- Name: easycoder
3
- Version: 241211.3
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
1
  # Introduction
12
2
  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
3
 
14
4
  The JavaScript version of **_EasyCoder_**, which provides a full set of graphical features to run in a browser, is at
15
5
 
16
- Repository: [https://github.com/easycoder/easycoder.github.io](https://github.com/easycoder/easycoder.github.io)
6
+ Repository: [https://github.com/easycoder/easycoder.github.io](https://github.com/easycoder/easycoder.github.io)
17
7
  Website: [https://easycoder.github.io](https://easycoder.github.io)
18
8
 
19
9
  ## Quick Start
@@ -58,6 +48,11 @@ Here in the repository is a folder called `scripts` containing some sample scrip
58
48
  `tests.ecs` is a test program containing many of the EasyCoder features
59
49
  `fizzbuzz.ecs` is a simple programming challenge often given at job interviews
60
50
 
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`.
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.
55
+
61
56
  ## EasyCoder programming reference
62
57
 
63
58
  The language comprises a general-purpose core package, which can be enhanced by plugins to provide special features on demand.
@@ -68,5 +63,4 @@ The language comprises a general-purpose core package, which can be enhanced by
68
63
 
69
64
  **_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.
70
65
 
71
- 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_**
72
-
66
+ 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_**.
@@ -10,7 +10,7 @@ The core package contains all the keywords values and conditionals needed for ge
10
10
 
11
11
  The core keywords are:
12
12
 
13
- [add](core/add.md) [append](core/append.md) [assert](core/assert.md) [begin](core/begin.md) [clear](core/clear.md) [close](core/close.md) [create](core/create.md) [debug](core/debug.md) [decrement](core/decrement.md) [delete](core/delete.md) [divide](core/divide.md) [exit](core/exit.md) [file](core/file.md) [fork](core/fork.md) [get](core/get.md) [go](core/go.md) [gosub](core/gosub.md) [if](core/if.md) [increment](core/increment.md) [index](core/index.md) [init](core/init.md) [input](core/input.md) [multiply](core/multiply.md) [open](core/open.md) [pop](core/pop.md) [post](core/post.md) [print](core/print.md) [push](core/push.md) [put](core/put.md) [read](core/read.md) [replace](core/replace.md) [return](core/return.md) [script](core/script.md) [set](core/set.md) [split](core/split.md) [stack](core/stack.md) [stop](core/stop.md) [system](core/system.md) [take](core/take.md) [toggle](core/toggle.md) [truncate](core/truncate.md) [variable](core/variable.md) [wait](core/wait.md) [while](core/while.md) [write](core/write.md)
13
+ [add](core/add.md) [append](core/append.md) [assert](core/assert.md) [begin](core/begin.md) [clear](core/clear.md) [close](core/close.md) [create](core/create.md) [debug](core/debug.md) [decrement](core/decrement.md) [delete](core/delete.md) [divide](core/divide.md) [exit](core/exit.md) [file](core/file.md) [fork](core/fork.md) [get](core/get.md) [go](core/go.md) [gosub](core/gosub.md) [if](core/if.md) [import](core/import.md) [increment](core/increment.md) [index](core/index.md) [init](core/init.md) [input](core/input.md) [multiply](core/multiply.md) [open](core/open.md) [pop](core/pop.md) [post](core/post.md) [print](core/print.md) [push](core/push.md) [put](core/put.md) [read](core/read.md) [replace](core/replace.md) [return](core/return.md) [script](core/script.md) [set](core/set.md) [split](core/split.md) [stack](core/stack.md) [stop](core/stop.md) [system](core/system.md) [take](core/take.md) [toggle](core/toggle.md) [truncate](core/truncate.md) [variable](core/variable.md) [wait](core/wait.md) [while](core/while.md) [write](core/write.md)
14
14
 
15
15
  The core values are:
16
16
 
@@ -8,7 +8,7 @@
8
8
  ## Description:
9
9
  `if` tests the condition that follows. If the result is `true` then control resumes at the named label; otherwise if there's an `else` section this is executed, then the program resumes at the next instruction after the `if`. See also [while](while.md).
10
10
 
11
- Next: [increment](increment.md)
11
+ Next: [import](import.md)
12
12
  Prev: [gosub](gosub.md)
13
13
 
14
14
  [Back](../README.md)
@@ -0,0 +1,13 @@
1
+ ## Syntax:
2
+ `import {classname} from {path}`
3
+
4
+ ## Examples:
5
+ `import Points from plugins/example.py`
6
+
7
+ ## Description:
8
+ As with [script](script.md), `import` is a compiler directive that should be placed at the top of the script, under the [script](script.md) directive. It's used to call in a plugin language extension where needed. The example above is provided in the repository, to be used as a starting point for your own extra functionality.
9
+
10
+ Next: [increment](increment.md)
11
+ Prev: [if](if.md)
12
+
13
+ [Back](../README.md)
@@ -8,6 +8,6 @@
8
8
  Add 1 to the value of the variable. See also [decrement](decrement.md).
9
9
 
10
10
  Next: [index](index.md)
11
- Prev: [if](if.md)
11
+ Prev: [import](import.md)
12
12
 
13
13
  [Back](../README.md)
@@ -8,5 +8,6 @@ from .ec_handler import *
8
8
  from .ec_program import *
9
9
  from .ec_timestamp import *
10
10
  from .ec_value import *
11
+ from .ec_graphics import *
11
12
 
12
- __version__ = "241211.3"
13
+ __version__ = "241218.1"
@@ -101,7 +101,7 @@ class Compiler:
101
101
 
102
102
  def showWarnings(self):
103
103
  for warning in self.warnings:
104
- print(f'Line {self.getLino() + 1}: {warning}')
104
+ print(f'Warning: Line {self.getLino() + 1}: {warning}')
105
105
 
106
106
  def getSymbolRecord(self):
107
107
  token = self.getToken()
@@ -38,7 +38,7 @@ class Core(Handler):
38
38
  command['target'] = self.getToken()
39
39
  self.add(command)
40
40
  return True
41
- self.warning(f'core.add: Expected value holder')
41
+ self.warning(f'Core.add: Expected value holder')
42
42
  else:
43
43
  # Here we have 2 values so 'giving' must come next
44
44
  command['value2'] = self.getValue()
@@ -46,7 +46,7 @@ class Core(Handler):
46
46
  command['target'] = self.nextToken()
47
47
  self.add(command)
48
48
  return True
49
- self.warning(f'core.add: Expected "giving"')
49
+ self.warning(f'Core.add: Expected "giving"')
50
50
  return False
51
51
 
52
52
  def r_add(self, command):
@@ -90,7 +90,7 @@ class Core(Handler):
90
90
  command['target'] = symbolRecord['name']
91
91
  self.add(command)
92
92
  return True
93
- self.warning(f'Variable "{symbolRecord["name"]}" does not hold a value')
93
+ self.warning(f'Core.append: Variable "{symbolRecord["name"]}" does not hold a value')
94
94
  return False
95
95
 
96
96
  def r_append(self, command):
@@ -248,7 +248,7 @@ class Core(Handler):
248
248
  command['target'] = self.getToken()
249
249
  self.add(command)
250
250
  return True
251
- self.warning(f'Variable "{symbolRecord["name"]}" does not hold a value')
251
+ self.warning(f'Core.decrement: Variable "{symbolRecord["name"]}" does not hold a value')
252
252
  return False
253
253
 
254
254
  def r_decrement(self, command):
@@ -272,9 +272,9 @@ class Core(Handler):
272
272
  self.add(command)
273
273
  return True
274
274
  else:
275
- self.warning(f'"of" expected; got {self.getToken()}')
275
+ self.warning(f'Core.delete: "of" expected; got {self.getToken()}')
276
276
  else:
277
- self.warning(f'"file" or "property" expected; got {token}')
277
+ self.warning(f'Core.delete: "file" or "property" expected; got {token}')
278
278
  return False
279
279
 
280
280
  def r_delete(self, command):
@@ -570,7 +570,7 @@ class Core(Handler):
570
570
  command['target'] = self.getToken()
571
571
  self.add(command)
572
572
  return True
573
- self.warning(f'Variable "{symbolRecord["name"]}" does not hold a value')
573
+ self.warning(f'Core.increment: Variable "{symbolRecord["name"]}" does not hold a value')
574
574
  return False
575
575
 
576
576
  def r_increment(self, command):
@@ -729,7 +729,7 @@ class Core(Handler):
729
729
  else:
730
730
  FatalError(self.compiler, f'Variable "{self.getToken()}" is not a file')
731
731
  else:
732
- self.warning(f'core.open: Variable "{self.getToken()}" not declared')
732
+ self.warning(f'Core.open: Variable "{self.getToken()}" not declared')
733
733
  return False
734
734
 
735
735
  def r_open(self, command):
@@ -1215,7 +1215,7 @@ class Core(Handler):
1215
1215
  command['target'] = self.getToken()
1216
1216
  self.add(command)
1217
1217
  return True
1218
- self.warning(f'core.take: Expected value holder')
1218
+ self.warning(f'Core.take: Expected value holder')
1219
1219
  else:
1220
1220
  # Here we have 2 values so 'giving' must come next
1221
1221
  command['value2'] = self.getValue()
@@ -1227,7 +1227,7 @@ class Core(Handler):
1227
1227
  else:
1228
1228
  FatalError(self.program.compiler, f'\'{self.getToken()}\' is not a symbol')
1229
1229
  else:
1230
- self.warning(f'core.take: Expected "giving"')
1230
+ self.warning(f'Core.take: Expected "giving"')
1231
1231
  return False
1232
1232
 
1233
1233
  def r_take(self, command):
@@ -1402,6 +1402,8 @@ class Core(Handler):
1402
1402
  RuntimeError(self.program, f'{symbolRecord["name"]} does not hold a value')
1403
1403
  return None
1404
1404
  value = self.getSymbolValue(symbolRecord)
1405
+ if value == None:
1406
+ RuntimeError(self.program, f'{symbolRecord["name"]} has not been initialised')
1405
1407
  if mode == '+':
1406
1408
  value['content'] += 1
1407
1409
  else:
@@ -1467,7 +1469,7 @@ class Core(Handler):
1467
1469
  if symbolRecord['valueHolder']:
1468
1470
  value['target'] = symbolRecord['name']
1469
1471
  return value
1470
- self.warning(f'Token \'{self.getToken()}\' does not hold a value')
1472
+ self.warning(f'Core.compileValue: Token \'{self.getToken()}\' does not hold a value')
1471
1473
  return None
1472
1474
 
1473
1475
  if token == 'property':
@@ -1478,7 +1480,7 @@ class Core(Handler):
1478
1480
  if symbolRecord['valueHolder']:
1479
1481
  value['target'] = symbolRecord['name']
1480
1482
  return value
1481
- self.warning(f'Token \'{self.getToken()}\' does not hold a value')
1483
+ self.warning(f'Core.compileValue: Token \'{self.getToken()}\' does not hold a value')
1482
1484
  return None
1483
1485
 
1484
1486
  if token == 'arg':
@@ -1640,7 +1642,7 @@ class Core(Handler):
1640
1642
  return value
1641
1643
  return None
1642
1644
 
1643
- self.warning(f'Core: Unknown token {token}')
1645
+ self.warning(f'Core.compileValue: Unknown token "{token}"')
1644
1646
  return None
1645
1647
 
1646
1648
  #############################################################################
@@ -2115,7 +2117,7 @@ class Core(Handler):
2115
2117
  condition.type = 'boolean'
2116
2118
  return condition
2117
2119
 
2118
- self.warning(f'I can\'t get a conditional:')
2120
+ self.warning(f'Core.compileCondition: I can\'t get a conditional:')
2119
2121
  return None
2120
2122
 
2121
2123
  def isNegate(self):
@@ -0,0 +1,376 @@
1
+ from .ec_classes import FatalError, RuntimeError
2
+ from .ec_handler import Handler
3
+ from .ec_renderer import *
4
+
5
+ class Graphics(Handler):
6
+
7
+ def __init__(self, compiler):
8
+ Handler.__init__(self, compiler)
9
+
10
+ def getName(self):
11
+ return 'graphics'
12
+
13
+ #############################################################################
14
+ # Keyword handlers
15
+
16
+ def k_attach(self, command):
17
+ if self.nextIsSymbol():
18
+ record = self.getSymbolRecord()
19
+ command['name'] = record['name']
20
+ if self.nextIs('to'):
21
+ value = self.nextValue()
22
+ command['id'] = value
23
+ self.add(command)
24
+ return True
25
+
26
+ def r_attach(self, command):
27
+ target = self.getVariable(command['name'])
28
+ id = self.getRuntimeValue(command['id'])
29
+ element = getElement(id)
30
+ if element == None:
31
+ FatalError(self.program.compiler, f'There is no screen element with id \'{id}\'')
32
+ return -1
33
+ if element['type'] != target['keyword']:
34
+ FatalError(self.program.compiler, f'Mismatched element type ({element['type']} and {target['keyword']})')
35
+ self.putSymbolValue(target, {'type': 'text', 'content': id})
36
+ return self.nextPC()
37
+
38
+ def k_close(self, command):
39
+ if self.nextIs('screen'):
40
+ self.add(command)
41
+ return True
42
+ return False
43
+
44
+ def r_close(self, command):
45
+ closeScreen()
46
+ return self.nextPC()
47
+
48
+ def k_create(self, command):
49
+ if self.nextIs('screen'):
50
+ while True:
51
+ token = self.peek()
52
+ if token == 'at':
53
+ self.nextToken()
54
+ command['left'] = self.nextValue()
55
+ command['top'] = self.nextValue()
56
+ elif token == 'size':
57
+ self.nextToken()
58
+ command['width'] = self.nextValue()
59
+ command['height'] = self.nextValue()
60
+ elif token == 'fill':
61
+ self.nextToken()
62
+ command['fill'] = self.nextValue()
63
+ else:
64
+ break
65
+ self.add(command)
66
+ return True
67
+ return False
68
+
69
+ def r_create(self, command):
70
+ createScreen(command)
71
+ return self.nextPC()
72
+
73
+ def k_ellipse(self, command):
74
+ return self.compileVariable(command)
75
+
76
+ def r_ellipse(self, command):
77
+ return self.nextPC()
78
+
79
+ def k_image(self, command):
80
+ return self.compileVariable(command)
81
+
82
+ def r_image(self, command):
83
+ return self.nextPC()
84
+
85
+ def k_move(self, command):
86
+ if self.nextIsSymbol():
87
+ record = self.getSymbolRecord()
88
+ if record['keyword'] in ['rectangle', 'ellipse', 'text', 'image']:
89
+ command['name'] = record['name']
90
+ if self.nextToken() in ['by', 'to']:
91
+ command['type'] = self.getToken()
92
+ command['x'] = self.nextValue()
93
+ command['y'] = self.nextValue()
94
+ self.add(command)
95
+ return True
96
+ return False
97
+
98
+ def r_move(self, command):
99
+ target = self.getVariable(command['name'])
100
+ id = self.getSymbolValue(target)['content']
101
+ type = command['type']
102
+ x = self.getRuntimeValue(command['x'])
103
+ y = self.getRuntimeValue(command['y'])
104
+ if type == 'by':
105
+ moveElement(id, x, y)
106
+ elif type == 'to':
107
+ moveElementTo(id, x, y)
108
+ return self.nextPC()
109
+
110
+ def k_on(self, command):
111
+ token = self.nextToken()
112
+ command['type'] = token
113
+ if token == 'click':
114
+ command['event'] = token
115
+ if self.peek() == 'in':
116
+ self.nextToken()
117
+ if self.nextIs('screen'):
118
+ command['target'] = None
119
+ elif self.isSymbol():
120
+ target = self.getSymbolRecord()
121
+ command['target'] = target['name']
122
+ else:
123
+ FatalError(self.program.compiler, f'{self.getToken()} is not a screen element')
124
+ return False
125
+ command['goto'] = self.getPC() + 2
126
+ self.add(command)
127
+ self.nextToken()
128
+ pcNext = self.getPC()
129
+ cmd = {}
130
+ cmd['domain'] = 'core'
131
+ cmd['lino'] = command['lino']
132
+ cmd['keyword'] = 'gotoPC'
133
+ cmd['goto'] = 0
134
+ cmd['debug'] = False
135
+ self.addCommand(cmd)
136
+ self.compileOne()
137
+ cmd = {}
138
+ cmd['domain'] = 'core'
139
+ cmd['lino'] = command['lino']
140
+ cmd['keyword'] = 'stop'
141
+ cmd['debug'] = False
142
+ self.addCommand(cmd)
143
+ # Fixup the link
144
+ self.getCommandAt(pcNext)['goto'] = self.getPC()
145
+ return True
146
+ elif token == 'tick':
147
+ command['event'] = token
148
+ command['goto'] = self.getPC() + 2
149
+ self.add(command)
150
+ self.nextToken()
151
+ pcNext = self.getPC()
152
+ cmd = {}
153
+ cmd['domain'] = 'core'
154
+ cmd['lino'] = command['lino']
155
+ cmd['keyword'] = 'gotoPC'
156
+ cmd['goto'] = 0
157
+ cmd['debug'] = False
158
+ self.addCommand(cmd)
159
+ self.compileOne()
160
+ cmd = {}
161
+ cmd['domain'] = 'core'
162
+ cmd['lino'] = command['lino']
163
+ cmd['keyword'] = 'stop'
164
+ cmd['debug'] = False
165
+ self.addCommand(cmd)
166
+ # Fixup the link
167
+ self.getCommandAt(pcNext)['goto'] = self.getPC()
168
+ return True
169
+ return False
170
+
171
+ def r_on(self, command):
172
+ pc = command['goto']
173
+ if command['type'] == 'click':
174
+ event = command['event']
175
+ if event == 'click':
176
+ target = command['target']
177
+ if target == None:
178
+ value = 'screen'
179
+ else:
180
+ widget = self.getVariable(target)
181
+ value = widget['value'][widget['index']]
182
+ setOnClick(value['content'], lambda: self.run(pc))
183
+ elif command['type'] == 'tick':
184
+ setOnTick(lambda: self.run(pc))
185
+ return self.nextPC()
186
+
187
+ def k_rectangle(self, command):
188
+ return self.compileVariable(command)
189
+
190
+ def r_rectangle(self, command):
191
+ return self.nextPC()
192
+
193
+ def k_render(self, command):
194
+ command['value'] = self.nextValue()
195
+ command['parent'] = 'screen'
196
+ if self.peek() == 'in':
197
+ self.nextToken()
198
+ if self.nextIsSymbol():
199
+ record = self.getSymbolRecord()
200
+ type = record['type']
201
+ name = record['name']
202
+ if type in ['rectangle', 'ellipse']:
203
+ command['parent'] = record['name']
204
+ self.add(command)
205
+ return True
206
+ else:
207
+ self.warning(f'Graphics.render: {name} cannot be a parent of another element')
208
+ return False
209
+ self.add(command)
210
+ return True
211
+ FatalError(self.program.compiler, 'Nothing specified to render')
212
+ return False
213
+
214
+ def r_render(self, command):
215
+ parent = command['parent']
216
+ value = self.getRuntimeValue(command['value'])
217
+ render(value, parent)
218
+ return self.nextPC()
219
+
220
+ def k_set(self, command):
221
+ if self.peek() == 'the':
222
+ self.nextToken()
223
+ token = self.peek()
224
+ if token == 'text':
225
+ self.nextToken()
226
+ command['variant'] = 'setText'
227
+ if self.peek() == 'of':
228
+ self.nextToken()
229
+ if self.nextIsSymbol():
230
+ record = self.getSymbolRecord()
231
+ command['name'] = record['name']
232
+ if record['keyword'] != 'text':
233
+ RuntimeError(command['program'], f'Symbol type is not \'text\'')
234
+ if self.peek() == 'to':
235
+ self.nextToken()
236
+ command['value'] = self.nextValue()
237
+ self.add(command)
238
+ return True
239
+ return False
240
+ elif token == 'background':
241
+ self.nextToken()
242
+ command['variant'] = 'setBackground'
243
+ if self.peek() == 'color':
244
+ self.nextToken()
245
+ if self.peek() == 'of':
246
+ self.nextToken()
247
+ if self.nextIsSymbol():
248
+ record = self.getSymbolRecord()
249
+ command['name'] = record['name']
250
+ if not record['keyword'] in ['rectangle', 'ellipse']:
251
+ RuntimeError(command['program'], f'Symbol type is not \'rectangle\' or \'ellipse\'')
252
+ if self.peek() == 'to':
253
+ self.nextToken()
254
+ command['value'] = self.nextValue()
255
+ self.add(command)
256
+ return True
257
+ return False
258
+ return False
259
+
260
+ def r_set(self, command):
261
+ variant = command['variant']
262
+ if variant == 'setText':
263
+ variable = self.getVariable(command['name'])
264
+ element = self.getSymbolValue(variable)
265
+ value = self.getRuntimeValue(command['value'])
266
+ setText(element['content'], value)
267
+ elif variant == 'setBackground':
268
+ variable = self.getVariable(command['name'])
269
+ element = self.getSymbolValue(variable)
270
+ value = self.getRuntimeValue(command['value'])
271
+ setBackground(element['content'], value)
272
+ return self.nextPC()
273
+
274
+ def k_show(self, command):
275
+ if self.nextIs('screen'):
276
+ command['name'] = None
277
+ self.add(command)
278
+ return True
279
+ return False
280
+
281
+ def r_show(self, command):
282
+ showScreen()
283
+ return self.nextPC()
284
+
285
+ def k_spec(self, command):
286
+ return self.compileVariable(command, True)
287
+
288
+ def r_spec(self, command):
289
+ return self.nextPC()
290
+
291
+ def k_text(self, command):
292
+ return self.compileVariable(command)
293
+
294
+ def r_text(self, command):
295
+ return self.nextPC()
296
+
297
+ #############################################################################
298
+ # Compile a value in this domain
299
+ def compileValue(self):
300
+ value = {}
301
+ value['domain'] = 'graphics'
302
+ token = self.getToken()
303
+ if self.isSymbol():
304
+ value['name'] = token
305
+ symbolRecord = self.getSymbolRecord()
306
+ keyword = symbolRecord['keyword']
307
+ if keyword == 'module':
308
+ value['type'] = 'module'
309
+ return value
310
+
311
+ if symbolRecord['valueHolder'] == True or keyword == 'dictionary':
312
+ value['type'] = 'symbol'
313
+ return value
314
+ return None
315
+
316
+ if self.tokenIs('the'):
317
+ self.nextToken()
318
+ token = self.getToken()
319
+
320
+ value['type'] = token
321
+
322
+ if token == 'color':
323
+ name = self.nextToken()
324
+ value = {}
325
+ value['type'] = 'string'
326
+ value['content'] = name
327
+ return value
328
+
329
+ elif token == 'attribute':
330
+ value['attribute'] = self.nextValue()
331
+ if (self.nextIs('of')):
332
+ if (self.nextIsSymbol()):
333
+ value['name'] = self.getToken()
334
+ return value
335
+ return None
336
+
337
+ #############################################################################
338
+ # Modify a value or leave it unchanged.
339
+ def modifyValue(self, value):
340
+ return value
341
+
342
+ #############################################################################
343
+ # Value handlers
344
+
345
+ def v_symbol(self, symbolRecord):
346
+ result = {}
347
+ if symbolRecord['valueHolder']:
348
+ symbolValue = self.getSymbolValue(symbolRecord)
349
+ if symbolValue == None:
350
+ return None
351
+ result['type'] = symbolValue['type']
352
+ content = symbolValue['content']
353
+ if content == None:
354
+ return ''
355
+ result['content'] = content
356
+ return result
357
+ else:
358
+ return ''
359
+
360
+ def v_attribute(self, v):
361
+ target = self.getVariable(v['name'])
362
+ attribute = self.getRuntimeValue(v['attribute'])
363
+ name = target['value'][target['index']]['content']
364
+ value = {}
365
+ value['type'] = 'int'
366
+ value['content'] = getAttribute(name, attribute)
367
+ return value
368
+
369
+ #############################################################################
370
+ # Compile a condition
371
+ def compileCondition(self):
372
+ condition = {}
373
+ return condition
374
+
375
+ #############################################################################
376
+ # Condition handlers