easycoder 241215.1__tar.gz → 241227.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 (78) hide show
  1. {easycoder-241215.1 → easycoder-241227.1}/PKG-INFO +3 -3
  2. {easycoder-241215.1 → easycoder-241227.1}/README.md +2 -2
  3. {easycoder-241215.1 → easycoder-241227.1}/easycoder/__init__.py +2 -2
  4. easycoder-241227.1/easycoder/ec.py +10 -0
  5. {easycoder-241215.1 → easycoder-241227.1}/easycoder/ec_classes.py +3 -0
  6. {easycoder-241215.1 → easycoder-241227.1}/easycoder/ec_compiler.py +7 -6
  7. {easycoder-241215.1 → easycoder-241227.1}/easycoder/ec_core.py +4 -2
  8. easycoder-241227.1/easycoder/ec_graphics.py +371 -0
  9. {easycoder-241215.1 → easycoder-241227.1}/easycoder/ec_handler.py +1 -0
  10. {easycoder-241215.1 → easycoder-241227.1}/easycoder/ec_program.py +26 -28
  11. easycoder-241227.1/easycoder/ec_renderer.py +185 -0
  12. easycoder-241227.1/easycoder/ec_screenspec.py +78 -0
  13. {easycoder-241215.1 → easycoder-241227.1}/easycoder/ec_value.py +10 -10
  14. easycoder-241227.1/images/Semoigo Dawn.jpg +0 -0
  15. easycoder-241227.1/json/graphics-demo.json +75 -0
  16. easycoder-241227.1/scripts/graphics-demo.ecg +102 -0
  17. easycoder-241215.1/easycoder/ec_graphics.py +0 -376
  18. easycoder-241215.1/easycoder/ec_renderer.py +0 -330
  19. easycoder-241215.1/scripts/graphics-demo.ecs +0 -70
  20. easycoder-241215.1/scripts/graphics-demo.json +0 -36
  21. {easycoder-241215.1 → easycoder-241227.1}/LICENSE +0 -0
  22. {easycoder-241215.1 → easycoder-241227.1}/doc/README.md +0 -0
  23. {easycoder-241215.1 → easycoder-241227.1}/doc/core/add.md +0 -0
  24. {easycoder-241215.1 → easycoder-241227.1}/doc/core/append.md +0 -0
  25. {easycoder-241215.1 → easycoder-241227.1}/doc/core/assert.md +0 -0
  26. {easycoder-241215.1 → easycoder-241227.1}/doc/core/begin.md +0 -0
  27. {easycoder-241215.1 → easycoder-241227.1}/doc/core/clear.md +0 -0
  28. {easycoder-241215.1 → easycoder-241227.1}/doc/core/close.md +0 -0
  29. {easycoder-241215.1 → easycoder-241227.1}/doc/core/create.md +0 -0
  30. {easycoder-241215.1 → easycoder-241227.1}/doc/core/debug.md +0 -0
  31. {easycoder-241215.1 → easycoder-241227.1}/doc/core/decrement.md +0 -0
  32. {easycoder-241215.1 → easycoder-241227.1}/doc/core/delete.md +0 -0
  33. {easycoder-241215.1 → easycoder-241227.1}/doc/core/divide.md +0 -0
  34. {easycoder-241215.1 → easycoder-241227.1}/doc/core/exit.md +0 -0
  35. {easycoder-241215.1 → easycoder-241227.1}/doc/core/file.md +0 -0
  36. {easycoder-241215.1 → easycoder-241227.1}/doc/core/fork.md +0 -0
  37. {easycoder-241215.1 → easycoder-241227.1}/doc/core/get.md +0 -0
  38. {easycoder-241215.1 → easycoder-241227.1}/doc/core/go.md +0 -0
  39. {easycoder-241215.1 → easycoder-241227.1}/doc/core/gosub.md +0 -0
  40. {easycoder-241215.1 → easycoder-241227.1}/doc/core/if.md +0 -0
  41. {easycoder-241215.1 → easycoder-241227.1}/doc/core/import.md +0 -0
  42. {easycoder-241215.1 → easycoder-241227.1}/doc/core/increment.md +0 -0
  43. {easycoder-241215.1 → easycoder-241227.1}/doc/core/index.md +0 -0
  44. {easycoder-241215.1 → easycoder-241227.1}/doc/core/init.md +0 -0
  45. {easycoder-241215.1 → easycoder-241227.1}/doc/core/input.md +0 -0
  46. {easycoder-241215.1 → easycoder-241227.1}/doc/core/multiply.md +0 -0
  47. {easycoder-241215.1 → easycoder-241227.1}/doc/core/open.md +0 -0
  48. {easycoder-241215.1 → easycoder-241227.1}/doc/core/pop.md +0 -0
  49. {easycoder-241215.1 → easycoder-241227.1}/doc/core/post.md +0 -0
  50. {easycoder-241215.1 → easycoder-241227.1}/doc/core/print.md +0 -0
  51. {easycoder-241215.1 → easycoder-241227.1}/doc/core/push.md +0 -0
  52. {easycoder-241215.1 → easycoder-241227.1}/doc/core/put.md +0 -0
  53. {easycoder-241215.1 → easycoder-241227.1}/doc/core/read.md +0 -0
  54. {easycoder-241215.1 → easycoder-241227.1}/doc/core/replace.md +0 -0
  55. {easycoder-241215.1 → easycoder-241227.1}/doc/core/return.md +0 -0
  56. {easycoder-241215.1 → easycoder-241227.1}/doc/core/script.md +0 -0
  57. {easycoder-241215.1 → easycoder-241227.1}/doc/core/set.md +0 -0
  58. {easycoder-241215.1 → easycoder-241227.1}/doc/core/split.md +0 -0
  59. {easycoder-241215.1 → easycoder-241227.1}/doc/core/stack.md +0 -0
  60. {easycoder-241215.1 → easycoder-241227.1}/doc/core/stop.md +0 -0
  61. {easycoder-241215.1 → easycoder-241227.1}/doc/core/system.md +0 -0
  62. {easycoder-241215.1 → easycoder-241227.1}/doc/core/take.md +0 -0
  63. {easycoder-241215.1 → easycoder-241227.1}/doc/core/toggle.md +0 -0
  64. {easycoder-241215.1 → easycoder-241227.1}/doc/core/truncate.md +0 -0
  65. {easycoder-241215.1 → easycoder-241227.1}/doc/core/variable.md +0 -0
  66. {easycoder-241215.1 → easycoder-241227.1}/doc/core/wait.md +0 -0
  67. {easycoder-241215.1 → easycoder-241227.1}/doc/core/while.md +0 -0
  68. {easycoder-241215.1 → easycoder-241227.1}/doc/core/write.md +0 -0
  69. {easycoder-241215.1 → easycoder-241227.1}/easycoder/ec_condition.py +0 -0
  70. {easycoder-241215.1 → easycoder-241227.1}/easycoder/ec_timestamp.py +0 -0
  71. {easycoder-241215.1 → easycoder-241227.1}/plugins/ec_p100.py +0 -0
  72. {easycoder-241215.1 → easycoder-241227.1}/plugins/example.py +0 -0
  73. {easycoder-241215.1 → easycoder-241227.1}/pyproject.toml +0 -0
  74. {easycoder-241215.1 → easycoder-241227.1}/scripts/benchmark.ecs +0 -0
  75. {easycoder-241215.1 → easycoder-241227.1}/scripts/fizzbuzz.ecs +0 -0
  76. {easycoder-241215.1 → easycoder-241227.1}/scripts/hello.ecs +0 -0
  77. {easycoder-241215.1 → easycoder-241227.1}/scripts/points.ecs +0 -0
  78. {easycoder-241215.1 → easycoder-241227.1}/scripts/tests.ecs +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: easycoder
