easycoder 251103.4__py2.py3-none-any.whl → 251105.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.
easycoder/__init__.py CHANGED
@@ -12,4 +12,4 @@ from .ec_pyside import *
12
12
  from .ec_timestamp import *
13
13
  from .ec_value import *
14
14
 
15
- __version__ = "251103.4"
15
+ __version__ = "251105.1"
easycoder/ec_border.py CHANGED
@@ -9,34 +9,38 @@ class Border(QWidget):
9
9
 
10
10
  def __init__(self):
11
11
  super().__init__()
12
- self.size = 40
13
- self.setFixedHeight(self.size)
12
+ self._size = 40
13
+ self.setFixedHeight(self._size)
14
14
  self._drag_active = False
15
15
  self._drag_start_pos = None
16
+ self._tick: QPixmap = QPixmap()
17
+ self._close_icon: QPixmap = QPixmap()
16
18
 
17
19
  def paintEvent(self, event):
18
20
  painter = QPainter(self)
19
- painter.setRenderHint(QPainter.Antialiasing)
21
+ painter.setRenderHint(QPainter.RenderHint.Antialiasing)
20
22
  # Draw the tick icon
21
- self.tick = QPixmap(f'{os.path.dirname(os.path.abspath(__file__))}/tick.png').scaled(self.size, self.size, Qt.KeepAspectRatio, Qt.SmoothTransformation)
23
+ self._tick = QPixmap(f'{os.path.dirname(os.path.abspath(__file__))}/icons/tick.png').scaled(
24
+ self._size, self._size, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation)
22
25
  x = 0
23
26
  y = 0
24
- painter.drawPixmap(x, y, self.tick)
27
+ painter.drawPixmap(x, y, self._tick)
25
28
  # Draw the close icon
26
- self.close = QPixmap(f'{os.path.dirname(os.path.abspath(__file__))}/close.png').scaled(self.size, self.size, Qt.KeepAspectRatio, Qt.SmoothTransformation)
27
- x = self.width() - self.close.width()
29
+ self._close_icon = QPixmap(f'{os.path.dirname(os.path.abspath(__file__))}/icons/close.png').scaled(
30
+ self._size, self._size, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation)
31
+ x = self.width() - self._close_icon.width()
28
32
  y = 0
29
- painter.drawPixmap(x, y, self.close)
33
+ painter.drawPixmap(x, y, self._close_icon)
30
34
 
31
35
  def mousePressEvent(self, event):
32
36
  # Tick icon
33
37
  x = 0
34
38
  y = 0
35
- tickRect = self.tick.rect().translated(x, y)
39
+ tickRect = self._tick.rect().translated(x, y)
36
40
  # Close icon
37
- x = self.width() - self.close.width()
41
+ x = self.width() - self._close_icon.width()
38
42
  y = 0
39
- closeRect = self.close.rect().translated(x, y)
43
+ closeRect = self._close_icon.rect().translated(x, y)
40
44
  if tickRect.contains(event.pos()):
41
45
  self.tickClicked.emit()
42
46
  if closeRect.contains(event.pos()):
easycoder/ec_classes.py CHANGED
@@ -1,6 +1,6 @@
1
1
  import sys
2
2
 
3
- class FatalError:
3
+ class FatalError(BaseException):
4
4
  def __init__(self, compiler, message):
5
5
  compiler.showWarnings()
6
6
  lino = compiler.tokens[compiler.index].lino
@@ -58,4 +58,9 @@ class Token:
58
58
  self.token = token
59
59
 
60
60
  class Object():
61
- pass
61
+ """Dynamic object that allows arbitrary attribute assignment"""
62
+ def __setattr__(self, name: str, value) -> None:
63
+ self.__dict__[name] = value
64
+
65
+ def __getattr__(self, name: str):
66
+ return self.__dict__.get(name)
easycoder/ec_compiler.py CHANGED
@@ -18,9 +18,11 @@ class Compiler:
18
18
  self.debugCompile = False
19
19
  self.valueTypes = {}
20
20
 
21
- def getPC(self):
21
+ # Get the current code size. Used during compilation
22
+ def getCodeSize(self):
22
23
  return len(self.program.code)
