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 +1 -1
- easycoder/ec_border.py +15 -11
- easycoder/ec_classes.py +7 -2
- easycoder/ec_compiler.py +26 -4
- easycoder/ec_core.py +20 -27
- easycoder/ec_debug.py +781 -0
- easycoder/ec_handler.py +2 -1
- easycoder/ec_keyboard.py +50 -50
- easycoder/ec_program.py +44 -10
- easycoder/ec_pyside.py +88 -101
- easycoder/ec_timestamp.py +2 -1
- easycoder/icons/exit.png +0 -0
- easycoder/icons/run.png +0 -0
- easycoder/icons/step.png +0 -0
- easycoder/icons/stop.png +0 -0
- {easycoder-251103.4.dist-info → easycoder-251105.1.dist-info}/METADATA +1 -1
- easycoder-251105.1.dist-info/RECORD +24 -0
- easycoder-251103.4.dist-info/RECORD +0 -19
- /easycoder/{close.png → icons/close.png} +0 -0
- /easycoder/{tick.png → icons/tick.png} +0 -0
- {easycoder-251103.4.dist-info → easycoder-251105.1.dist-info}/WHEEL +0 -0
- {easycoder-251103.4.dist-info → easycoder-251105.1.dist-info}/entry_points.txt +0 -0
- {easycoder-251103.4.dist-info → easycoder-251105.1.dist-info}/licenses/LICENSE +0 -0
easycoder/__init__.py
CHANGED
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.
|
|
13
|
-
self.setFixedHeight(self.
|
|
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.
|
|
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.
|
|
27
|
+
painter.drawPixmap(x, y, self._tick)
|
|
25
28
|
# Draw the close icon
|
|
26
|
-
self.
|
|
27
|
-
|
|
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.
|
|
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.
|
|
39
|
+
tickRect = self._tick.rect().translated(x, y)
|
|
36
40
|
# Close icon
|
|
37
|
-
x = self.width() - self.
|
|
41
|
+
x = self.width() - self._close_icon.width()
|
|
38
42
|
y = 0
|
|
39
|
-
closeRect = self.
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
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.
|
|
34
|
+
skip = self.getCodeSize()
|
|
35
35
|
self.add(cmd)
|
|
36
36
|
# Process the 'or'
|
|
37
|
-
self.getCommandAt(orHere)['or'] = self.
|
|
37
|
+
self.getCommandAt(orHere)['or'] = self.getCodeSize()
|
|
38
38
|
self.compileOne()
|
|
39
39
|
# Fixup the skip
|
|
40
|
-
self.getCommandAt(skip)['goto'] = self.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
1775
|
-
|
|
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.
|
|
1819
|
+
test = self.getCodeSize()
|
|
1827
1820
|
self.add(command)
|
|
1828
1821
|
# Set up a goto for when the test fails
|
|
1829
|
-
fail = self.
|
|
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.
|
|
1843
|
+
self.getCommandAt(fail)['goto'] = self.getCodeSize()
|
|
1851
1844
|
return True
|
|
1852
1845
|
|
|
1853
1846
|
def r_while(self, command):
|