3
- Version: 241215.1
3
+ Version: 241227.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>
@@ -62,7 +62,7 @@ Here in the repository is a folder called `scripts` containing some sample scrip
62
62
  ## Graphical programmming
63
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
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
+ 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
66
 
67
67
  ## EasyCoder programming reference
68
68
 
@@ -74,5 +74,5 @@ The language comprises a general-purpose core package, which can be enhanced by
74
74
 
75
75
  **_EasyCoder_** can be extended to add new functionality with the use of 'plugins'. These contain compiler and runtime modules for the added language features. **_EasyCoder_** can use the added keywords, values and conditions freely; the effect is completely seamless. There is an outline example in the `plugins` directory called `example.py`, which comprises a module called `Points` with new language syntax to deal with two-valued items such as coordinates. In the `scripts` directory there is `points.ecs`, which exercises the new functionality.
76
76
 
77
- A plugin can act as a wrapper around any Python functionality that has a sensible API, thereby hiding its complexity. The only challenge is to devise an unambiguous syntax that doesn't clash with anything already existing in **_EasyCoder_**
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
78
 
@@ -51,7 +51,7 @@ Here in the repository is a folder called `scripts` containing some sample scrip
51
51
  ## Graphical programmming
52
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
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
+ 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
55
 
56
56
  ## EasyCoder programming reference