23
24
 
25
+ # Get the current index (the program counter)
24
26
  def getIndex(self):
25
27
  return self.index
26
28
 
@@ -39,6 +41,7 @@ class Compiler:
39
41
  self.index += 1
40
42
  return self.getToken()
41
43
 
44
+ # Peek ahead to see the next token without advancing the index
42
45
  def peek(self):
43
46
  try:
44
47
  return self.tokens[self.index + 1].token
@@ -68,19 +71,24 @@ class Compiler:
68
71
  self.index += 1
69
72
  return self.condition.compileCondition()
70
73
 
74
+ # Test if the current token has a specified value
71
75
  def tokenIs(self, value):
72
76
  return self.getToken() == value
73
77
 
78
+ # Test if the next token has the specified value
74
79
  def nextIs(self, value):
75
80
  return self.nextToken() == value
76
81
 
82
+ # Get the command at a given pc in the code list
77
83
  def getCommandAt(self, pc):
78
84
  return self.program.code[pc]
79
85
 
80
86
  # Add a command to the code list
81
87
  def addCommand(self, command):
88
+ command['bp'] = False
82
89
  self.code.append(command)
83
90
 
91
+ # Test if the current token is a symbol
84
92
  def isSymbol(self):
85
93
  token = self.getToken()
86
94
  try:
@@ -89,10 +97,12 @@ class Compiler:
89
97
  return False
90
98
  return True
91
99
 
100
+ # Test if the next token is a symbol
92
101
  def nextIsSymbol(self):
93
102
  self.next()
94
103
  return self.isSymbol()
95
104
 
105
+ # Skip the next token if it matches the value given
96
106
  def skip(self, token):
97
107
  next = self.peek()
98
108
  if type(token) == list:
@@ -102,21 +112,26 @@ class Compiler:
102
112
  return
103
113
  elif next == token: self.nextToken()
104
114
 
115
+ # Rewind to a given position in the code list
105
116
  def rewindTo(self, index):
106
117
  self.index = index
107
118
 
119
+ # Get source line number containing the current token
108
120
  def getLino(self):
109
121
  if self.index >= len(self.tokens):
110
122
  return 0
111
123
  return self.tokens[self.index].lino
112
124
 
125
+ # Issue a warning
113
126
  def warning(self, message):
114
127
  self.warnings.append(f'Warning at line {self.getLino() + 1} of {self.program.name}: {message}')
115
128
 
129
+ # Print all warnings
116
130
  def showWarnings(self):
117
131
  for warning in self.warnings:
118
132
  print(warning)
119
133
 
134
+ # Get the symbol record for the current token (assumes it is a symbol name)
120
135
  def getSymbolRecord(self):
121
136
  token = self.getToken()
122
137
  if not token in self.symbols:
@@ -128,18 +143,23 @@ class Compiler:
128
143
  symbolRecord['used'] = True
129
144
  return symbolRecord
130
145
 
146
+ # Add a value type
131
147
  def addValueType(self):
132
148
  self.valueTypes[self.getToken()] = True
133
149
 
150
+ # Test if a given value is in the value types list
134
151
  def hasValue(self, type):
135
152
  return type in self.valueTypes
136
153
 
154
+ # Compile a program label (a symbol ending with ':')
137
155
  def compileLabel(self, command):
138
156
  return self.compileSymbol(command, self.getToken())
139
157
 
158
+ # Compile a variable
140
159
  def compileVariable(self, command, extra=None):
141
160
  return self.compileSymbol(command, self.nextToken(), extra)
142
161
 
162
+ # Compile a symbol
143
163
  def compileSymbol(self, command, name, extra=None):
144
164
  try:
145
165
  v = self.symbols[name]
@@ -148,7 +168,7 @@ class Compiler:
148
168
  if v:
149
169
  FatalError(self, f'Duplicate symbol name "{name}"')
150
170
  return False
151
- self.symbols[name] = self.getPC()
171
+ self.symbols[name] = self.getCodeSize()
152
172
  command['program'] = self.program
153
173
  command['type'] = 'symbol'
