easycoder 250423.2__py2.py3-none-any.whl → 250503.1__py2.py3-none-any.whl

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

Potentially problematic release.


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

easycoder/__init__.py CHANGED
@@ -9,4 +9,4 @@ from .ec_program import *
9
9
  from .ec_timestamp import *
10
10
  from .ec_value import *
11
11
 
12
- __version__ = "250423.2"
12
+ __version__ = "250503.1"
easycoder/ec_compiler.py CHANGED
@@ -87,6 +87,15 @@ class Compiler:
87
87
  def nextIsSymbol(self):
88
88
  self.next()
89
89
  return self.isSymbol()
90
+
91
+ def skip(self, token):
92
+ next = self.peek()
93
+ if type(token) == list:
94
+ for item in token:
95
+ if next == item:
96
+ self.nextToken()
97
+ return
98
+ elif next == token: self.nextToken()
90
99
 
91
100
  def rewindTo(self, index):
92
101
  self.index = index
@@ -114,10 +123,10 @@ class Compiler:
114
123
  def compileLabel(self, command):
115
124
  return self.compileSymbol(command, self.getToken(), False)
116
125
 
117
- def compileVariable(self, command, hasValue = False):
118
- return self.compileSymbol(command, self.nextToken(), hasValue)
126
+ def compileVariable(self, command, hasValue = False, extra=None):
127
+ return self.compileSymbol(command, self.nextToken(), hasValue, extra)
119
128
 
120
- def compileSymbol(self, command, name, hasValue):
129
+ def compileSymbol(self, command, name, hasValue, extra=None):
121
130
  try:
122
131
  v = self.symbols[name]
123
132
  except:
@@ -137,6 +146,7 @@ class Compiler:
137
146
  command['debug'] = False
138
147
  command['import'] = None
139
148
  command['locked'] = False
149
+ command['extra'] = extra
140
150
  self.addCommand(command)
141
151
  return True
142
152
 
@@ -164,7 +174,7 @@ class Compiler:
164
174
  self.rewindTo(mark)
165
175
  else:
166
176
  self.rewindTo(mark)
167
- FatalError(self, f'No handler found for "{token}"')
177
+ FatalError(self, f'Unable to compile this "{token}" command. Perhaps a syntax error?')
168
178
 
169
179
  # Compile a single command
170
180
  def compileOne(self):
easycoder/ec_core.py CHANGED
@@ -14,6 +14,9 @@ class Core(Handler):
14
14
 
15
15
  def getName(self):
16
16
  return 'core'
17
+
18
+ def noSymbolWarning(self):
19
+ self.warning(f'Symbol "{self.getToken()}" not found')
17
20
 
18
21
  #############################################################################
19
22
  # Keyword handlers
@@ -161,7 +164,6 @@ class Core(Handler):
161
164
  val['type'] = 'boolean'
162
165
  val['content'] = False
163
166
  self.putSymbolValue(target, val)
164
- # self.add(command)
165
167
  return self.nextPC()
166
168
 
167
169
  # Close a file
@@ -367,6 +369,8 @@ class Core(Handler):
367
369
  return True
368
370
 
369
371
  def r_exit(self, command):
372
+ if self.program.graphics != None:
373
+ self.program.graphics.force_exit()
370
374
  return -1
371
375
 
372
376
  # Declare a file variable
@@ -717,7 +721,7 @@ class Core(Handler):
717
721
  try:
718
722
  with open(filename) as f: content = f.read()
719
723
  except:
720
- RuntimeError(self.program, f'File \'{filename}\' not found')
724
+ content = ''
721
725
  try:
722
726
  if filename.endswith('.json'): content = json.loads(content)
723
727
  except:
@@ -1295,7 +1299,10 @@ class Core(Handler):
1295
1299
  if self.nextIsSymbol():
1296
1300
  command['target'] = self.getSymbolRecord()['name']
1297
1301
  if self.nextIs('to'):
1298
- command['value'] = self.nextValue()
1302
+ value = self.nextValue()
1303
+ if value == None:
1304
+ FatalError(self.compiler, 'Unable to get a value')
1305
+ command['value'] = value
1299
1306
  self.add(command)
1300
1307
  return True
1301
1308
 
@@ -1379,6 +1386,33 @@ class Core(Handler):
1379
1386
  self.putSymbolValue(targetVariable, val)
1380
1387
  return self.nextPC()
1381
1388
 
1389
+ # Shuffle a list
1390
+ def k_shuffle(self, command):
1391
+ if self.nextIsSymbol():
1392
+ symbolRecord = self.getSymbolRecord()
1393
+ if symbolRecord['hasValue']:
1394
+ command['target'] = self.getToken()
1395
+ self.add(command)
1396
+ return True
1397
+ self.warning(f'Core.negate: Variable "{symbolRecord["name"]}" does not hold a value')
1398
+ return False
1399
+
1400
+ def r_shuffle(self, command):
1401
+ symbolRecord = self.getVariable(command['target'])
1402
+ if not symbolRecord['hasValue']:
1403
+ RuntimeError(self.program, f'{symbolRecord["name"]} does not hold a value')
1404
+ return None
1405
+ value = self.getSymbolValue(symbolRecord)
1406
+ if value == None:
1407
+ RuntimeError(self.program, f'{symbolRecord["name"]} has not been initialised')
1408
+ content = value['content']
1409
+ if isinstance(content, list):
1410
+ random.shuffle(content)
1411
+ value['content'] = content
1412
+ self.putSymbolValue(symbolRecord, value)
1413
+ return self.nextPC()
1414
+ RuntimeError(self.program, f'{symbolRecord["name"]} is not a list')
1415
+
1382
1416
  # Split a string into a variable with several elements
1383
1417
  # split {variable} on {value}
1384
1418
  def k_split(self, command):
@@ -1400,6 +1434,7 @@ class Core(Handler):
1400
1434
  command['on'] = self.nextValue()
1401
1435
  self.add(command)
1402
1436
  return True
1437
+ else: self.noSymbolWarning()
1403
1438
  return False
1404
1439
 
1405
1440
  def r_split(self, command):
@@ -1419,33 +1454,6 @@ class Core(Handler):
1419
1454
 
1420
1455
  return self.nextPC()
1421
1456
 
