easycoder 250116.1__py2.py3-none-any.whl → 250116.4__py2.py3-none-any.whl

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

Potentially problematic release.


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

easycoder/__init__.py CHANGED
@@ -9,4 +9,4 @@ from .ec_program import *
9
9
  from .ec_timestamp import *
10
10
  from .ec_value import *
11
11
 
12
- __version__ = "250116.1"
12
+ __version__ = "250116.4"
easycoder/ec_compiler.py CHANGED
@@ -98,11 +98,11 @@ class Compiler:
98
98
  return self.tokens[self.index].lino
99
99
 
100
100
  def warning(self, message):
101
- self.warnings.append(message)
101
+ self.warnings.append(f'Warning at line {self.getLino() + 1} of {self.program.name}: {message}')
102
102
 
103
103
  def showWarnings(self):
104
104
  for warning in self.warnings:
105
- print(f'Warning at line {self.getLino() + 1} of {self.program.name}: {warning}')
105
+ print(warning)
106
106
 
107
107
  def getSymbolRecord(self):
108
108
  token = self.getToken()
easycoder/ec_graphics.py CHANGED
@@ -9,6 +9,7 @@ class Graphics(Handler):
9
9
  def __init__(self, compiler):
10
10
  Handler.__init__(self, compiler)
11
11
  self.utils = GUtils()
12
+ self.eventHandlers = {}
12
13
 
13
14
  def getName(self):
14
15
  return 'graphics'
@@ -18,17 +19,17 @@ class Graphics(Handler):
18
19
 
19
20
  def k_add(self, command):
20
21
  elements = []
21
- while True:
22
- if self.nextIsSymbol():
23
- symbolRecord = self.getSymbolRecord()
24
- name = symbolRecord['name']
25
- if 'iselement' in symbolRecord:
26
- elements.append(name)
27
- if self.peek() != 'and': break
28
- else: FatalError(self.program.compiler, f'"{name}" is not a graphic element')
29
- else: FatalError(self.program.compiler, f'Element expected; got "{self.getToken()}"')
30
- self.nextToken()
31
- command['elements'] = json.dumps(elements)
22
+ token = self.nextToken()
23
+ if self.isSymbol():
24
+ symbolRecord = self.getSymbolRecord()
25
+ name = symbolRecord['name']
26
+ if symbolRecord['keyword'] == 'layout':
27
+ elements.append(name)
28
+ command['args'] = name
29
+ else: FatalError(self.compiler.program, f'\'{name}\' is not a layout')
30
+ else:
31
+ command['type'] = token
32
+ command['args'] = self.utils.getArgs(self)
32
33
  if self.nextIs('to'):
33
34
  if self.nextIsSymbol():
34
35
  symbolRecord = self.getSymbolRecord()
@@ -40,14 +41,36 @@ class Graphics(Handler):
40
41
 
41
42
  def r_add(self, command):
42
43
  target = self.getVariable(command['target'])
43
- elements = json.loads(command['elements'])
44
+ type = command['type']
45
+ args = command['args']
44
46
  if not 'layout' in target:
45
47
  target['layout'] = []
46
- for element in elements:
47
- v = self.getVariable(element)
48
+ if args[0] == '{':
49
+ layout = json.loads(self.getRuntimeValue(json.loads(args)))
50
+ default = self.utils.getDefaultArgs(type)
51
+ for n in range(0, len(layout)):
52
+ args = self.utils.decode(default, layout[n])
53
+ target['layout'].append(self.utils.createElement(type, args))
54
+ else:
55
+ v = self.getVariable(args)
48
56
  target['layout'].append(v['layout'])
49
57
  return self.nextPC()
50
58
 