57
57
 
@@ -63,4 +63,4 @@ The language comprises a general-purpose core package, which can be enhanced by
63
63
 
64
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.
65
65
 
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_**
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_**.
@@ -1,5 +1,6 @@
1
1
  '''EasyCoder for Python'''
2
2
 
3
+ from .ec import Main
3
4
  from .ec_classes import *
4
5
  from .ec_compiler import *
5
6
  from .ec_condition import *
@@ -8,6 +9,5 @@ from .ec_handler import *
8
9
  from .ec_program import *
9
10
  from .ec_timestamp import *
10
11
  from .ec_value import *
11
- from .ec_graphics import *
12
12
 
13
- __version__ = "241215.1"
13
+ __version__ = "241227.1"
@@ -0,0 +1,10 @@
1
+ import sys
2
+ from .ec_program import Program
3
+
4
+ # This is the program launcher
5
+ def Main():
6
+ print(f'Args: {sys.argv}')
7
+ if (len(sys.argv) > 1):
8
+ Program(sys.argv[1:]).start()
9
+ else:
10
+ print('Syntax: easycoder <scriptname>')
@@ -52,3 +52,6 @@ class Token:
52
52
 
53
53
  class Condition():
54
54
  negate = False
55
+
56
+ class Object():
57
+ pass
@@ -16,6 +16,7 @@ class Compiler:
16
16
  self.warnings = []
17
17
  self.program.compiler = self
18
18
  self.addCommand = self.program.add
19
+ self.compileConstant = self.value.compileConstant
19
20
 
20
21
  def getPC(self):
21
22
  return len(self.program.code)
@@ -44,6 +45,11 @@ class Compiler:
44
45
  except:
45
46
  return None
46
47
 
48
+ # Get a constant
49
+ def getConstant(self, token):
50
+ self.index += 1
51
+ return self.compileConstant(token)
52
+
47
53
  # Get a value
48
54
  def getValue(self):
49
55
  return self.value.compileValue()
@@ -53,11 +59,6 @@ class Compiler:
53
59
  self.index += 1
54
60
  return self.value.compileValue()
55
61
 
56
- # Get a constant
57
- def getConstant(self, token):
58
- self.index += 1
59
- return self.value.compileConstant(token)
60
-
61
62
  # Get a condition
62
63
  def getCondition(self):
63
64
  return self.condition.compileCondition()
@@ -101,7 +102,7 @@ class Compiler:
101
102
 
102
103
  def showWarnings(self):
103
104
  for warning in self.warnings:
104
- print(f'Warning: Line {self.getLino() + 1}: {warning}')
105
+ print(f'Warning at line {self.getLino() + 1} from {warning}')
105
106
 
106
107
  def getSymbolRecord(self):
107
108
  token = self.getToken()
@@ -724,8 +724,10 @@ class Core(Handler):
724
724
  FatalError(self.program.compiler, 'Unknown file open mode {self.getToken()}')
725
725
  return False
726
726
  command['mode'] = mode