1422
- # Shuffle a list
1423
- def k_shuffle(self, command):
1424
- if self.nextIsSymbol():
1425
- symbolRecord = self.getSymbolRecord()
1426
- if symbolRecord['hasValue']:
1427
- command['target'] = self.getToken()
1428
- self.add(command)
1429
- return True
1430
- self.warning(f'Core.negate: Variable "{symbolRecord["name"]}" does not hold a value')
1431
- return False
1432
-
1433
- def r_shuffle(self, command):
1434
- symbolRecord = self.getVariable(command['target'])
1435
- if not symbolRecord['hasValue']:
1436
- RuntimeError(self.program, f'{symbolRecord["name"]} does not hold a value')
1437
- return None
1438
- value = self.getSymbolValue(symbolRecord)
1439
- if value == None:
1440
- RuntimeError(self.program, f'{symbolRecord["name"]} has not been initialised')
1441
- content = value['content']
1442
- if isinstance(content, list):
1443
- random.shuffle(content)
1444
- value['content'] = content
1445
- self.putSymbolValue(symbolRecord, value)
1446
- return self.nextPC()
1447
- RuntimeError(self.program, f'{symbolRecord["name"]} is not a list')
1448
-
1449
1457
  # Declare a stack variable
1450
1458
  def k_stack(self, command):
1451
1459
  return self.compileVariable(command)
@@ -1599,7 +1607,9 @@ class Core(Handler):
1599
1607
 
1600
1608
  def k_use(self, command):
1601
1609
  if self.nextIs('graphics'):
1602
- from .ec_pyside6 import Graphics
1610
+ print('Loading graphics module')
1611
+ from .ec_pyside import Graphics
1612
+ self.program.graphics = Graphics
1603
1613
  self.program.classes.append(Graphics)
1604
1614
  self.program.processClasses()
1605
1615
  return True
@@ -1762,7 +1772,7 @@ class Core(Handler):
1762
1772
  if token in ['now', 'today', 'newline', 'tab', 'empty']:
1763
1773
  return value
1764
1774
 
1765
- if token in ['stringify', 'json', 'lowercase', 'uppercase', 'hash', 'random', 'float', 'integer', 'encode', 'decode']:
1775
+ if token in ['stringify', 'prettify', 'json', 'lowercase', 'uppercase', 'hash', 'random', 'float', 'integer', 'encode', 'decode']:
1766
1776
  value['content'] = self.nextValue()
1767
1777
  return value
1768
1778
 
@@ -2272,6 +2282,13 @@ class Core(Handler):
2272
2282
  value['content'] = haystack.rfind(needle) if last else haystack.find(needle)
2273
2283
  return value
2274
2284
 
2285
+ def v_prettify(self, v):
2286
+ item = self.getRuntimeValue(v['content'])
2287
+ value = {}
2288
+ value['type'] = 'text'
2289
+ value['content'] = json.dumps(item, indent=4)
2290
+ return value
2291
+
2275
2292
  def v_property(self, v):
2276
2293
  propertyValue = self.getRuntimeValue(v['name'])
2277
2294
  if 'target' in v:
easycoder/ec_handler.py CHANGED
@@ -7,6 +7,7 @@ class Handler:
7
7
  self.program = compiler.program
8
8
  self.getToken = compiler.getToken
9
9
  self.nextToken = compiler.nextToken
10
+ self.skip = compiler.skip
10
11
  self.peek = compiler.peek
11
12
  self.getValue = compiler.getValue
12
13
  self.nextValue = compiler.nextValue
easycoder/ec_program.py CHANGED
@@ -78,7 +78,7 @@ class Program:
78
78
  while True:
79
79
  if self.running == True:
80
80
  flush()
81
- time.sleep(0.1)
81
+ time.sleep(0.01)
82
82
  else:
83
83
  break
84
84
 
@@ -1,6 +1,7 @@
1
1
  import sys
2
2
  from easycoder import Handler, FatalError, RuntimeError
3
3
  from PySide6.QtCore import Qt, QTimer