154
174
  command['name'] = name
@@ -172,7 +192,7 @@ class Compiler:
172
192
  if not token:
173
193
  return False
174
194
  if len(self.code) == 0:
175
- if self.program.parent == None and hasattr(self.program, 'usingGraphics'):
195
+ if self.program.parent == None and self.program.usingGraphics:
176
196
  cmd = {'domain': 'graphics', 'keyword': 'init', 'debug': False}
177
197
  self.code.append(cmd)
178
198
  mark = self.getIndex()
@@ -199,7 +219,7 @@ class Compiler:
199
219
  keyword = self.getToken()
200
220
  if not keyword:
201
221
  return False
202
- print(f'Compile keyword "{keyword}"')
222
+ # print(f'Compile keyword "{keyword}"')
203
223
  if keyword.endswith(':'):
204
224
  command = {}
205
225
  command['domain'] = None
@@ -225,8 +245,10 @@ class Compiler:
225
245
  else:
226
246
  return False
227
247
 
248
+ # Compile fom the current location, stopping on any of a list of tokens
228
249
  def compileFromHere(self, stopOn):
229
250
  return self.compileFrom(self.getIndex(), stopOn)
230
251
 
252
+ # Compile from the start of the script
231
253
  def compileFromStart(self):
232
254
  return self.compileFrom(0, [])
easycoder/ec_core.py CHANGED
@@ -31,13 +31,13 @@ class Core(Handler):
31
31
  cmd['keyword'] = 'gotoPC'
32
32
  cmd['goto'] = 0
33
33
  cmd['debug'] = False
34
- skip = self.getPC()
34
+ skip = self.getCodeSize()
35
35
  self.add(cmd)
36
36
  # Process the 'or'
37
- self.getCommandAt(orHere)['or'] = self.getPC()
37
+ self.getCommandAt(orHere)['or'] = self.getCodeSize()
38
38
  self.compileOne()
39
39
  # Fixup the skip
40
- self.getCommandAt(skip)['goto'] = self.getPC()
40
+ self.getCommandAt(skip)['goto'] = self.getCodeSize()
41
41
 
42
42
  #############################################################################
43
43
  # Keyword handlers
@@ -468,7 +468,7 @@ class Core(Handler):
468
468
  if url != None:
469
469
  command['url'] = url
470
470
  command['or'] = None
471
- get = self.getPC()
471
+ get = self.getCodeSize()
472
472
  if self.peek() == 'timeout':
473
473
  self.nextToken()
474
474
  command['timeout'] = self.nextValue()
@@ -556,7 +556,7 @@ class Core(Handler):
556
556
  command['condition'] = self.nextCondition()
557
557
  self.add(command)
558
558
  self.nextToken()
559
- pcElse = self.getPC()
559
+ pcElse = self.getCodeSize()
560
560
  cmd = {}
561
561
  cmd['lino'] = command['lino']
562
562
  cmd['domain'] = 'core'
@@ -569,7 +569,7 @@ class Core(Handler):
569
569
  if self.peek() == 'else':
570
570
  self.nextToken()
571
571
  # Add a 'goto' to skip the 'else'
572
- pcNext = self.getPC()
572
+ pcNext = self.getCodeSize()
573
573
  cmd = {}
574
574
  cmd['lino'] = command['lino']
575
575
  cmd['domain'] = 'core'
@@ -578,15 +578,15 @@ class Core(Handler):
578
578
  cmd['debug'] = False
579
579
  self.add(cmd)
580
580
  # Fixup the link to the 'else' branch
581
- self.getCommandAt(pcElse)['goto'] = self.getPC()
581
+ self.getCommandAt(pcElse)['goto'] = self.getCodeSize()
582
582
  # Process the 'else' branch
583
583
  self.nextToken()
584
584
  self.compileOne()
585
585
  # Fixup the pcNext 'goto'
586
- self.getCommandAt(pcNext)['goto'] = self.getPC()
586
+ self.getCommandAt(pcNext)['goto'] = self.getCodeSize()
587
587
  else:
588
588
  # We're already at the next command