727
- self.add(command)
728
- return True
727
+ else:
728
+ command['mode'] = 'r'
729
+ self.add(command)
730
+ return True
729
731
  else:
730
732
  FatalError(self.compiler, f'Variable "{self.getToken()}" is not a file')
731
733
  else:
@@ -0,0 +1,371 @@
1
+ from .ec_classes import FatalError, RuntimeError, Object
2
+ from .ec_handler import Handler
3
+ from .ec_screenspec import ScreenSpec
4
+ from .ec_renderer import Renderer
5
+
6
+ class Graphics(Handler):
7
+
8
+ def __init__(self, compiler):
9
+ Handler.__init__(self, compiler)
10
+
11
+ def getName(self):
12
+ return 'kivy'
13
+
14
+ #############################################################################
15
+ # Keyword handlers
16
+
17
+ def k_attach(self, command):
18
+ if self.nextIsSymbol():
19
+ record = self.getSymbolRecord()
20
+ command['name'] = record['name']
21
+ if self.nextIs('to'):
22
+ value = self.nextValue()
23
+ record['id'] = value
24
+ command['id'] = value
25
+ self.add(command)
26
+ return True
27
+
28
+ def r_attach(self, command):
29
+ targetRecord = self.getVariable(command['name'])
30
+ keyword = targetRecord['keyword']
31
+ id = self.getRuntimeValue(command['id'])
32
+ element = self.ui.getElement(id)
33
+ if element == None:
34
+ FatalError(self.program.compiler, f'There is no screen element with id \'{id}\'')
35
+ return -1
36
+ if element.getType() != keyword:
37
+ FatalError(self.program.compiler, f'Mismatched element type ({element['type']} and {keyword})')
38
+ self.putSymbolValue(targetRecord, {'type': 'text', 'content': id})
39
+ return self.nextPC()
40
+
41
+ # close window
42
+ def k_close(self, command):
43
+ if (self.nextIs('window')):
44
+ self.add(command)
45
+ return True
46
+ return False
47
+
48
+ def r_close(self, command):
49
+ self.renderer.stop()
50
+ return 0
51
+
52
+ # create window/ellipse/rectangle//text/image
53
+ def k_create(self, command):
54
+ token = self.nextToken()
55
+ if (token == 'window'):
56
+ t = {}
57
+ t['type'] = 'text'
58
+ t['content'] = 'EasyCoder'
59
+ width = self.compileConstant(640)
60
+ height = self.compileConstant(480)
61
+ left = self.compileConstant(100)
62
+ top = self.compileConstant(100)
63
+ r = self.compileConstant(255)
64
+ g = self.compileConstant(255)
65
+ b = self.compileConstant(255)
66
+ while True:
67
+ token = self.peek()
68
+ if token == 'title':
69
+ self.nextToken()
70
+ t = self.nextValue()
71
+ elif token == 'at':
72
+ self.nextToken()
73
+ left = self.nextValue()
74
+ top = self.nextValue()
75
+ elif token == 'size':
76
+ self.nextToken()
77
+ width = self.nextValue()
78
+ height = self.nextValue()
79
+ elif token == 'fill':
80
+ self.nextToken()
81
+ if self.nextIs('color'):
82
+ r = self.nextValue()
83
+ g = self.nextValue()
84
+ b = self.nextValue()
85
+ else:
86
+ break
87
+ command['type'] = 'window'
88
+ command['title'] = t
89
+ command['pos'] = (left, top)
90
+ command['size'] = (width, height)
91
+ command['fill'] = (r, g, b)
92
+ self.add(command)
93
+ return True
94
+
95
+ elif self.isSymbol():
96
+ record = self.getSymbolRecord()
97
+ command['target'] = record['name']
98
+ type = record['keyword']
99
+ command['type'] = type
100
+ if type in ['ellipse', 'rectangle', 'image']:
101
+ self.getElementData(type, command)
102
+ for item in ['width', 'height', 'left', 'bottom', 'r', 'g', 'b']:
103
+ if command[item] == None:
104
+ FatalError(self.program.compiler, f'Missing property \'{item}\'')
105
+ return True
106
+ elif type == 'text':
107
+ self.getElementData(type, command)
108
+ for item in ['width', 'height', 'left', 'bottom', 'r', 'g', 'b', 'text']:
109
+ if command[item] == None:
110
+ FatalError(self.program.compiler, f'Missing property \'{item}\'')
111
+ self.add(command)
112
+ record['elementID'] = command['id']
113
+ return False
114
+
115
+ def getElementData(self, type, command):
116
+ width = None
117
+ height = None
118
+ left = None
119
+ bottom = None
120
+ r = None
121
+ g = None
122
+ b = None
123
+ text = None
124
+ source = None
125
+ id = self.nextValue()
126
+ while True:
127
+ token = self.peek()
128
+ if token == 'size':
129
+ self.nextToken()
130
+ width = self.nextValue()
131
+ height = self.nextValue()
132
+ elif token == 'at':
133
+ self.nextToken()
134
+ left = self.nextValue()
135
+ bottom = self.nextValue()
136
+ elif token == 'fill':
137
+ self.nextToken()
138
+ r = self.nextValue()
139
+ g = self.nextValue()
140
+ b = self.nextValue()
141
+ elif token == 'text':
142
+ self.nextToken()
143
+ text = self.nextValue()
144
+ elif token == 'source':
145
+ self.nextToken()
146
+ source = self.nextValue()
147
+ else:
148
+ break
149
+ command['id'] = id
150
+ command['type'] = type
151
+ if width != None:
152
+ command['width'] = width
153
+ if height != None:
154
+ command['height'] = height
155
+ if left!= None:
156
+ command['left'] = left
157
+ if bottom != None:
158
+ command['bottom'] = bottom
159
+ if r != None:
160
+ command['r'] = r
161
+ if g != None:
162
+ command['g'] = g
163
+ if b != None:
164
+ command['b'] = b
165
+ if text != None:
166
+ command['text'] = text
167
+ if source != None:
168
+ command['source'] = source
169
+
170
+ def r_create(self, command):
171
+ try:
172
+ type = command['type']
173
+ if type == 'window':
174
+ self.windowSpec = Object()
175
+ self.windowSpec.title = command['title']['content']
176
+ self.windowSpec.flush = self.program.flush
177
+ self.windowSpec.finish = self.program.finish
178
+ self.windowSpec.pos = (self.getRuntimeValue(command['pos'][0]), self.getRuntimeValue(command['pos'][1]))
179
+ self.windowSpec.size = (self.getRuntimeValue(command['size'][0]), self.getRuntimeValue(command['size'][1]))
180
+ self.windowSpec.fill = (self.getRuntimeValue(command['fill'][0])/255, self.getRuntimeValue(command['fill'][1])/255, self.getRuntimeValue(command['fill'][2])/255)
181
+ else:
182
+ element = self.ui.createWidget(self.getWidgetSpec(command))
183
+ print(element)
184
+ except Exception as e:
185
+ RuntimeError(self.program, e)
186
+ return self.nextPC()
187
+
188
+ def getWidgetSpec(self, command):
189
+ spec = Object()
190
+ spec.id = self.getRuntimeValue(command['id'])
191
+ spec.type = command['type']
192
+ spec.w = self.getRuntimeValue(command['width'])
193
+ spec.h = self.getRuntimeValue(command['height'])
194
+ spec.x = self.getRuntimeValue(command['left'])
195
+ spec.y = self.getRuntimeValue(command['bottom'])
196
+ spec.r = self.getRuntimeValue(command['r'])/255
197
+ spec.g = self.getRuntimeValue(command['g'])/255
198
+ spec.b = self.getRuntimeValue(command['b'])/255
199
+ return spec
200
+
201
+ def k_ellipse(self, command):
202
+ return self.compileVariable(command)
203
+
204
+ def r_ellipse(self, command):
205
+ return self.nextPC()
206
+
207
+ def k_image(self, command):
208
+ return self.compileVariable(command)
209
+
210
+ def r_image(self, command):
211
+ return self.nextPC()
212
+
213
+ def k_on(self, command):
214
+ token = self.nextToken()
215
+ if token in ['click', 'tap']:
216
+ command['type'] = 'tap'
217
+ if self.nextIsSymbol():
218
+ target = self.getSymbolRecord()
219
+ else:
220
+ FatalError(self.program.compiler, f'{self.getToken()} is not a screen element')
221
+ return False
222
+ command['target'] = target['name']
223
+ command['goto'] = self.getPC() + 2
224
+ self.add(command)
225
+ self.nextToken()
226
+ pcNext = self.getPC()
227
+ cmd = {}
228
+ cmd['domain'] = 'core'
229
+ cmd['lino'] = command['lino']
230
+ cmd['keyword'] = 'gotoPC'
231
+ cmd['goto'] = 0
232
+ cmd['debug'] = False
233
+ self.addCommand(cmd)
234
+ self.compileOne()
235
+ cmd = {}
236
+ cmd['domain'] = 'core'
237
+ cmd['lino'] = command['lino']
238
+ cmd['keyword'] = 'stop'
239
+ cmd['debug'] = False
240
+ self.addCommand(cmd)
241
+ # Fixup the link
242
+ self.getCommandAt(pcNext)['goto'] = self.getPC()
243
+ return True
244
+ return False
245
+
246
+ def r_on(self, command):
247
+ pc = command['goto']
248
+ if command['type'] == 'tap':
249
+ record = self.getVariable(command['target'])
250
+ keyword = record['keyword']
251
+ if keyword in ['ellipse', 'rectangle', 'text', 'image']:
252
+ id = record['value'][record['index']]['content']
253
+ self.ui.setOnClick(id, lambda: self.run(pc))
254
+ else:
255
+ RuntimeError(self.program, f'{record['name']} is not a clickable object')
256
+ return self.nextPC()
257
+
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
+ def k_rectangle(self, command):
290
+ return self.compileVariable(command)
291
+
292
+ def r_rectangle(self, command):
293
+ return self.nextPC()
294
+
295
+ def k_text(self, command):
296
+ return self.compileVariable(command)
297
+
298
+ def r_text(self, command):
299
+ return self.nextPC()
300
+
301
+ # render {spec}
302
+ def k_render(self, command):
303
+ command['spec'] = self.nextValue()
304
+ self.add(command)
305
+ return True
306
+
307
+ def r_render(self, command):
308
+ self.ui = self.renderer.getUI()
309
+ ScreenSpec().render(self.getRuntimeValue(command['spec']), self.ui)
310
+ return self.nextPC()
311
+
312
+ # run graphics
313
+ def k_run(self, command):
314
+ if self.nextIs('graphics'):
315
+ self.add(command)
316
+ return True
317
+ return False
318
+
319
+ def r_run(self, command):
320
+ self.renderer = Renderer()
321
+ self.renderer.init(self.windowSpec)
322
+ self.program.setExternalControl()
323
+ self.program.run(self.nextPC())
324
+ self.renderer.run()
325
+
326
+ #############################################################################
327
+ # Modify a value or leave it unchanged.
328
+ def modifyValue(self, value):
329
+ return value
330
+
331
+ #############################################################################
332
+ # Compile a value in this domain
333
+ def compileValue(self):
334
+ value = {}
335
+ value['domain'] = self.getName()
336
+ if self.tokenIs('attribute'):
337
+ attribute = self.nextValue()
338
+ if self.nextIs('of'):
339
+ if self.nextIsSymbol():
340
+ record = self.getSymbolRecord()
341
+ if record['keyword'] in ['ellipse', 'rectangle']:
342
+ value['type'] = 'attribute'
343
+ value['attribute'] = attribute
344
+ value['target'] = record['name']
345
+ return value
346
+ return None
347
+
348
+ #############################################################################
349
+ # Value handlers
350
+
351
+ def v_attribute(self, v):
352
+ try:
353
+ attribute = self.getRuntimeValue(v['attribute'])
354
+ target = self.getVariable(v['target'])
355
+ val = self.getSymbolValue(target)
356
+ v = self.ui.getAttribute(val['content'], attribute)
357
+ value = {}
358
+ value['type'] = 'int'
359
+ value['content'] = int(round(v))
360
+ return value
361
+ except Exception as e:
362
+ RuntimeError(self.program, e)
363
+
364
+ #############################################################################
365
+ # Compile a condition
366
+ def compileCondition(self):
367
+ condition = {}
368
+ return condition
369
+
370
+ #############################################################################
371
+ # Condition handlers
@@ -25,6 +25,7 @@ class Handler:
25
25
  self.getCommandAt = compiler.getCommandAt