59
+ def k_capture(self, command):
60
+ if self.nextIs('event'):
61
+ if self.nextIs('as'):
62
+ if self.nextIsSymbol():
63
+ record = self.getSymbolRecord()
64
+ command['target'] = record['name']
65
+ self.addCommand(command)
66
+ return True
67
+ return False
68
+
69
+ def r_capture(self, command):
70
+ target = self.getVariable(command['target'])
71
+ self.putSymbolValue(target, self.getConstant(self.eventValues))
72
+ return self.nextPC()
73
+
51
74
  def k_close(self, command):
52
75
  if self.nextIsSymbol():
53
76
  symbolRecord = self.getSymbolRecord()
@@ -79,10 +102,6 @@ class Graphics(Handler):
79
102
  command['layout'] = symbolRecord['name']
80
103
  self.addCommand(command)
81
104
  return True
82
- elif type[0:2] == 'g_':
83
- command['args'] = self.compileConstant(self.utils.getArgs(self))
84
- self.addCommand(command)
85
- return True
86
105
  return False
87
106
 
88
107
  def r_create(self, command):
@@ -96,79 +115,10 @@ class Graphics(Handler):
96
115
  self.mainLoop()
97
116
  self.program.kill()
98
117
  return 0
99
- elif 'iselement' in record:
100
- layout = json.loads(self.getRuntimeValue(command['args']))
101
- args = self.utils.getDefaultArgs(type)
102
- content = json.loads(layout['content'])
103
- for n in range(0, len(content)):
104
- args = self.utils.decode(args, content[n])
105
- element = self.utils.createElement(type, args)
106
- record['layout'] = element
107
- return self.nextPC()
108
118
  else:
109
119
  RuntimeError(self.program, 'Variable is not a window or an element')
110
120
 
111
- def k_g_button(self, command):
112
- command['iselement'] = True
113
- return self.compileVariable(command)
114
-
115
- def r_g_button(self, command):
116
- return self.nextPC()
117
-
118
- def k_g_input(self, command):
119
- command['iselement'] = True
120
- return self.compileVariable(command)
121
-
122
- def r_g_input(self, command):
123
- return self.nextPC()
124
-
125
- def k_g_text(self, command):
126
- command['iselement'] = True
127
- return self.compileVariable(command)
128
-
129
- def r_g_text(self, command):
130
- return self.nextPC()
131
-
132
- def k_init(self, command):
133
- if self.nextIsSymbol():
134
- record = self.getSymbolRecord()
135
- if record['keyword'] == 'layout':
136
- command['target'] = record['name']
137
- if self.peek() == 'with':
138
- self.nextToken()
139
- if self.nextIsSymbol():
140
- record = self.getSymbolRecord()
141
- name = record['name']
142
- if record['iselement']:
143
- command['args'] = name
144
- else: FatalError(self.program.compiler, f'\'{name}\' is not a graphic element')
145
- else:
146
- command['type'] = self.getToken()
147
- command['args'] = self.utils.getArgs(self)
148
- else: command['args'] = None
149
- self.addCommand(command)
150
- return True
151
- return False
152
-
153
- def r_init(self, command):
154
- record = self.getVariable(command['target'])
155
- record['layout'] = []
156
- type = command['type']
157
- args = command['args']
158
- if args != None:
159
- if args[0] == '{':
160
- layout = json.loads(self.getRuntimeValue(json.loads(args)))
161
- args = self.utils.getDefaultArgs(type)
162
- for n in range(0, len(layout)):
163
- args = self.utils.decode(args, layout[n])
164
- record['layout'].append(self.utils.createElement(type, args))
165
- else:
166
- v = self.getVariable(args)
167
- record['layout'].append(v['layout'])
168
- return self.nextPC()
169
-
170
121
  def k_layout(self, command):
171
- command['iselement'] = True
172
122
  return self.compileVariable(command)
173
123
 
174
124
  def r_layout(self, command):
@@ -176,42 +126,8 @@ class Graphics(Handler):
176
126
 
177
127
  def k_on(self, command):
178
128
  token = self.nextToken()
