easycoder 241211.3__py2.py3-none-any.whl → 250116.3__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/README.md +6 -0
- easycoder/__init__.py +1 -1
- easycoder/ec_classes.py +3 -0
- easycoder/ec_compiler.py +11 -7
- easycoder/ec_core.py +493 -208
- easycoder/ec_graphics.py +274 -0
- easycoder/ec_gutils.py +52 -0
- easycoder/ec_handler.py +1 -0
- easycoder/ec_program.py +156 -79
- easycoder/ec_value.py +21 -14
- easycoder-250116.3.dist-info/METADATA +116 -0
- easycoder-250116.3.dist-info/RECORD +17 -0
- {easycoder-241211.3.dist-info → easycoder-250116.3.dist-info}/WHEEL +1 -1
- easycoder-241211.3.dist-info/METADATA +0 -72
- easycoder-241211.3.dist-info/RECORD +0 -14
- {easycoder-241211.3.dist-info → easycoder-250116.3.dist-info}/LICENSE +0 -0
- {easycoder-241211.3.dist-info → easycoder-250116.3.dist-info}/entry_points.txt +0 -0
easycoder/ec_graphics.py
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
from .ec_classes import FatalError, RuntimeError, Object
|
|
2
|
+
from .ec_handler import Handler
|
|
3
|
+
from .ec_gutils import GUtils
|
|
4
|
+
import PySimpleGUI as psg
|
|
5
|
+
import json
|
|
6
|
+
|
|
7
|
+
class Graphics(Handler):
|
|
8
|
+
|
|
9
|
+
def __init__(self, compiler):
|
|
10
|
+
Handler.__init__(self, compiler)
|
|
11
|
+
self.utils = GUtils()
|
|
12
|
+
self.eventHandlers = {}
|
|
13
|
+
|
|
14
|
+
def getName(self):
|
|
15
|
+
return 'graphics'
|
|
16
|
+
|
|
17
|
+
#############################################################################
|
|
18
|
+
# Keyword handlers
|
|
19
|
+
|
|
20
|
+
def k_add(self, command):
|
|
21
|
+
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
|
+
elif token[0:2] == 'g_':
|
|
31
|
+
command['type'] = token
|
|
32
|
+
command['args'] = self.utils.getArgs(self)
|
|
33
|
+
else: return False
|
|
34
|
+
if self.nextIs('to'):
|
|
35
|
+
if self.nextIsSymbol():
|
|
36
|
+
symbolRecord = self.getSymbolRecord()
|
|
37
|
+
if symbolRecord['keyword'] == 'layout':
|
|
38
|
+
command['target'] = symbolRecord['name']
|
|
39
|
+
self.addCommand(command)
|
|
40
|
+
return True
|
|
41
|
+
return False
|
|
42
|
+
|
|
43
|
+
def r_add(self, command):
|
|
44
|
+
target = self.getVariable(command['target'])
|
|
45
|
+
type = command['type']
|
|
46
|
+
args = command['args']
|
|
47
|
+
if not 'layout' in target:
|
|
48
|
+
target['layout'] = []
|
|
49
|
+
if args[0] == '{':
|
|
50
|
+
layout = json.loads(self.getRuntimeValue(json.loads(args)))
|
|
51
|
+
default = self.utils.getDefaultArgs(type)
|
|
52
|
+
for n in range(0, len(layout)):
|
|
53
|
+
args = self.utils.decode(default, layout[n])
|
|
54
|
+
target['layout'].append(self.utils.createElement(type, args))
|
|
55
|
+
else:
|
|
56
|
+
v = self.getVariable(args)
|
|
57
|
+
target['layout'].append(v['layout'])
|
|
58
|
+
return self.nextPC()
|
|
59
|
+
|
|
60
|
+
def k_capture(self, command):
|
|
61
|
+
if self.nextIs('event'):
|
|
62
|
+
if self.nextIs('as'):
|
|
63
|
+
if self.nextIsSymbol():
|
|
64
|
+
record = self.getSymbolRecord()
|
|
65
|
+
command['target'] = record['name']
|
|
66
|
+
self.addCommand(command)
|
|
67
|
+
return True
|
|
68
|
+
return False
|
|
69
|
+
|
|
70
|
+
def r_capture(self, command):
|
|
71
|
+
target = self.getVariable(command['target'])
|
|
72
|
+
self.putSymbolValue(target, self.getConstant(self.eventValues))
|
|
73
|
+
return self.nextPC()
|
|
74
|
+
|
|
75
|
+
def k_close(self, command):
|
|
76
|
+
if self.nextIsSymbol():
|
|
77
|
+
symbolRecord = self.getSymbolRecord()
|
|
78
|
+
if symbolRecord['keyword'] == 'window':
|
|
79
|
+
command['target'] = symbolRecord['name']
|
|
80
|
+
self.add(command)
|
|
81
|
+
return True
|
|
82
|
+
return False
|
|
83
|
+
|
|
84
|
+
def r_close(self, command):
|
|
85
|
+
target = self.getVariable(command['target'])
|
|
86
|
+
target['window'].close()
|
|
87
|
+
return self.nextPC()
|
|
88
|
+
|
|
89
|
+
# create {window} layout {layout}
|
|
90
|
+
# create {element} {args...}
|
|
91
|
+
def k_create(self, command):
|
|
92
|
+
if self.nextIsSymbol():
|
|
93
|
+
symbolRecord = self.getSymbolRecord()
|
|
94
|
+
type = symbolRecord['keyword']
|
|
95
|
+
command['type'] = type
|
|
96
|
+
command['name'] = symbolRecord['name']
|
|
97
|
+
if type == 'window':
|
|
98
|
+
command['title'] = self.nextValue()
|
|
99
|
+
if self.nextIs('layout'):
|
|
100
|
+
if self.nextIsSymbol():
|
|
101
|
+
symbolRecord = self.getSymbolRecord()
|
|
102
|
+
if symbolRecord['keyword'] == 'layout':
|
|
103
|
+
command['layout'] = symbolRecord['name']
|
|
104
|
+
self.addCommand(command)
|
|
105
|
+
return True
|
|
106
|
+
return False
|
|
107
|
+
|
|
108
|
+
def r_create(self, command):
|
|
109
|
+
type = command['type']
|
|
110
|
+
record = self.getVariable(command['name'])
|
|
111
|
+
if type == 'window':
|
|
112
|
+
layout = self.getVariable(command['layout'])
|
|
113
|
+
title = self.getRuntimeValue(command['title'])
|
|
114
|
+
self.program.window = psg.Window(title, layout['layout'], finalize=True)
|
|
115
|
+
self.program.run(self.nextPC())
|
|
116
|
+
self.mainLoop()
|
|
117
|
+
self.program.kill()
|
|
118
|
+
return 0
|
|
119
|
+
else:
|
|
120
|
+
RuntimeError(self.program, 'Variable is not a window or an element')
|
|
121
|
+
|
|
122
|
+
def k_layout(self, command):
|
|
123
|
+
return self.compileVariable(command)
|
|
124
|
+
|
|
125
|
+
def r_layout(self, command):
|
|
126
|
+
return self.nextPC()
|
|
127
|
+
|
|
128
|
+
def k_on(self, command):
|
|
129
|
+
token = self.nextToken()
|
|
130
|
+
if token == 'event':
|
|
131
|
+
command['key'] = self.nextValue()
|
|
132
|
+
command['goto'] = self.getPC() + 2
|
|
133
|
+
self.add(command)
|
|
134
|
+
self.nextToken()
|
|
135
|
+
pcNext = self.getPC()
|
|
136
|
+
cmd = {}
|
|
137
|
+
cmd['domain'] = 'core'
|
|
138
|
+
cmd['lino'] = command['lino']
|
|
139
|
+
cmd['keyword'] = 'gotoPC'
|
|
140
|
+
cmd['goto'] = 0
|
|
141
|
+
cmd['debug'] = False
|
|
142
|
+
self.addCommand(cmd)
|
|
143
|
+
self.compileOne()
|
|
144
|
+
cmd = {}
|
|
145
|
+
cmd['domain'] = 'core'
|
|
146
|
+
cmd['lino'] = command['lino']
|
|
147
|
+
cmd['keyword'] = 'stop'
|
|
148
|
+
cmd['debug'] = False
|
|
149
|
+
self.addCommand(cmd)
|
|
150
|
+
# Fixup the link
|
|
151
|
+
self.getCommandAt(pcNext)['goto'] = self.getPC()
|
|
152
|
+
return True
|
|
153
|
+
return False
|
|
154
|
+
|
|
155
|
+
def r_on(self, command):
|
|
156
|
+
key = self.getRuntimeValue(command['key'])
|
|
157
|
+
pc = command['goto']
|
|
158
|
+
self.eventHandlers[key] = lambda: self.run(pc)
|
|
159
|
+
return self.nextPC()
|
|
160
|
+
|
|
161
|
+
def k_popup(self, command):
|
|
162
|
+
command['message'] = self.nextValue()
|
|
163
|
+
self.addCommand(command)
|
|
164
|
+
return True
|
|
165
|
+
|
|
166
|
+
def r_popup(self, command):
|
|
167
|
+
psg.popup(self.getRuntimeValue(command['message']))
|
|
168
|
+
return self.nextPC()
|
|
169
|
+
|
|
170
|
+
def k_set(self, command):
|
|
171
|
+
if self.nextIsSymbol():
|
|
172
|
+
record = self.getSymbolRecord()
|
|
173
|
+
keyword = record['keyword']
|
|
174
|
+
if keyword == 'layout':
|
|
175
|
+
command['target'] = record['name']
|
|
176
|
+
if self.peek() == 'to':
|
|
177
|
+
self.nextToken()
|
|
178
|
+
command['type'] = self.nextToken()
|
|
179
|
+
command['args'] = self.utils.getArgs(self)
|
|
180
|
+
else: command['args'] = None
|
|
181
|
+
self.addCommand(command)
|
|
182
|
+
return True
|
|
183
|
+
elif keyword == 'event':
|
|
184
|
+
pass
|
|
185
|
+
return False
|
|
186
|
+
|
|
187
|
+
def r_set(self, command):
|
|
188
|
+
target = self.getVariable(command['target'])
|
|
189
|
+
target['layout'] = []
|
|
190
|
+
type = command['type']
|
|
191
|
+
args = command['args']
|
|
192
|
+
if args != None:
|
|
193
|
+
if args[0] == '{':
|
|
194
|
+
layout = json.loads(self.getRuntimeValue(json.loads(args)))
|
|
195
|
+
default = self.utils.getDefaultArgs(type)
|
|
196
|
+
for n in range(0, len(layout)):
|
|
197
|
+
args = self.utils.decode(default, layout[n])
|
|
198
|
+
target['layout'].append(self.utils.createElement(type, args))
|
|
199
|
+
else:
|
|
200
|
+
v = self.getVariable(args)
|
|
201
|
+
target['layout'].append(v['layout'])
|
|
202
|
+
return self.nextPC()
|
|
203
|
+
|
|
204
|
+
def k_window(self, command):
|
|
205
|
+
return self.compileVariable(command)
|
|
206
|
+
|
|
207
|
+
def r_window(self, command):
|
|
208
|
+
return self.nextPC()
|
|
209
|
+
|
|
210
|
+
#############################################################################
|
|
211
|
+
# Compile a value in this domain
|
|
212
|
+
def compileValue(self):
|
|
213
|
+
value = {}
|
|
214
|
+
value['domain'] = self.getName()
|
|
215
|
+
token = self.getToken()
|
|
216
|
+
if self.isSymbol():
|
|
217
|
+
value['name'] = token
|
|
218
|
+
symbolRecord = self.getSymbolRecord()
|
|
219
|
+
keyword = symbolRecord['keyword']
|
|
220
|
+
if keyword == 'event':
|
|
221
|
+
value['type'] = 'symbol'
|
|
222
|
+
return value
|
|
223
|
+
return None
|
|
224
|
+
|
|
225
|
+
value['type'] = token
|
|
226
|
+
|
|
227
|
+
if token == 'test':
|
|
228
|
+
value = {}
|
|
229
|
+
value['type'] = 'text'
|
|
230
|
+
value['content'] = 'test'
|
|
231
|
+
return value
|
|
232
|
+
|
|
233
|
+
return None
|
|
234
|
+
|
|
235
|
+
#############################################################################
|
|
236
|
+
# Modify a value or leave it unchanged.
|
|
237
|
+
def modifyValue(self, value):
|
|
238
|
+
return value
|
|
239
|
+
|
|
240
|
+
#############################################################################
|
|
241
|
+
# Value handlers
|
|
242
|
+
|
|
243
|
+
# This is used by the expression evaluator to get the value of a symbol
|
|
244
|
+
def v_symbol(self, symbolRecord):
|
|
245
|
+
if symbolRecord['keyword'] == 'event':
|
|
246
|
+
return self.getSymbolValue(symbolRecord)
|
|
247
|
+
else:
|
|
248
|
+
return None
|
|
249
|
+
|
|
250
|
+
def v_test(self, v):
|
|
251
|
+
return v
|
|
252
|
+
|
|
253
|
+
#############################################################################
|
|
254
|
+
# Compile a condition
|
|
255
|
+
def compileCondition(self):
|
|
256
|
+
condition = {}
|
|
257
|
+
return condition
|
|
258
|
+
|
|
259
|
+
#############################################################################
|
|
260
|
+
# Condition handlers
|
|
261
|
+
|
|
262
|
+
#############################################################################
|
|
263
|
+
# The main loop
|
|
264
|
+
def mainLoop(self):
|
|
265
|
+
while True:
|
|
266
|
+
event, values = self.program.window.Read(timeout=100)
|
|
267
|
+
if event == psg.WINDOW_CLOSED or event == "EXIT":
|
|
268
|
+
break
|
|
269
|
+
if event == '__TIMEOUT__': self.program.flushCB()
|
|
270
|
+
else:
|
|
271
|
+
if event in self.eventHandlers:
|
|
272
|
+
self.eventValues = values
|
|
273
|
+
self.eventHandlers[event]()
|
|
274
|
+
|
easycoder/ec_gutils.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import PySimpleGUI as psg
|
|
2
|
+
import json
|
|
3
|
+
|
|
4
|
+
class GUtils:
|
|
5
|
+
|
|
6
|
+
# Parse a set of compile-time arguments
|
|
7
|
+
def getArgs(self, handler):
|
|
8
|
+
args = []
|
|
9
|
+
while True:
|
|
10
|
+
key = handler.nextToken()
|
|
11
|
+
value = json.dumps(handler.nextValue())
|
|
12
|
+
args.append(f'{key}={value}')
|
|
13
|
+
if handler.peek() == 'and':
|
|
14
|
+
handler.nextToken()
|
|
15
|
+
else: break
|
|
16
|
+
v = {}
|
|
17
|
+
v['type'] = 'text'
|
|
18
|
+
v['content'] = json.dumps(args)
|
|
19
|
+
return json.dumps(v)
|
|
20
|
+
|
|
21
|
+
# Get the default args for a graphic element
|
|
22
|
+
def getDefaultArgs(self, type):
|
|
23
|
+
args = {}
|
|
24
|
+
if type == 'g_text':
|
|
25
|
+
args['text'] = '(empty)'
|
|
26
|
+
args['expand_x'] = False
|
|
27
|
+
elif type == 'g_input':
|
|
28
|
+
args['key'] = None
|
|
29
|
+
args['size'] = (None, None)
|
|
30
|
+
elif type == 'g_button':
|
|
31
|
+
args['button_text'] = '(empty)'
|
|
32
|
+
return args
|
|
33
|
+
|
|
34
|
+
# Decode an argument at runtime
|
|
35
|
+
def decode(self, args, text):
|
|
36
|
+
p = text.find('=')
|
|
37
|
+
if p > 0:
|
|
38
|
+
key = text[0:p]
|
|
39
|
+
value = json.loads(text[p+1:])['content']
|
|
40
|
+
args[key] = value
|
|
41
|
+
return args
|
|
42
|
+
return None
|
|
43
|
+
|
|
44
|
+
# Create an element
|
|
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':
|
|
48
|
+
size = args['size'].split()
|
|
49
|
+
size = (size[0], size[1])
|
|
50
|
+
return psg.Input(key=args['key'], size=size)
|
|
51
|
+
elif type == 'g_button': return psg.Button(button_text=args['button_text'])
|
|
52
|
+
else: return None
|
easycoder/ec_handler.py
CHANGED
|
@@ -25,6 +25,7 @@ class Handler:
|
|
|
25
25
|
self.getCommandAt = compiler.getCommandAt
|
|
26
26
|
self.compileOne = compiler.compileOne
|
|
27
27
|
self.compileFromHere = compiler.compileFromHere
|
|
28
|
+
self.compileConstant = compiler.compileConstant
|
|
28
29
|
|
|
29
30
|
self.code = self.program.code
|
|
30
31
|
self.add = self.program.add
|
easycoder/ec_program.py
CHANGED
|
@@ -1,29 +1,38 @@
|
|
|
1
1
|
import time, json, sys
|
|
2
2
|
from copy import deepcopy
|
|
3
3
|
from collections import deque
|
|
4
|
-
from .ec_classes import Script, Token, FatalError, RuntimeError
|
|
4
|
+
from .ec_classes import Script, Token, FatalError, RuntimeError, Object
|
|
5
5
|
from .ec_compiler import Compiler
|
|
6
6
|
from .ec_core import Core
|
|
7
7
|
import importlib
|
|
8
8
|
from importlib.metadata import version
|
|
9
9
|
|
|
10
|
+
# Flush the queue
|
|
11
|
+
def flush():
|
|
12
|
+
global queue
|
|
13
|
+
while len(queue):
|
|
14
|
+
item = queue.popleft()
|
|
15
|
+
item.program.flush(item.pc)
|
|
16
|
+
|
|
10
17
|
class Program:
|
|
11
18
|
|
|
12
19
|
def __init__(self, argv):
|
|
20
|
+
global queue
|
|
13
21
|
print(f'EasyCoder version {version("easycoder")}')
|
|
14
|
-
|
|
15
|
-
if len(argv)>0:
|
|
16
|
-
scriptName = argv[0]
|
|
17
|
-
else:
|
|
22
|
+
if len(argv) == 0:
|
|
18
23
|
print('No script supplied')
|
|
19
|
-
exit()
|
|
24
|
+
exit()
|
|
25
|
+
self.classes=[Core]
|
|
26
|
+
scriptName = argv
|
|
27
|
+
if scriptName.endswith('.ecg'):
|
|
28
|
+
from .ec_graphics import Graphics
|
|
29
|
+
self.classes.append(Graphics)
|
|
20
30
|
|
|
21
|
-
# print('Domains:',domains)
|
|
22
31
|
f = open(scriptName, 'r')
|
|
23
32
|
source = f.read()
|
|
24
33
|
f.close()
|
|
34
|
+
queue = deque()
|
|
25
35
|
self.argv = argv
|
|
26
|
-
self.classes=[Core]
|
|
27
36
|
self.domains = []
|
|
28
37
|
self.domainIndex = {}
|
|
29
38
|
self.name = '<anon>'
|
|
@@ -38,8 +47,14 @@ class Program:
|
|
|
38
47
|
self.value = self.compiler.value
|
|
39
48
|
self.condition = self.compiler.condition
|
|
40
49
|
self.processClasses()
|
|
41
|
-
self.
|
|
50
|
+
self.externalControl = False
|
|
51
|
+
self.running = True
|
|
42
52
|
|
|
53
|
+
def start(self, parent=None, module = None, exports=[]):
|
|
54
|
+
self.parent = parent
|
|
55
|
+
self.exports = exports
|
|
56
|
+
if module != None:
|
|
57
|
+
module['child'] = self
|
|
43
58
|
startCompile = time.time()
|
|
44
59
|
self.tokenise(self.script)
|
|
45
60
|
if self.compiler.compileFrom(0, []):
|
|
@@ -57,13 +72,24 @@ class Program:
|
|
|
57
72
|
self.run(0)
|
|
58
73
|
else:
|
|
59
74
|
self.compiler.showWarnings()
|
|
60
|
-
|
|
75
|
+
|
|
76
|
+
# If this is the main script and there's no graphics, run a main loop
|
|
77
|
+
if parent == None and self.externalControl == False:
|
|
78
|
+
while True:
|
|
79
|
+
if self.running == True:
|
|
80
|
+
flush()
|
|
81
|
+
time.sleep(0.1)
|
|
82
|
+
else:
|
|
83
|
+
break
|
|
61
84
|
|
|
62
85
|
# Import a plugin
|
|
63
86
|
def importPlugin(self, source):
|
|
64
87
|
args=source.split(':')
|
|
88
|
+
if len(args)<2:
|
|
89
|
+
RuntimeError(None, f'Invalid plugin spec "{source}"')
|
|
65
90
|
idx=args[0].rfind('/')
|
|
66
91
|
if idx<0:
|
|
92
|
+
sys.path.append('.')
|
|
67
93
|
module=args[0]
|
|
68
94
|
else:
|
|
69
95
|
sys.path.append(args[0][0:idx])
|
|
@@ -81,7 +107,7 @@ class Program:
|
|
|
81
107
|
handler = clazz(self.compiler)
|
|
82
108
|
self.domains.append(handler)
|
|
83
109
|
self.domainIndex[handler.getName()] = handler
|
|
84
|
-
|
|
110
|
+
|
|
85
111
|
# Get the domain list
|
|
86
112
|
def getDomains(self):
|
|
87
113
|
return self.domains
|
|
@@ -93,11 +119,11 @@ class Program:
|
|
|
93
119
|
def getSymbolRecord(self, name):
|
|
94
120
|
try:
|
|
95
121
|
target = self.code[self.symbols[name]]
|
|
122
|
+
if target['import'] != None:
|
|
123
|
+
target = target['import']
|
|
124
|
+
return target
|
|
96
125
|
except:
|
|
97
|
-
RuntimeError(self
|
|
98
|
-
return None
|
|
99
|
-
|
|
100
|
-
return target
|
|
126
|
+
RuntimeError(self, f'Unknown symbol \'{name}\'')
|
|
101
127
|
|
|
102
128
|
def doValue(self, value):
|
|
103
129
|
if value == None:
|
|
@@ -124,7 +150,7 @@ class Program:
|
|
|
124
150
|
name = value['name']
|
|
125
151
|
symbolRecord = self.getSymbolRecord(name)
|
|
126
152
|
if symbolRecord['value'] == [None]:
|
|
127
|
-
RuntimeWarning(self.
|
|
153
|
+
RuntimeWarning(self.program, f'Variable "{name}" has no value')
|
|
128
154
|
return None
|
|
129
155
|
handler = self.domainIndex[symbolRecord['domain']].valueHandler('symbol')
|
|
130
156
|
result = handler(symbolRecord)
|
|
@@ -179,6 +205,9 @@ class Program:
|
|
|
179
205
|
return copy
|
|
180
206
|
|
|
181
207
|
def putSymbolValue(self, symbolRecord, value):
|
|
208
|
+
if symbolRecord['locked']:
|
|
209
|
+
name = symbolRecord['name']
|
|
210
|
+
RuntimeError(self, f'Symbol "{name}" is locked')
|
|
182
211
|
if symbolRecord['value'] == None or symbolRecord['value'] == []:
|
|
183
212
|
symbolRecord['value'] = [value]
|
|
184
213
|
else:
|
|
@@ -195,80 +224,115 @@ class Program:
|
|
|
195
224
|
|
|
196
225
|
# Tokenise the script
|
|
197
226
|
def tokenise(self, script):
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
for
|
|
227
|
+
token = ''
|
|
228
|
+
literal = False
|
|
229
|
+
for lino in range(0, len(script.lines)):
|
|
230
|
+
line = script.lines[lino]
|
|
201
231
|
length = len(line)
|
|
202
|
-
|
|
203
|
-
|
|
232
|
+
if length == 0:
|
|
233
|
+
continue
|
|
234
|
+
# Look for the first non-space
|
|
204
235
|
n = 0
|
|
205
|
-
while n < length:
|
|
236
|
+
while n < length and line[n].isspace():
|
|
237
|
+
n += 1
|
|
238
|
+
# The whole line may be empty
|
|
239
|
+
if n == length:
|
|
240
|
+
if literal:
|
|
241
|
+
token += '\n'
|
|
242
|
+
continue
|
|
243
|
+
# If in an unfinished literal, the first char must be a backtick to continue adding to it
|
|
244
|
+
if literal:
|
|
245
|
+
if line[n] != '`':
|
|
246
|
+
# Close the current token
|
|
247
|
+
if len(token) > 0:
|
|
248
|
+
script.tokens.append(Token(lino, token))
|
|
249
|
+
token = ''
|
|
250
|
+
literal = False
|
|
251
|
+
n += 1
|
|
252
|
+
for n in range(n, length):
|
|
206
253
|
c = line[n]
|
|
207
|
-
if
|
|
208
|
-
|
|
209
|
-
|
|
254
|
+
# Test if we are in a literal
|
|
255
|
+
if not literal:
|
|
256
|
+
if c.isspace():
|
|
257
|
+
if len(token) > 0:
|
|
258
|
+
script.tokens.append(Token(lino, token))
|
|
259
|
+
token = ''
|
|
210
260
|
continue
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
inSpace = True
|
|
215
|
-
n += 1
|
|
216
|
-
continue
|
|
217
|
-
inSpace = False
|
|
261
|
+
elif c == '!':
|
|
262
|
+
break
|
|
263
|
+
# Test for the start or end of a literal
|
|
218
264
|
if c == '`':
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
elif c == '!':
|
|
228
|
-
break
|
|
265
|
+
if literal:
|
|
266
|
+
token += c
|
|
267
|
+
literal = False
|
|
268
|
+
else:
|
|
269
|
+
token += c
|
|
270
|
+
literal = True
|
|
271
|
+
m = n
|
|
272
|
+
continue
|
|
229
273
|
else:
|
|
230
274
|
token += c
|
|
231
|
-
n += 1
|
|
232
275
|
if len(token) > 0:
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
276
|
+
if literal:
|
|
277
|
+
token += '\n'
|
|
278
|
+
else:
|
|
279
|
+
script.tokens.append(Token(lino, token))
|
|
280
|
+
token = ''
|
|
236
281
|
return
|
|
237
282
|
|
|
283
|
+
def releaseParent(self):
|
|
284
|
+
if self.parent.waiting and self.parent.program.running:
|
|
285
|
+
self.parent.waiting = False
|
|
286
|
+
self.parent.program.run(self.parent.pc)
|
|
287
|
+
|
|
288
|
+
def flushCB(self):
|
|
289
|
+
flush()
|
|
290
|
+
|
|
291
|
+
# Flush the queue
|
|
292
|
+
def flush(self, pc):
|
|
293
|
+
global queue
|
|
294
|
+
self.pc = pc
|
|
295
|
+
while self.running:
|
|
296
|
+
command = self.code[self.pc]
|
|
297
|
+
domainName = command['domain']
|
|
298
|
+
if domainName == None:
|
|
299
|
+
self.pc += 1
|
|
300
|
+
else:
|
|
301
|
+
keyword = command['keyword']
|
|
302
|
+
if self.debugStep and command['debug']:
|
|
303
|
+
lino = command['lino'] + 1
|
|
304
|
+
line = self.script.lines[command['lino']].strip()
|
|
305
|
+
print(f'{self.name}: Line {lino}: {domainName}:{keyword}: {line}')
|
|
306
|
+
domain = self.domainIndex[domainName]
|
|
307
|
+
handler = domain.runHandler(keyword)
|
|
308
|
+
if handler:
|
|
309
|
+
command = self.code[self.pc]
|
|
310
|
+
command['program'] = self
|
|
311
|
+
self.pc = handler(command)
|
|
312
|
+
# Deal with 'exit'
|
|
313
|
+
if self.pc == -1:
|
|
314
|
+
queue = deque()
|
|
315
|
+
if self.parent != None:
|
|
316
|
+
self.releaseParent()
|
|
317
|
+
else:
|
|
318
|
+
self.running = False
|
|
319
|
+
break
|
|
320
|
+
elif self.pc == None or self.pc == 0 or self.pc >= len(self.code):
|
|
321
|
+
break
|
|
322
|
+
|
|
238
323
|
# Run the script
|
|
239
324
|
def run(self, pc):
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
self
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
if domainName == None:
|
|
252
|
-
self.pc += 1
|
|
253
|
-
else:
|
|
254
|
-
keyword = command['keyword']
|
|
255
|
-
if self.debugStep and command['debug']:
|
|
256
|
-
lino = command['lino'] + 1
|
|
257
|
-
line = self.script.lines[command['lino']].strip()
|
|
258
|
-
print(f'{self.name}: Line {lino}: {domainName}:{keyword}: {line}')
|
|
259
|
-
domain = self.domainIndex[domainName]
|
|
260
|
-
handler = domain.runHandler(keyword)
|
|
261
|
-
if handler:
|
|
262
|
-
command = self.code[self.pc]
|
|
263
|
-
command['program'] = self
|
|
264
|
-
self.pc = handler(command)
|
|
265
|
-
try:
|
|
266
|
-
if self.pc == 0 or self.pc >= len(self.code):
|
|
267
|
-
return 0
|
|
268
|
-
except:
|
|
269
|
-
return 0
|
|
270
|
-
if self.pc < 0:
|
|
271
|
-
return -1
|
|
325
|
+
global queue
|
|
326
|
+
item = Object()
|
|
327
|
+
item.program = self
|
|
328
|
+
item.pc = pc
|
|
329
|
+
queue.append(item)
|
|
330
|
+
|
|
331
|
+
def kill(self):
|
|
332
|
+
self.running = False
|
|
333
|
+
|
|
334
|
+
def setExternalControl(self):
|
|
335
|
+
self.externalControl = True
|
|
272
336
|
|
|
273
337
|
def nonNumericValueError(self):
|
|
274
338
|
FatalError(self.compiler, 'Non-numeric value')
|
|
@@ -315,9 +379,22 @@ class Program:
|
|
|
315
379
|
return -1
|
|
316
380
|
return 0
|
|
317
381
|
|
|
382
|
+
# Set up a message handler
|
|
383
|
+
def onMessage(self, pc):
|
|
384
|
+
self.onMessagePC = pc
|
|
385
|
+
|
|
386
|
+
# Handle a message from our parent program
|
|
387
|
+
def handleMessage(self, message):
|
|
388
|
+
self.message = message
|
|
389
|
+
self.run(self.onMessagePC)
|
|
390
|
+
|
|
318
391
|
# This is the program launcher
|
|
319
392
|
def Main():
|
|
320
393
|
if (len(sys.argv) > 1):
|
|
321
|
-
Program(sys.argv[1
|
|
394
|
+
Program(sys.argv[1]).start()
|
|
322
395
|
else:
|
|
323
396
|
print('Syntax: easycoder <scriptname> [plugins]')
|
|
397
|
+
|
|
398
|
+
if __name__ == '__main__':
|
|
399
|
+
Main()
|
|
400
|
+
|