26
26
  self.compileOne = compiler.compileOne
27
27
  self.compileFromHere = compiler.compileFromHere
28
+ self.compileConstant = compiler.compileConstant
28
29
 
29
30
  self.code = self.program.code
30
31
  self.add = self.program.add
@@ -11,23 +11,18 @@ class Program:
11
11
 
12
12
  def __init__(self, argv):
13
13
  print(f'EasyCoder version {version("easycoder")}')
14
- scriptName = None
15
14
  if len(argv) == 0:
16
15
  print('No script supplied')
17
16
  exit()
18
17
  self.classes=[Core]
19
- for n in range(len(argv)):
20
- arg = argv[n]
21
- if arg == '-g':
22
- from .ec_graphics import Graphics
23
- self.classes.append(Graphics)
24
- else:
25
- scriptName = arg
18
+ scriptName = argv[0]
19
+ if scriptName.endswith('.ecg'):
20
+ from .ec_graphics import Graphics
21
+ self.classes.append(Graphics)
26
22
 
27
23
  f = open(scriptName, 'r')
28
24
  source = f.read()
29
25
  f.close()
30
- self.argv = argv
31
26
  self.domains = []
32
27
  self.domainIndex = {}
33
28
  self.name = '<anon>'
@@ -43,6 +38,8 @@ class Program:
43
38
  self.condition = self.compiler.condition