179
- command['type'] = token
180
- if token == 'click':
181
- command['event'] = token
182
- if self.peek() == 'in':
183
- self.nextToken()
184
- if self.nextIs('screen'):
185
- command['target'] = None
186
- elif self.isSymbol():
187
- target = self.getSymbolRecord()
188
- command['target'] = target['name']
189
- else:
190
- FatalError(self.program.compiler, f'{self.getToken()} is not a screen element')
191
- return False
192
- command['goto'] = self.getPC() + 2
193
- self.add(command)
194
- self.nextToken()
195
- pcNext = self.getPC()
196
- cmd = {}
197
- cmd['domain'] = 'core'
198
- cmd['lino'] = command['lino']
199
- cmd['keyword'] = 'gotoPC'
200
- cmd['goto'] = 0
201
- cmd['debug'] = False
202
- self.addCommand(cmd)
203
- self.compileOne()
204
- cmd = {}
205
- cmd['domain'] = 'core'
206
- cmd['lino'] = command['lino']
207
- cmd['keyword'] = 'stop'
208
- cmd['debug'] = False
209
- self.addCommand(cmd)
210
- # Fixup the link
211
- self.getCommandAt(pcNext)['goto'] = self.getPC()
212
- return True
213
- elif token == 'tick':
214
- command['event'] = token
129
+ if token == 'event':
130
+ command['key'] = self.nextValue()
215
131
  command['goto'] = self.getPC() + 2
216
132
  self.add(command)
217
133
  self.nextToken()
@@ -236,17 +152,9 @@ class Graphics(Handler):
236
152
  return False
237
153
 
238
154
  def r_on(self, command):
155
+ key = self.getRuntimeValue(command['key'])
239
156
  pc = command['goto']
240
- if command['type'] == 'click':
241
- event = command['event']
242
- if event == 'click':
243
- target = command['target']
244
- if target == None:
245
- value = 'screen'
246
- else:
247
- widget = self.getVariable(target)
248
- value = widget['value'][widget['index']]
249
- self.renderer.setOnClick(value['content'], lambda: self.run(pc))
157
+ self.eventHandlers[key] = lambda: self.run(pc)
250
158
  return self.nextPC()
251
159
 
252
160
  def k_popup(self, command):
@@ -259,9 +167,37 @@ class Graphics(Handler):
259
167
  return self.nextPC()
260
168
 
261
169
  def k_set(self, command):
262
- return True
170
+ if self.nextIsSymbol():
171
+ record = self.getSymbolRecord()
172
+ keyword = record['keyword']
173
+ if keyword == 'layout':
174
+ command['target'] = record['name']
175
+ if self.peek() == 'to':
176
+ self.nextToken()
177
+ command['type'] = self.nextToken()
178
+ command['args'] = self.utils.getArgs(self)
179
+ else: command['args'] = None
180
+ self.addCommand(command)
181
+ return True
182
+ elif keyword == 'event':
183
+ pass
184
+ return False
263
185
 
264
186
  def r_set(self, command):
187
+ target = self.getVariable(command['target'])
188
+ target['layout'] = []
189
+ type = command['type']
190
+ args = command['args']
191
+ if args != None:
192
+ if args[0] == '{':
193
+ layout = json.loads(self.getRuntimeValue(json.loads(args)))
194
+ default = self.utils.getDefaultArgs(type)
195
+ for n in range(0, len(layout)):
196
+ args = self.utils.decode(default, layout[n])
197
+ target['layout'].append(self.utils.createElement(type, args))
198
+ else:
199
+ v = self.getVariable(args)
200
+ target['layout'].append(v['layout'])
265
201
  return self.nextPC()
266
202
 
267
203
  def k_window(self, command):
@@ -274,19 +210,20 @@ class Graphics(Handler):
274
210
  # Compile a value in this domain
275
211
  def compileValue(self):
276
212
  value = {}