589
- self.getCommandAt(pcElse)['goto'] = self.getPC()
589
+ self.getCommandAt(pcElse)['goto'] = self.getCodeSize()
590
590
  return True
591
591
 
592
592
  def r_if(self, command):
@@ -605,7 +605,7 @@ class Core(Handler):
605
605
  name = self.nextToken()
606
606
  item = [keyword, name]
607
607
  imports.append(item)
608
- self.symbols[name] = self.getPC()
608
+ self.symbols[name] = self.getCodeSize()
609
609
  variable = {}
610
610
  variable['domain'] = None
611
611
  variable['name'] = name
@@ -747,7 +747,7 @@ class Core(Handler):
747
747
  else:
748
748
  command['file'] = self.getValue()
749
749
  command['or'] = None
750
- load = self.getPC()
750
+ load = self.getCodeSize()
751
751
  self.processOr(command, load)
752
752
  return True
753
753
  else:
@@ -916,7 +916,7 @@ class Core(Handler):
916
916
  cmd['debug'] = False
917
917
  self.add(cmd)
918
918
  # Fixup the link
919
- command['goto'] = self.getPC()
919
+ command['goto'] = self.getCodeSize()
920
920
  return True
921
921
  return False
922
922
 
@@ -1007,7 +1007,7 @@ class Core(Handler):
1007
1007
  else:
1008
1008
  command['result'] = None
1009
1009
  command['or'] = None
1010
- post = self.getPC()
1010
+ post = self.getCodeSize()
1011
1011
  self.processOr(command, post)
1012
1012
  return True
1013
1013
 
@@ -1106,7 +1106,7 @@ class Core(Handler):
1106
1106
  FatalError(self.compiler, f'Symbol {symbolRecord["name"]} is not a value holder')
1107
1107
  else:
1108
1108
  command['or'] = None
1109
- self.processOr(command, self.getPC())
1109
+ self.processOr(command, self.getCodeSize())
1110
1110
  return True
1111
1111
  else:
1112
1112
  FatalError(self.compiler, f'Symbol {self.getToken()} is not a variable')
@@ -1274,7 +1274,7 @@ class Core(Handler):
1274
1274
  else:
1275
1275
  command['file'] = self.getValue()
1276
1276
  command['or'] = None
1277
- save = self.getPC()
1277
+ save = self.getCodeSize()
1278
1278
  self.processOr(command, save)
1279
1279
  return True
1280
1280
 
@@ -1771,15 +1771,8 @@ class Core(Handler):
1771
1771
  return False
1772
1772
  else:
1773
1773
  token = self.nextToken()
1774
- if token in ['graphics', 'debugger']:
1775
- if not hasattr(self.program, 'usingGraphics'):
1776
- print('Loading graphics module')
1777
- from .ec_pyside import Graphics
1778
- self.program.graphics = Graphics
1779
- self.program.useClass(Graphics)
1780
- self.program.usingGraphics = True
1781
- if token == 'debugger': self.program.debugging = True
1782
- return True
1774
+ if token == 'graphics':
1775
+ return self.program.useGraphics()
1783
1776
  return False
1784
1777
 
1785
1778
  # Declare a general-purpose variable
@@ -1823,10 +1816,10 @@ class Core(Handler):
1823
1816
  return None
1824
1817
  # token = self.getToken()
1825
1818
  command['condition'] = code
1826
- test = self.getPC()
1819
+ test = self.getCodeSize()
1827
1820
  self.add(command)
1828
1821
  # Set up a goto for when the test fails
1829
- fail = self.getPC()
1822
+ fail = self.getCodeSize()
1830
1823
  cmd = {}
1831
1824
  cmd['lino'] = command['lino']
1832
1825
  cmd['domain'] = 'core'
@@ -1847,7 +1840,7 @@ class Core(Handler):
1847
1840
  cmd['debug'] = False
1848
1841
  self.add(cmd)
1849
1842
  # Fixup the 'goto' on completion
1850
- self.getCommandAt(fail)['goto'] = self.getPC()
1843
+ self.getCommandAt(fail)['goto'] = self.getCodeSize()
1851
1844
  return True
1852
1845
 
1853
1846
  def r_while(self, command):