44
39
  self.processClasses()
45
40
  self.queue = deque()
41
+ self.externalControl = False
42
+ self.quit = False
46
43
 
47
44
  def start(self):
48
45
  startCompile = time.time()
@@ -242,18 +239,17 @@ class Program:
242
239
  index += 1
243
240
  lino += 1
244
241
  return
242
+
243
+ def finish(self):
244
+ self.quit = True
245
245
 
246
- # Run the script
247
- def run(self, pc):
248
- # print(f'Run from {pc}')
249
- length = len(self.queue)
250
- self.queue.append(pc)
251
- if length > 0:
252
- return
253
-
246
+ # Flush the queue
247
+ def flush(self):
254
248
  while len(self.queue):
255
249
  self.pc = self.queue.popleft()
256
250
  while True:
251
+ if self.quit:
252
+ return
257
253
  command = self.code[self.pc]
258
254
  domainName = command['domain']
259
255
  if domainName == None:
@@ -272,11 +268,20 @@ class Program:
272
268
  self.pc = handler(command)
273
269
  try:
274
270
  if self.pc == 0 or self.pc >= len(self.code):
275
- return 0
271
+ break
276
272
  except:
277
- return 0
278
- if self.pc < 0:
279
- return -1
273
+ break
274
+
275
+ def setExternalControl(self):
276
+ self.externalControl = True
277
+
278
+ # Run the script
279
+ def run(self, pc):
280
+ length = len(self.queue)
281
+ self.queue.append(pc)
282
+ if not self.externalControl:
283
+ if length == 0:
284
+ return self.flush()
280
285
 
281
286
  def nonNumericValueError(self):
282
287
  FatalError(self.compiler, 'Non-numeric value')
@@ -322,10 +327,3 @@ class Program:
322
327
  if v1 < v2:
323
328
  return -1
324
329
  return 0
325
-
326
- # This is the program launcher
327
- def Main():
328
- if (len(sys.argv) > 1):
329
- Program(sys.argv[1:]).start()
330
- else:
331
- print('Syntax: easycoder <scriptname> [plugins]')