277
- value['domain'] = 'graphics'
213
+ value['domain'] = self.getName()
278
214
  token = self.getToken()
279
215
  if self.isSymbol():
216
+ value['name'] = token
217
+ symbolRecord = self.getSymbolRecord()
218
+ keyword = symbolRecord['keyword']
219
+ if keyword == 'event':
220
+ value['type'] = 'symbol'
221
+ return value
280
222
  return None
281
223
 
282
- if self.tokenIs('the'):
283
- self.nextToken()
284
- token = self.getToken()
285
-
286
224
  value['type'] = token
287
225
 
288
226
  if token == 'test':
289
- name = self.nextToken()
290
227
  value = {}
291
228
  value['type'] = 'text'
292
229
  value['content'] = 'test'
@@ -302,6 +239,13 @@ class Graphics(Handler):
302
239
  #############################################################################
303
240
  # Value handlers
304
241
 
242
+ # This is used by the expression evaluator to get the value of a symbol
243
+ def v_symbol(self, symbolRecord):
244
+ if symbolRecord['keyword'] == 'event':
245
+ return self.getSymbolValue(symbolRecord)
246
+ else:
247
+ return None
248
+
305
249
  def v_test(self, v):
306
250
  return v
307
251
 
@@ -323,4 +267,7 @@ class Graphics(Handler):
323
267
  break
324
268
  if event == '__TIMEOUT__': self.program.flushCB()
325
269
  else:
326
- print(event, values)
270
+ if event in self.eventHandlers:
271
+ self.eventValues = values
272
+ self.eventHandlers[event]()
273
+
easycoder/ec_gutils.py CHANGED
@@ -21,13 +21,13 @@ class GUtils:
21
21
  # Get the default args for a graphic element
22
22
  def getDefaultArgs(self, type):
23
23
  args = {}
24
- if type == 'g_text':
24
+ if type == 'Text':
25
25
  args['text'] = '(empty)'
26
26
  args['expand_x'] = False
27
- elif type == 'g_input':
27
+ elif type == 'Input':
28
28
  args['key'] = None
29
29
  args['size'] = (None, None)
30
- elif type == 'g_button':
30
+ elif type == 'Button':
31
31
  args['button_text'] = '(empty)'
32
32
  return args
33
33
 
@@ -43,10 +43,10 @@ class GUtils:
43
43
 
44
44
  # Create an element
45
45
  def createElement(self, type, args):
46
- if type == 'g_text': return psg.Text(text=args['text'], expand_x=args['expand_x'])
47
- elif type == 'g_input':
46
+ if type == 'Text': return psg.Text(text=args['text'], expand_x=args['expand_x'])
47
+ elif type == 'Input':
48
48
  size = args['size'].split()
49
49
  size = (size[0], size[1])
50
50
  return psg.Input(key=args['key'], size=size)
51
- elif type == 'g_button': return psg.Button(button_text=args['button_text'])
51
+ elif type == 'Button': return psg.Button(button_text=args['button_text'])
52
52
  else: return None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: easycoder