4
+ from PySide6.QtGui import QPixmap
4
5
  from PySide6.QtWidgets import (
5
6
  QApplication,
6
7
  QCheckBox,
@@ -30,7 +31,8 @@ from PySide6.QtWidgets import (
30
31
  QSpacerItem,
31
32
  QSizePolicy,
32
33
  QDialog,
33
- QMessageBox
34
+ QMessageBox,
35
+ QDialogButtonBox
34
36
  )
35
37
 
36
38
  class Graphics(Handler):
@@ -84,28 +86,30 @@ class Graphics(Handler):
84
86
 
85
87
  # Here it's either (1) or (2)
86
88
  elif self.isSymbol():
87
- if self.peek() == 'to':
88
- # (2)
89
- record = self.getSymbolRecord()
90
- command['widget'] = record['name']
91
- self.nextToken()
92
- return addToLayout()
93
- else:
94
- # (1)
95
- command['value'] = self.getValue()
96
- if self.nextIs('to'):
97
- if self.nextIsSymbol():
89
+ record = self.getSymbolRecord()
90
+ if record['extra'] == 'gui':
91
+ if self.peek() == 'to':
92
+ # (2)
98
93
  record = self.getSymbolRecord()
99
94
  command['widget'] = record['name']
100
- self.add(command)
101
- return True
95
+ self.nextToken()
96
+ return addToLayout()
97
+ return False
98
+ # (1)
99
+ command['value'] = self.getValue()
100
+ self.skip('to')
101
+ if self.nextIsSymbol():
102
+ record = self.getSymbolRecord()
103
+ command['widget'] = record['name']
104
+ self.add(command)
105
+ return True
102
106
  return False
103
107
 
104
108
  def r_add(self, command):
105
109
  if 'value' in command:
106
110
  value = self.getRuntimeValue(command['value'])
107
111
  widget = self.getVariable(command['widget'])
108
- if widget['keyword'] == 'combobox':
112
+ if widget['keyword'] in ['listbox', 'combobox']:
109
113
  widget['widget'].addItem(value)
110
114
  else:
111
115
  layoutRecord = self.getVariable(command['layout'])
@@ -132,14 +136,51 @@ class Graphics(Handler):
132
136
  else: layout.addWidget(widget)
133
137
  return self.nextPC()
134
138
 
139
+ # Center one window on another
140
+ # center {window2} on {window1}
141
+ def k_center(self, command):
142
+ if self.nextIsSymbol():
143
+ record = self.getSymbolRecord()
144
+ if record['keyword'] == 'window':
145
+ command['window2'] = record['name']
146
+ self.skip('on')
147
+ if self.nextIsSymbol():
148
+ record = self.getSymbolRecord()
149
+ if record['keyword'] == 'window':
150
+ command['window1'] = record['name']
151
+ self.add(command)
152
+ return True
153
+ return False
154
+
155
+ def r_center(self, command):
156
+ window1 = self.getVariable(command['window1'])['window']
157
+ window2 = self.getVariable(command['window2'])['window']
158
+ geo1 = window1.geometry()
159
+ geo2 = window2.geometry()
160
+ geo2.moveCenter(geo1.center())
161
+ window2.setGeometry(geo2)
162
+ return self.nextPC()
163
+
135
164
  # Declare a checkbox variable
136
165
  def k_checkbox(self, command):
137
- return self.compileVariable(command, False)
166
+ return self.compileVariable(command, False, 'gui')
138
167
 
139
168
  def r_checkbox(self, command):
140
169
  return self.nextPC()
141
170
 
142
- # Close a window
171
+ # clear {widget}
172
+ def k_clear(self, command):
173
+ if self.nextIsSymbol():
174
+ command['name'] = self.getSymbolRecord()['name']
175
+ self.add(command)
176
+ return True
177
+ return False
178
+
179
+ def r_clear(self, command):
180
+ self.getVariable(command['name'])['widget'].clear()
181
+ return self.nextPC()
182
+
183
+ # close {window}
143
184
  def k_close(self, command):
144
185
  if self.nextIsSymbol():
145
186
  record = self.getSymbolRecord()
@@ -155,7 +196,7 @@ class Graphics(Handler):
155
196
 
156
197
  # Declare a combobox variable
157
198
  def k_combobox(self, command):
158
- return self.compileVariable(command, False)
199
+ return self.compileVariable(command, False, 'gui')
159
200
 
160
201
  def r_combobox(self, command):
161
202
  return self.nextPC()
@@ -165,34 +206,39 @@ class Graphics(Handler):
165
206
  command['title'] = 'Default'
166
207
  x = None
167
208
  y = None
168
- w = 640
169
- h = 480
209
+ w = self.compileConstant(640)
210
+ h = self.compileConstant(480)
170
211
  while True:
171
212
  token = self.peek()
172
- if token in ['title', 'at', 'size']:
213
+ if token in ['title', 'at', 'size', 'layout']:
173
214
  self.nextToken()
174
215
  if token == 'title': command['title'] = self.nextValue()
175
216
  elif token == 'at':
176
217
  x = self.nextValue()
177
218
  y = self.nextValue()
178
219
  elif token == 'size':
179
- command['w'] = self.nextValue()
180
- command['h'] = self.nextValue()
220
+ w = self.nextValue()
221
+ h = self.nextValue()
222
+ elif token == 'layout':
223
+ if self.nextIsSymbol():
224
+ record = self.getSymbolRecord()
225
+ if record['keyword'] == 'layout':
226
+ command['layout'] = record['name']
227
+ else: return False
181
228
  else: break
182
- command['w'] = self.compileConstant(w)
183
- command['h'] = self.compileConstant(h)
184
229
  command['x'] = x
185
230
  command['y'] = y
231
+ command['w'] = w
232
+ command['h'] = h
186
233
  self.add(command)
187
234
  return True
188
235
 
189
236
  # Create a widget
190
237
  def k_createLayout(self, command):
191
- if self.nextIs('type'):
192
- command['type'] = self.nextToken()
193
- self.add(command)
194
- return True
195
- return False
238
+ self.skip('type')
239
+ command['type'] = self.nextToken()
240
+ self.add(command)
241
+ return True
196
242
 
197
243
  def k_createGroupBox(self, command):
198
244
  if self.peek() == 'title':
@@ -204,7 +250,7 @@ class Graphics(Handler):
204
250
  return True
205
251
 
206
252
  def k_createLabel(self, command):
207
- text = ''
253
+ text = self.compileConstant('')
208
254
  while True:
209
255
  token = self.peek()
210
256
  if token == 'text':
@@ -213,6 +259,11 @@ class Graphics(Handler):
213
259
  elif token == 'size':
214
260
  self.nextToken()
215
261
  command['size'] = self.nextValue()
262
+ elif token == 'align':
263
+ self.nextToken()
264
+ token = self.nextToken()
265
+ if token in ['left', 'right', 'center', 'centre', 'justify']:
266
+ command['align'] = token
216
267
  else: break
217
268
  command['text'] = text
218
269
  self.add(command)
@@ -260,38 +311,50 @@ class Graphics(Handler):
260
311
  return True
261
312
 
262
313
  def k_createDialog(self, command):
263
- if self.peek() == 'title':
314
+ if self.peek() == 'on':
264
315
  self.nextToken()
265
- title = self.nextValue()
266
- else: title = ''
316
+ if self.nextIsSymbol():
317
+ command['window'] = self.getSymbolRecord()['name']
318
+ else: command['window'] = None
319
+ title = ''
320
+ while True:
321
+ if self.peek() == 'title':
322
+ self.nextToken()
323
+ title = self.nextValue()
324
+ elif self.peek() == 'layout':
325
+ self.nextToken()
326
+ if self.nextIsSymbol():
327
+ command['layout'] = self.getSymbolRecord()['name']
328
+ else: break
267
329
  command['title'] = title
268
330
  self.add(command)
269
331
  return True
270
332
 
271
333
  def k_createMessageBox(self, command):
272
- if self.nextIs('on'):
334
+ if self.peek() == 'on':
335
+ self.nextToken()
273
336
  if self.nextIsSymbol():
274
337
  command['window'] = self.getSymbolRecord()['name']
275
- style = 'question'
276
- title = ''
277
- message = ''
278
- while True:
279
- if self.peek() == 'style':
280
- self.nextToken()
281
- style = self.nextToken()
282
- elif self.peek() == 'title':
283
- self.nextToken()
284
- title = self.nextValue()
285
- elif self.peek() == 'message':
286
- self.nextToken()
287
- message = self.nextValue()
288
- else: break
289
- command['style'] = style
290
- command['title'] = title
291
- command['message'] = message
292
- self.add(command)
293
- return True
294
- return False
338
+ else: command['window'] = None
339
+ style = 'question'
340
+ title = ''
341
+ message = ''
342
+ while True:
343
+ if self.peek() == 'style':
344
+ self.nextToken()
345
+ style = self.nextToken()
346
+ elif self.peek() == 'title':
347
+ self.nextToken()
348
+ title = self.nextValue()
349
+ elif self.peek() == 'message':
350
+ self.nextToken()
351
+ message = self.nextValue()
352
+ else: break
353
+ command['style'] = style
354
+ command['title'] = title
355
+ command['message'] = message
356
+ self.add(command)
357
+ return True
295
358
 
296
359
  def k_create(self, command):
297
360
  if self.nextIsSymbol():
@@ -323,6 +386,9 @@ class Graphics(Handler):
323
386
  if y == None: y = (self.screenHeight - h) / 2
324
387
  else: y = self.getRuntimeValue(x)
325
388
  window.setGeometry(x, y, w, h)
389
+ container = QWidget()
390
+ container.setLayout(self.getVariable(command['layout'])['widget'])
391
+ window.setCentralWidget(container)
326
392
  record['window'] = window
327
393
  return self.nextPC()
328
394
 
@@ -347,17 +413,25 @@ class Graphics(Handler):
347
413
  if 'size' in command:
348
414
  fm = label.fontMetrics()
349
415
  c = label.contentsMargins()
350
- w = fm.horizontalAdvance('x') * self.getRuntimeValue(command['size']) +c.left()+c.right()
416
+ w = fm.horizontalAdvance('m') * self.getRuntimeValue(command['size']) +c.left()+c.right()
351
417
  label.setMaximumWidth(w)
418
+ if 'align' in command:
419
+ alignment = command['align']
420
+ if alignment == 'left': label.setAlignment(Qt.AlignLeft)
421
+ elif alignment == 'right': label.setAlignment(Qt.AlignRight)
422
+ elif alignment in ['center', 'centre']: label.setAlignment(Qt.AlignHCenter)
423
+ elif alignment == 'justify': label.setAlignment(Qt.AlignJustify)
352
424
  record['widget'] = label
353
425
  return self.nextPC()
354
426
 
355
427
  def r_createPushbutton(self, command, record):
356
- pushbutton = QPushButton(self.getRuntimeValue(command['text']))
428
+ text = self.getRuntimeValue(command['text'])
429
+ pushbutton = QPushButton(text)
430
+ pushbutton.setAccessibleName(text)
357
431
  if 'size' in command:
358
432
  fm = pushbutton.fontMetrics()
359
433
  c = pushbutton.contentsMargins()
360
- w = fm.horizontalAdvance('x') * self.getRuntimeValue(command['size']) +c.left()+c.right()
434
+ w = fm.horizontalAdvance('m') * self.getRuntimeValue(command['size']) +c.left()+c.right()
361
435
  pushbutton.setMaximumWidth(w)
362
436
  record['widget'] = pushbutton
363
437
  return self.nextPC()
@@ -386,8 +460,14 @@ class Graphics(Handler):
386
460
  return self.nextPC()
387
461
 
388
462
  def r_createDialog(self, command, record):
463
+ layout = self.getVariable(command['layout'])['widget']
389
464
  dialog = QDialog()
390
465
  dialog.setWindowTitle(self.getRuntimeValue(command['title']))
466
+ dialog.buttonBox = QDialogButtonBox((QDialogButtonBox.Ok | QDialogButtonBox.Cancel))
467
+ dialog.buttonBox.accepted.connect(dialog.accept)
468
+ dialog.buttonBox.rejected.connect(dialog.reject)
469
+ layout.addWidget(dialog.buttonBox)
470
+ dialog.setLayout(layout)
391
471
  record['dialog'] = dialog
392
472
  return self.nextPC()
393
473
 
@@ -450,7 +530,7 @@ class Graphics(Handler):
450
530
 
451
531
  # Create a group box
452
532
  def k_groupbox(self, command):
453
- return self.compileVariable(command, False)
533
+ return self.compileVariable(command, False, 'gui')
454
534
 
455
535
  def r_groupbox(self, command):
456
536
  return self.nextPC()
@@ -472,28 +552,28 @@ class Graphics(Handler):
472
552
 
473
553
  # Declare a label variable
474
554
  def k_label(self, command):
475
- return self.compileVariable(command, False)
555
+ return self.compileVariable(command, False, 'gui')
476
556
 
477
557
  def r_label(self, command):
478
558
  return self.nextPC()
479
559
 
480
560
  # Declare a layout variable
481
561
  def k_layout(self, command):
482
- return self.compileVariable(command, False)
562
+ return self.compileVariable(command, False, 'gui')
483
563
 
484
564
  def r_layout(self, command):
485
565
  return self.nextPC()
486
566
 
487
567
  # Declare a line input variable
488
568
  def k_lineinput(self, command):
489
- return self.compileVariable(command, False)
569
+ return self.compileVariable(command, False, 'gui')
490
570
 
491
571
  def r_lineinput(self, command):
492
572
  return self.nextPC()
493
573
 
494
574
  # Declare a listbox input variable
495
575
  def k_listbox(self, command):
496
- return self.compileVariable(command, False)
576
+ return self.compileVariable(command, False, 'gui')
497
577
 
498
578
  def r_listbox(self, command):
499
579
  return self.nextPC()
@@ -505,139 +585,247 @@ class Graphics(Handler):
505
585
  def r_messagebox(self, command):
506
586
  return self.nextPC()
507
587
 
508
- # Handle events
588
+ # on click {pushbutton}
589
+ # on select {combobox}/{listbox}
509
590
  def k_on(self, command):
510
- if self.nextIs('click'):
591
+ def setupOn():
592
+ command['name'] = record['name']
593
+ command['goto'] = self.getPC() + 2
594
+ self.add(command)
595
+ self.nextToken()
596
+ # Step over the click handler
597
+ pcNext = self.getPC()
598
+ cmd = {}
599
+ cmd['domain'] = 'core'
600
+ cmd['lino'] = command['lino']
601
+ cmd['keyword'] = 'gotoPC'
602
+ cmd['goto'] = 0
603
+ cmd['debug'] = False
604
+ self.addCommand(cmd)
605
+ # This is the click handler
606
+ self.compileOne()
607
+ cmd = {}
608
+ cmd['domain'] = 'core'
609
+ cmd['lino'] = command['lino']
610
+ cmd['keyword'] = 'stop'
611
+ cmd['debug'] = False
612
+ self.addCommand(cmd)
613
+ # Fixup the link
614
+ self.getCommandAt(pcNext)['goto'] = self.getPC()
615
+
616
+ token = self.nextToken()
617
+ if token == 'click':
511
618
  if self.nextIsSymbol():
512
619
  record = self.getSymbolRecord()
513
620
  if record['keyword'] == 'pushbutton':
514
- command['name'] = record['name']
515
- command['goto'] = self.getPC() + 2
516
- self.add(command)
517
- self.nextToken()
518
- # Step over the click handler
519
- pcNext = self.getPC()
520
- cmd = {}
521
- cmd['domain'] = 'core'
522
- cmd['lino'] = command['lino']
523
- cmd['keyword'] = 'gotoPC'
524
- cmd['goto'] = 0
525
- cmd['debug'] = False
526
- self.addCommand(cmd)
527
- # This is the click handler
528
- self.compileOne()
529
- cmd = {}
530
- cmd['domain'] = 'core'
531
- cmd['lino'] = command['lino']
532
- cmd['keyword'] = 'stop'
533
- cmd['debug'] = False
534
- self.addCommand(cmd)
535
- # Fixup the link
536
- self.getCommandAt(pcNext)['goto'] = self.getPC()
621
+ setupOn()
622
+ return True
623
+ elif token == 'select':
624
+ if self.nextIsSymbol():
625
+ record = self.getSymbolRecord()
626
+ if record['keyword'] in ['combobox', 'listbox']:
627
+ setupOn()
537
628
  return True
538
629
  return False
539
630
 
540
631
  def r_on(self, command):
541
- pushbutton = self.getVariable(command['name'])['widget']
542
- pushbutton.clicked.connect(lambda: self.run(command['goto']))
632
+ record = self.getVariable(command['name'])
633
+ widget = record['widget']
634
+ keyword = record['keyword']
635
+ if keyword == 'pushbutton':
636
+ widget.clicked.connect(lambda: self.run(command['goto']))
637
+ elif keyword == 'combobox':
638
+ widget.currentIndexChanged.connect(lambda: self.run(command['goto']))
639
+ elif keyword == 'listbox':
640
+ widget.itemClicked.connect(lambda: self.run(command['goto']))
543
641
  return self.nextPC()
544
642
 
545
643
  # Declare a pushbutton variable
546
644
  def k_pushbutton(self, command):
547
- return self.compileVariable(command, False)
645
+ return self.compileVariable(command, False, 'gui')
548
646
 
549
647
  def r_pushbutton(self, command):
550
648
  return self.nextPC()
551
649
 
552
- # remove current item from {combobox}
650
+ # remove [the] [current/selected] [item] [from/in] {combobox}/{listbox}
553
651
  def k_remove(self, command):
554
652
  command['variant'] = None
555
- if self.nextIs('current'):
556
- if self.nextIs('item'):
557
- if self.nextIs('from'):
558
- if self.nextIsSymbol():
559
- record = self.getSymbolRecord()
560
- if record['keyword'] == 'combobox':
561
- command['variant'] = 'current'
562
- command['name'] = record['name']
563
- self.addCommand(command)
564
- return True
653
+ self.skip('the')
654
+ self.skip(['current', 'selected'])
655
+ self.skip('item')
656
+ self.skip(['from', 'in'])
657
+ if self.nextIsSymbol():
658
+ record = self.getSymbolRecord()
659
+ if record['keyword'] == 'combobox':
660
+ command['variant'] = 'current'
661
+ command['name'] = record['name']
662
+ self.addCommand(command)
663
+ return True
664
+ elif record['keyword'] == 'listbox':
665
+ command['variant'] = 'current'
666
+ command['name'] = record['name']
667
+ self.addCommand(command)
668
+ return True
565
669
  return False
566
670
 
567
671
  def r_remove(self, command):
568
672
  variant = command['variant']
569
673
  record = self.getVariable(command['name'])
570
- if record['keyword'] == 'combobox' and variant == 'current':
571
- widget = record['widget']
572
- widget.removeItem(widget.currentIndex())
674
+ if variant == 'current':
675
+ if record['keyword'] == 'combobox':
676
+ widget = record['widget']
677
+ widget.removeItem(widget.currentIndex())
678
+ if record['keyword'] == 'listbox':
679
+ widget = record['widget']
680
+ selectedItem = widget.currentItem()
681
+ if selectedItem:
682
+ row = widget.row(selectedItem)
683
+ widget.takeItem(row)
573
684
  return self.nextPC()
574
685
 
575
- # This is called every 10ms to keep the main application running
576
- def flush(self):
577
- self.program.flushCB()
686
+ # select index {n} [of] {combobox]}
687
+ # select {name} [in] {combobox}
688
+ def k_select(self, command):
689
+ if self.nextIs('index'):
690
+ command['index'] = self.nextValue()
691
+ self.skip('of')
692
+ else:
693
+ command['name'] = self.nextValue()
694
+ self.skip('in')
695
+ if self.nextIsSymbol():
696
+ record = self.getSymbolRecord()
697
+ if record['keyword'] == 'combobox':
698
+ command['widget'] = record['name']
699
+ self.add(command)
700
+ return True
701
+ return False
702
+
703
+ def r_select(self, command):
704
+ widget = self.getVariable(command['widget'])['widget']
705
+ if 'index' in command:
706
+ index = self.getRuntimeValue(command['index'])
707
+ else:
708
+ name = self.getRuntimeValue(command['name'])
709
+ index = widget.findText(name, Qt.MatchFixedString)
710
+ if index >= 0:
711
+ widget.setCurrentIndex(index)
712
+ return self.nextPC()
578
713
 
579
- # Set something
714
+ # set [the] width/height [of] {widget} [to] {value}
715
+ # set [the] text [of] {label}/{button}/{lineinput} [to] {text}
716
+ # set [the] color [of] {label}/{button}/{lineinput} [to] {color}
717
+ # set {listbox} to {list}
580
718
  def k_set(self, command):
719
+ self.skip('the')
581
720
  token = self.nextToken()
582
- if token == 'the': token = self.nextToken()
583
- if token == 'height':
584
- command['property'] = token
585
- if self.nextToken() == 'of':
586
- if self.nextIsSymbol():
587
- record = self.getSymbolRecord()
588
- keyword = record['keyword']
589
- if keyword == 'groupbox':
590
- command['name'] = record['name']
591
- if self.nextIs('to'):
592
- command['value'] = self.nextValue()
593
- self.add(command)
594
- return True
721
+ command['what'] = token
722
+ if token in ['width', 'height']:
723
+ self.skip('of')
724
+ if self.nextIsSymbol():
725
+ record = self.getSymbolRecord()
726
+ if record['extra'] == 'gui':
727
+ command['name'] = record['name']
728
+ self.skip('to')
729
+ command['value'] = self.nextValue()
730
+ self.add(command)
731
+ return True
732
+ elif token == 'text':
733
+ self.skip('of')
734
+ if self.nextIsSymbol():
735
+ record = self.getSymbolRecord()
736
+ if record['keyword'] in ['label', 'pushbutton', 'lineinput']:
737
+ command['name'] = record['name']
738
+ self.skip('to')
739
+ command['value'] = self.nextValue()
740
+ self.add(command)
741
+ return True
742
+ elif token == 'color':
743
+ self.skip('of')
744
+ if self.nextIsSymbol():
745
+ record = self.getSymbolRecord()
746
+ if record['keyword'] == 'label':
747
+ command['name'] = record['name']
748
+ self.skip('to')
749
+ command['value'] = self.nextValue()
750
+ self.add(command)
751
+ return True
752
+ elif token == 'background':
753
+ self.skip('color')
754
+ self.skip('of')
755
+ if self.nextIsSymbol():
756
+ record = self.getSymbolRecord()
757
+ if record['keyword'] in ['label', 'pushbutton', 'lineinput']:
758
+ command['name'] = record['name']
759
+ self.skip('to')
760
+ command['value'] = self.nextValue()
761
+ self.add(command)
762
+ return True
763
+ elif self.isSymbol():
764
+ record = self.getSymbolRecord()
765
+ if record['keyword'] == 'listbox':
766
+ command['what'] = 'listbox'
767
+ command['name'] = record['name']
768
+ self.skip('to')
769
+ command['value'] = self.nextValue()
770
+ self.add(command)
771
+ return True
595
772
  return False
596
773
 
597
774
  def r_set(self, command):
598
- property = command['property']
599
- if property == 'height':
600
- groupbox = self.getVariable(command['name'])['widget']
601
- groupbox.setFixedHeight(self.getRuntimeValue(command['value']))
775
+ what = command['what']
776
+ if what == 'height':
777
+ widget = self.getVariable(command['name'])['widget']
778
+ widget.setFixedHeight(self.getRuntimeValue(command['value']))
779
+ elif what == 'width':
780
+ widget = self.getVariable(command['name'])['widget']
781
+ widget.setFixedWidth(self.getRuntimeValue(command['value']))
782
+ elif what == 'text':
783
+ record = self.getVariable(command['name'])
784
+ widget = self.getVariable(command['name'])['widget']
785
+ text = self.getRuntimeValue(command['value'])
786
+ widget.setText(text)
787
+ if record['keyword'] == 'pushbutton':
788
+ widget.setAccessibleName(text)
789
+ elif what == 'color':
790
+ widget = self.getVariable(command['name'])['widget']
791
+ color = self.getRuntimeValue(command['value'])
792
+ widget.setStyleSheet(f"color: {color};")
793
+ elif what == 'background-color':
794
+ widget = self.getVariable(command['name'])['widget']
795
+ bg_color = self.getRuntimeValue(command['value'])
796
+ widget.setStyleSheet(f"background-color: {bg_color};")
797
+ elif what == 'listbox':
798
+ widget = self.getVariable(command['name'])['widget']
799
+ value = self.getRuntimeValue(command['value'])
800
+ widget.addItems(value)
602
801
  return self.nextPC()
603
802
 
604
- # Show something
605
- # show {name} in {window}}
606
- # show {dialog}/{messagebox}
803
+ # show {window}
804
+ # show {dialog}
805
+ # show {messagebox} giving {result}}
607
806
  def k_show(self, command):
608
807
  if self.nextIsSymbol():
609
808
  record = self.getSymbolRecord()
610
809
  keyword = record['keyword']
611
- if keyword == 'layout':
612
- command['layout'] = record['name']
613
- if self.nextIs('in'):
614
- if self.nextIsSymbol():
615
- record = self.getSymbolRecord()
616
- if record['keyword'] == 'window':
617
- command['window'] = record['name']
618
- self.add(command)
619
- return True
810
+ if keyword == 'window':
811
+ command['window'] = record['name']
812
+ self.add(command)
813
+ return True
620
814
  elif keyword == 'dialog':
621
815
  command['dialog'] = record['name']
622
816
  self.add(command)
623
817
  return True
624
818
  elif keyword == 'messagebox':
625
819
  command['messagebox'] = record['name']
626
- if self.nextIs('giving'):
627
- if self.nextIsSymbol():
628
- command['result'] = self.getSymbolRecord()['name']
629
- self.add(command)
630
- return True
820
+ self.skip('giving')
821
+ if self.nextIsSymbol():
822
+ command['result'] = self.getSymbolRecord()['name']
823
+ self.add(command)
824
+ return True
631
825
  return False
632
826
 
633
827
  def r_show(self, command):
634
- if 'dialog' in command:
635
- dialog = self.getVariable(command['dialog'])['dialog']
636
- b1 = QPushButton("ok",dialog)
637
- b1.move(50,50)
638
- dialog.setWindowModality(Qt.ApplicationModal)
639
- dialog.exec_()
640
- elif 'messagebox' in command:
828
+ if 'messagebox' in command:
641
829
  data = self.getVariable(command['messagebox'])['data']
642
830
  symbolRecord = self.getVariable(command['result'])
643
831
  window = self.getVariable(data['window'])['window']
@@ -657,14 +845,12 @@ class Graphics(Handler):
657
845
  v['type'] = 'text'
658
846
  v['content'] = result
659
847
  self.putSymbolValue(symbolRecord, v)
660
- else:
661
- layoutRecord = self.getVariable(command['layout'])
662
- windowRecord = self.getVariable(command['window'])
663
- window = windowRecord['window']
664
- container = QWidget()
665
- container.setLayout(layoutRecord['widget'])
666
- window.setCentralWidget(container)
848
+ elif 'window' in command:
849
+ window = self.getVariable(command['window'])['window']
667
850
  window.show()
851
+ elif 'dialog' in command:
852
+ dialog = self.getVariable(command['dialog'])['dialog']
853
+ dialog.exec()
668
854
  return self.nextPC()
669
855
 
670
856
  # Start the graphics
@@ -676,12 +862,14 @@ class Graphics(Handler):
676
862
 
677
863
  def r_start(self, command):
678
864
  def on_last_window_closed():
679
- print("Performing cleanup...")
865
+ print("Kill the appication...")
680
866
  self.program.kill()
681
867
  def resume():
682
868
  self.program.flush(self.nextPC())
869
+ def flush():
870
+ self.program.flushCB()
683
871
  timer = QTimer()
684
- timer.timeout.connect(self.flush)
872
+ timer.timeout.connect(flush)
685
873
  timer.start(10)
686
874
  QTimer.singleShot(500, resume)
687
875
  self.app.lastWindowClosed.connect(on_last_window_closed)
@@ -693,7 +881,7 @@ class Graphics(Handler):
693
881
 
694
882
  def r_window(self, command):
695
883
  return self.nextPC()
696
-
884
+
697
885
  #############################################################################
698
886
  # Compile a value in this domain
699
887
  def compileValue(self):
@@ -710,15 +898,27 @@ class Graphics(Handler):
710
898
  token = self.getToken()
711
899
 
712
900
  if token == 'count':
713
- if self.nextIs('of'):
714
- if self.nextIsSymbol():
715
- value['type'] = 'symbol'
716
- record = self.getSymbolRecord()
717
- keyword = record['keyword']
718
- if keyword == 'combobox':
719
- value['type'] = 'count'
720
- value['name'] = record['name']
721
- return value
901
+ self.skip('of')
902
+ if self.nextIsSymbol():
903
+ value['type'] = 'symbol'
904
+ record = self.getSymbolRecord()
905
+ keyword = record['keyword']
906
+ if keyword in ['combobox', 'listbox']:
907
+ value['type'] = 'count'
908
+ value['name'] = record['name']
909
+ return value
910
+
911
+ if token == 'current':
912
+ self.skip('item')
913
+ self.skip('in')
914
+ if self.nextIsSymbol():
915
+ value['type'] = 'symbol'
916
+ record = self.getSymbolRecord()
917
+ keyword = record['keyword']
918
+ if keyword == 'listbox':
919
+ value['type'] = 'current'
920
+ value['name'] = record['name']
921
+ return value
722
922
 
723
923
  return None
724
924
 
@@ -734,24 +934,53 @@ class Graphics(Handler):
734
934
  def v_symbol(self, symbolRecord):
735
935
  symbolRecord = self.getVariable(symbolRecord['name'])
736
936
  keyword = symbolRecord['keyword']
737
- if keyword == 'combobox':
937
+ if keyword == 'pushbutton':
938
+ pushbutton = symbolRecord['widget']
939
+ v = {}
940
+ v['type'] = 'text'
941
+ v['content'] = pushbutton.accessibleName()
942
+ return v
943
+ elif keyword == 'lineinput':
944
+ lineinput = symbolRecord['widget']
945
+ v = {}
946
+ v['type'] = 'text'
947
+ v['content'] = lineinput.displayText()
948
+ return v
949
+ elif keyword == 'combobox':
738
950
  combobox = symbolRecord['widget']
739
951
  v = {}
740
952
  v['type'] = 'text'
741
953
  v['content'] = combobox.currentText()
742
954
  return v
955
+ elif keyword == 'listbox':
956
+ listbox = symbolRecord['widget']
957
+ content = listbox.currentItem().text()
958
+ v = {}
959
+ v['type'] = 'text'
960
+ v['content'] = content
961
+ return v
743
962
  return None
744
963
 
745
964
  def v_count(self, v):
746
965
  record = self.getVariable(v['name'])
747
966
  keyword = record['keyword']
748
967
  widget = record['widget']
749
- if keyword == 'combobox': content = widget.count()
968
+ if keyword in ['combobox', 'listbox']: content = widget.count()
750
969
  value = {}
751
970
  value['type'] = 'int'
752
971
  value['content'] = content
753
972
  return value
754
973
 
974
+ def v_current(self, v):
975
+ record = self.getVariable(v['name'])
976
+ keyword = record['keyword']
977
+ widget = record['widget']
978
+ if keyword == 'listbox': content = widget.currentItem().text()
979
+ value = {}
980
+ value['type'] = 'text'
981
+ value['content'] = content
982
+ return value
983
+
755
984
  #############################################################################
756
985
  # Compile a condition
757
986
  def compileCondition(self):
@@ -760,3 +989,22 @@ class Graphics(Handler):
760
989
 
761
990
  #############################################################################
762
991
  # Condition handlers
992
+
993
+ #############################################################################
994
+ # Force the application to exit
995
+ def force_exit(self):
996
+ QApplication.quit() # Gracefully close the application
997
+ sys.exit(0) # Force a complete system exit
998
+
999
+
1000
+ def addIconToLayout(layout, icon_path):
1001
+ """
1002
+ Adds an icon to the specified layout.
1003
+
1004
+ :param layout: The layout to which the icon will be added.
1005
+ :param icon_path: The file path of the icon image.
1006
+ """
1007
+ icon_label = QLabel()
1008
+ pixmap = QPixmap(icon_path)
1009
+ icon_label.setPixmap(pixmap)
1010
+ layout.addWidget(icon_label)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: easycoder
3
- Version: 250423.2
3
+ Version: 250503.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>
@@ -11,7 +11,11 @@ Requires-Dist: pyside6
11
11
  Project-URL: Home, https://github.com/easycoder/easycoder-py
12
12
 
13
13
  # Introduction
14
- **_EasyCoder_** is a high-level English-like scripting language suited for prototyping and rapid testing of ideas. It operates on the command line and a graphics module is under construction. The language is written in Python and it acts as a fairly thin wrapper around standard Python functions, giving fast compilation and good runtime performance for general applications.
14
+ **_EasyCoder_** is a high-level English-like domain-specific scripting language (DSL) suited for prototyping and rapid testing of ideas. It operates on the command line and a graphics module is under construction. The language is written in Python and it acts as a fairly thin wrapper around standard Python functions, giving fast compilation and good runtime performance for general applications.
15
+
16
+ **_EasyCoder_** is well suited to building command-line or graphical applications for expressing random logic such as operating procedures and rules, or controlling physical systems, primarily wifi devices. It is particularly easy to construct and issue REST commands to local or remote web servers.
17
+
18
+ For more advanced applications, **_EasyCoder_** is designed to be extensible, by enabling extra language syntax to be added via plugin-in modules. Once these are installed they act as seamless extensions to the basic syntax provided. **_EasyCoder_** derives its power from the use of rich and comprehensive language rather than a complex system of frameworks such as those commonly used in modern programming. This makes it very easy to learn as our brains are wired to operate that way. Having said that, the needs of most control systems are usually served by a fairly modest number of keywords and syntactic variants.
15
19
  <hr>
16
20
 
17
21
  There is also a JavaScript version of **_EasyCoder_**, which provides a full set of graphical features to run in a browser. For this, please visit
@@ -23,15 +27,12 @@ Website: [https://easycoder.github.io](https://easycoder.github.io)
23
27
  ## Quick Start
24
28
  Install **_EasyCoder_** in your Python environment:
25
29
  ```
26
- pip install requests pytz easycoder
30
+ pip install requests easycoder
27
31
  ```
28
32
 
29
33
  Test the install by typing the command `easycoder`.
30
34
  <hr>
31
- On Linux, this will probably fail as the installer places the executable file in the `$HOME/.local/bin` directory. So give the command
32
- ```
33
- export PATH=$HOME/.local/bin:$PATH
34
- ```
35
+ On Linux, this will probably fail as the installer places the executable file in the `$HOME/.local/bin` directory. So give the command `export PATH=$HOME/.local/bin:$PATH`.
35
36
 
36
37
  To make this change permanent, edit your `.profile` file, adding the following:
37
38
  ```
@@ -42,7 +43,7 @@ fi
42
43
  ```
43
44
  <hr>
44
45
 
45
- Now write a test script, 'hello.ecs', containing the following:
46
+ Now write a test script, `hello.ecs`, containing the following:
46
47
  ```
47
48
  print `Hello, world!`
48
49
  exit
@@ -84,7 +85,7 @@ Here in the repository is a folder called `scripts` containing some sample scrip
84
85
  `benchmark.ecs` allows the performance of **_EasyCoder_** to be compared to other languages if a similar script is written for each one.
85
86
 
86
87
  ## Graphical programming
87
- **_EasyCoder_** includes a graphical programming environment based on PySide6, that is in the early stages of development. Some demo scripts will be included in the `scripts` directory as development proceeds.
88
+ **_EasyCoder_** includes a graphical programming environment based on PySide6, that is in under development. Some demo scripts will be included in the `scripts` directory as development proceeds. Anyone wishing to track progress can do so via this repository. At the time of writing we are transitioning from an early version based on PySimpleGUI to one based on PySide, the latter being an open product that matches the needs of a DSL better than does the former.
88
89
 
89
90
  ## Significant features
90
91
 
@@ -0,0 +1,18 @@
1
+ easycoder/README.md,sha256=BVXmYphcTJ6q6RN_9L6HtQukgCnOjSLVIsTM3lk-9aM,587
2
+ easycoder/__init__.py,sha256=nOSldJ2q0EIA4NLCRkG8vCCgqAc64CpgzIgBYq9yO78,262
3
+ easycoder/ec_classes.py,sha256=xnWBNak8oKydkFoxHLlq9wo3lIsB3aMnTDrqbtCfoWo,1512
4
+ easycoder/ec_compiler.py,sha256=vNOAKIK2pX_cW4mcxwCe0OR16iqeZqvZQ6JCgQ5MqtU,5062
5
+ easycoder/ec_condition.py,sha256=YXvSBQKEzKGCcgUGo3Qp8iHolXmm2BpEm0NimSDszIM,785
6
+ easycoder/ec_core.py,sha256=hmMHQ5UxJ8JS6gMmcttzmZGGHc6bXR624A5g8VCH3JY,91224
7
+ easycoder/ec_graphics.py,sha256=WXxKMB4GJSmxvk-FVbOTyufiUx4TYIzyDoB1PCAO3JY,16067
8
+ easycoder/ec_gutils.py,sha256=yqu4RRQ6VdRkC5B2ADBYsXzgNu76dLnekd9aUjdEgPw,6399
9
+ easycoder/ec_handler.py,sha256=zPDZ_hqdgNnkCd8B5HmSLkqsGgf4aDmqcUBOPHgo47U,2305
10
+ easycoder/ec_program.py,sha256=CxGYl1slYXNOYFxiSMc-BuXL_QztYuBfCXltPCtw1U4,10011
11
+ easycoder/ec_pyside.py,sha256=6GIZpnmIj9LissJopfqcSvc1i1qbl4h56PQsJXOu9XU,36005
12
+ easycoder/ec_timestamp.py,sha256=_3QFJPzIWZ9Rzk3SQOQJ-gwmvB07pg78k23SPntoZtY,288
13
+ easycoder/ec_value.py,sha256=zgDJTJhIg3yOvmnnKIfccIizmIhGbtvL_ghLTL1T5fg,2516
14
+ easycoder-250503.1.dist-info/entry_points.txt,sha256=JXAZbenl0TnsIft2FcGJbJ-4qoztVu2FuT8PFmWFexM,44
15
+ easycoder-250503.1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
16
+ easycoder-250503.1.dist-info/WHEEL,sha256=ssQ84EZ5gH1pCOujd3iW7HClo_O_aDaClUbX4B8bjKY,100
17
+ easycoder-250503.1.dist-info/METADATA,sha256=S-ZJU8J3jqERA2fkdZ1SHwRhJ_Xdp-QR1ByCOwStNHU,6803
18
+ easycoder-250503.1.dist-info/RECORD,,
@@ -1,18 +0,0 @@
1
- easycoder/README.md,sha256=BVXmYphcTJ6q6RN_9L6HtQukgCnOjSLVIsTM3lk-9aM,587
2
- easycoder/__init__.py,sha256=rXpc2iuRmzM8KsgUZWefLoHMii_uABr61154GK0iZ_0,262
3
- easycoder/ec_classes.py,sha256=xnWBNak8oKydkFoxHLlq9wo3lIsB3aMnTDrqbtCfoWo,1512
4
- easycoder/ec_compiler.py,sha256=WN4DMTU66kzOAwOGJe3KDoXj2nPvq19ACegQ-RSMglo,4780
5
- easycoder/ec_condition.py,sha256=YXvSBQKEzKGCcgUGo3Qp8iHolXmm2BpEm0NimSDszIM,785
6
- easycoder/ec_core.py,sha256=X66TBECPnp-82lEcCpaiJuXSy4Ex519iBK2BM-wGHaQ,90611
7
- easycoder/ec_graphics.py,sha256=WXxKMB4GJSmxvk-FVbOTyufiUx4TYIzyDoB1PCAO3JY,16067
8
- easycoder/ec_gutils.py,sha256=yqu4RRQ6VdRkC5B2ADBYsXzgNu76dLnekd9aUjdEgPw,6399
9
- easycoder/ec_handler.py,sha256=K7nBuQTH8l0k8hX1o2b4KhTnhZHGdf2fkEuX4FJXJs8,2277
10
- easycoder/ec_program.py,sha256=ZCcvI36iq9HG4o8rFwFxzVElzZ7PEeNOPMr8eqwz8ns,10010
11
- easycoder/ec_pyside6.py,sha256=0Z-uWrCq7Uz_C6WjN-9E0TDI-IHny14-j5sTc1a3LLg,26627
12
- easycoder/ec_timestamp.py,sha256=_3QFJPzIWZ9Rzk3SQOQJ-gwmvB07pg78k23SPntoZtY,288
13
- easycoder/ec_value.py,sha256=zgDJTJhIg3yOvmnnKIfccIizmIhGbtvL_ghLTL1T5fg,2516
14
- easycoder-250423.2.dist-info/entry_points.txt,sha256=JXAZbenl0TnsIft2FcGJbJ-4qoztVu2FuT8PFmWFexM,44
15
- easycoder-250423.2.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
16
- easycoder-250423.2.dist-info/WHEEL,sha256=ssQ84EZ5gH1pCOujd3iW7HClo_O_aDaClUbX4B8bjKY,100
17
- easycoder-250423.2.dist-info/METADATA,sha256=XZhRQ-0z-KpgImt8Nvyk46I6V_lZ1M2aet5VoR8hHYs,5617
18
- easycoder-250423.2.dist-info/RECORD,,