3
- Version: 250116.1
3
+ Version: 250116.4
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>
@@ -22,15 +22,30 @@ Website: [https://easycoder.github.io](https://easycoder.github.io)
22
22
  ## Quick Start
23
23
  Install **_EasyCoder_** in your Python environment:
24
24
  ```
25
- pip install easycoder
25
+ pip install requests pytz easycoder
26
26
  ```
27
- You may also need to install `pytz`, as some commands need it.
28
27
 
29
- Write a test script, 'hello.ecs', containing the following:
28
+ Test the install by typing the command `easycoder`.
29
+ <hr>
30
+ On Linux, this will probably fail as the installer places the executable file in the `$HOME/.local/bin` directory. So give the command
31
+ ```
32
+ export PATH=$HOME/.local/bin:$PATH
33
+ ```
34
+
35
+ To make this change permanent, edit your `.profile` file, adding the following:
36
+ ```
37
+ # set PATH so it includes user's private .local/bin if it exists
38
+ if [ -d "$HOME/.local/bin" ] ; then
39
+ PATH="$HOME/.local/bin:$PATH"
40
+ fi
41
+ ```
42
+ <hr>
43
+
44
+ Now write a test script, 'hello.ecs', containing the following:
30
45
  ```
31
46
  print `Hello, world!`
32
47
  ```
33
- This is traditionally the first program to be written in virtually any language. To run it, use `easycoder hello.ecs`.
48
+ (Note the backticks.) This is traditionally the first program to be written in virtually any language. To run it, use `easycoder hello.ecs`.
34
49
 
35
50
  The output will look like this (the version number will differ):
36
51
  ```
@@ -63,19 +78,18 @@ Here in the repository is a folder called `scripts` containing some sample scrip
63
78
  `benchmark.ecs` allows the performance of **_EasyCoder_** to be compared to other languages if a similar script is written for each one.
64
79
 
65
80
  ## Graphical programmming
66
- **_EasyCoder_** includes a graphical programming environment that is in the early stages of development. A couple of demo scripts are included in the `scripts` directory. To run them, first install the Python `kivy` graphics library if it's not already present on your system. This is done with `pip install kivy`. Then run your **_EasyCoder_** script using `easycoder {scriptname}.ecg`.
67
-
68
- Graphical scripts look much like any other script but their file names must use the extension `.ecg` to signal to **_EasyCoder_** that it needs to load the graphics module. Non-graphical applications can use any extension but `.ecs` is recommended. This allows the **_EasyCoder_** application to be used wherever Python is installed, in either a command-line or a graphical environment, but graphics will of course not be available in the former.
69
-
70
- Some demo graphical scripts are included in the `scripts` directory:
81
+ **_EasyCoder_** includes a graphical programming environment that is in the early stages of development. Some demo scripts will be included in the `scripts` directory; these can be recognised by the extension`.ecg`. To run them, first install `tkinter`. On Linux this is done with
82
+ ```
83
+ sudo apt install python3-tk
84
+ ```
71
85
 
72
- `graphics-demo.ecg` shows some of the elements that can be created, and demonstrates a variety of the graphical features of the language such as detecting when elements are clicked.
86
+ Next, install the Python `pySimpleGUI` graphics library; this is done with `pip install pysimplegui`. Then run your **_EasyCoder_** script using `easycoder {scriptname}.ecg`.
73
87
 
74
- `wave.ecg` is a "Mexican Wave" simulation.
88
+ Graphical scripts look much like any other script but their file names must use the extension `.ecg` to signal to **_EasyCoder_** that it needs to load the graphics module. Non-graphical applications can use any extension but `.ecs` is recommended. This allows the **_EasyCoder_** application to be used wherever Python is installed, in either a command-line or a graphical environment, but graphics will of course not be available in the former.
75
89
 
76
- `keyboard.ecg` creates an on-screen keyboard (currently a 4-function calculator keypad) that responds to clicks on its keys. It uses a plugin module (see below) to add extra vocabulary and syntax to the language. This is currently under development so its features are likely to change. The intention is to support a wide range of keyboard styles with the minimum mount of coding. The plugin (`ec_keyword.py`) can be downloaded from the repository.
90
+ Some demo graphical scripts will included in the `scripts` directory as development proceeds.
77
91
 
78
- **_EasyCoder_** graphics are handled by a library module, `ec_renderer` that can be used outside of the **_EasyCoder_** environment, in other Python programs. The renderer works with JSON-formatted specifications of the itens to be displayed.
92
+ `gtest.ecg` contains sample code to demonstrate and test basic features.
79
93
 
80
94
  ## Significant features
81
95
 
@@ -1,17 +1,17 @@
1
1
  easycoder/README.md,sha256=PYqOc_SkIGiFbyCNs90y7JqoqWe4aO1xYIW-6bOnFKU,573
2
- easycoder/__init__.py,sha256=6tfI5jOPMiZDuD7BsvqLihJFFijWgyIr-EKAapPxT-s,262
2
+ easycoder/__init__.py,sha256=7P--K2LPePX1pCo332aXacQgLD3I3uHKC3Qr56PA15o,262
3
3
  easycoder/ec_classes.py,sha256=xnWBNak8oKydkFoxHLlq9wo3lIsB3aMnTDrqbtCfoWo,1512
4
- easycoder/ec_compiler.py,sha256=f3zZRtbNsegBuRHTvTLK8BOdnuRq5p_p-1vtJYb-LiY,4800
4
+ easycoder/ec_compiler.py,sha256=dFJEA_uOhD-HeSiAdBzmmA6q3LHThUVoJpSETanmSHs,4800
5
5
  easycoder/ec_condition.py,sha256=WSbONo4zs2sX1icOVpscZDFSCAEFmTsquoc2RGcLx_k,763
6
6
  easycoder/ec_core.py,sha256=yO7d5OyEFHBDGKSaC1Fhf1uGjzsttAl6VCvR1W5X5YE,86279
7
- easycoder/ec_graphics.py,sha256=R1LVI-heohCM_uNwHas8VuTIOdxtT6-RMjhca_B5l4Q,11335
8
- easycoder/ec_gutils.py,sha256=fqh0VKfm2ry5yjHoOE1ufF7uu741lOU7EEwTUEabJ4k,1624
7
+ easycoder/ec_graphics.py,sha256=sjSB7K66oVB4gn8Byjlfs-qPUFoSNVbvK_0plPHI7dI,9423
8
+ easycoder/ec_gutils.py,sha256=9bjRCTBBSCEy6Z3pSkTaZIn_foWKZ79h6pswkLqCti4,1612
9
9
  easycoder/ec_handler.py,sha256=IJvxcrJJSR53d6DS_8H5qPHKhp9y5-GV4WXAjhZxu_o,2250
10
10
  easycoder/ec_program.py,sha256=wU-vWRWAYK2Ie4EFnp8HeSPUL0bxz-j9HLQSNplObcc,9919
11
11
  easycoder/ec_timestamp.py,sha256=_3QFJPzIWZ9Rzk3SQOQJ-gwmvB07pg78k23SPntoZtY,288
12
12
  easycoder/ec_value.py,sha256=zgDJTJhIg3yOvmnnKIfccIizmIhGbtvL_ghLTL1T5fg,2516
13
- easycoder-250116.1.dist-info/entry_points.txt,sha256=JXAZbenl0TnsIft2FcGJbJ-4qoztVu2FuT8PFmWFexM,44
14
- easycoder-250116.1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
15
- easycoder-250116.1.dist-info/WHEEL,sha256=Sgu64hAMa6g5FdzHxXv9Xdse9yxpGGMeagVtPMWpJQY,99
16
- easycoder-250116.1.dist-info/METADATA,sha256=L9ZijU5ykpK7eHLHghThRQcJ_xqxM3BKQfsLn1kcDAo,6426
17
- easycoder-250116.1.dist-info/RECORD,,
13
+ easycoder-250116.4.dist-info/entry_points.txt,sha256=JXAZbenl0TnsIft2FcGJbJ-4qoztVu2FuT8PFmWFexM,44
14
+ easycoder-250116.4.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
15
+ easycoder-250116.4.dist-info/WHEEL,sha256=Sgu64hAMa6g5FdzHxXv9Xdse9yxpGGMeagVtPMWpJQY,99
16
+ easycoder-250116.4.dist-info/METADATA,sha256=n5ZHkO3yF44XFEsO-x0DpIQBgmAT4XA0nZW7pG3DZ50,6162
17
+ easycoder-250116.4.dist-info/RECORD,,