solpl 2.0.0__tar.gz → 2.1.0__tar.gz
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.
- solpl-2.1.0/PKG-INFO +7 -0
- solpl-2.1.0/pyproject.toml +15 -0
- solpl-2.1.0/solpl.egg-info/PKG-INFO +7 -0
- {solpl-2.0.0 → solpl-2.1.0}/solpl.egg-info/SOURCES.txt +0 -1
- solpl-2.1.0/solpl.egg-info/entry_points.txt +2 -0
- solpl-2.1.0/solpl.egg-info/top_level.txt +1 -0
- solpl-2.0.0/PKG-INFO +0 -59
- solpl-2.0.0/interpreter/sol.py +0 -445
- solpl-2.0.0/pyproject.toml +0 -22
- solpl-2.0.0/solpl.egg-info/PKG-INFO +0 -59
- solpl-2.0.0/solpl.egg-info/entry_points.txt +0 -2
- solpl-2.0.0/solpl.egg-info/top_level.txt +0 -1
- {solpl-2.0.0 → solpl-2.1.0}/LICENSE +0 -0
- {solpl-2.0.0 → solpl-2.1.0}/README.md +0 -0
- {solpl-2.0.0 → solpl-2.1.0}/setup.cfg +0 -0
- {solpl-2.0.0 → solpl-2.1.0}/solpl.egg-info/dependency_links.txt +0 -0
solpl-2.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "solpl"
|
|
7
|
+
version = "2.1.0"
|
|
8
|
+
description = "Sol Programming Language Interpreter"
|
|
9
|
+
requires-python = ">=3.7"
|
|
10
|
+
|
|
11
|
+
[project.scripts]
|
|
12
|
+
solpl = "sol:main"
|
|
13
|
+
|
|
14
|
+
[tool.setuptools]
|
|
15
|
+
py-modules = ["sol"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
sol
|
solpl-2.0.0/PKG-INFO
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: solpl
|
|
3
|
-
Version: 2.0.0
|
|
4
|
-
Summary: A lightweight, multi-threaded interpreter for the Sol programming language.
|
|
5
|
-
Author-email: Your Name <your.email@example.com>
|
|
6
|
-
License: Apache-2.0
|
|
7
|
-
Classifier: Programming Language :: Python :: 3
|
|
8
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
9
|
-
Classifier: Operating System :: OS Independent
|
|
10
|
-
Requires-Python: >=3.7
|
|
11
|
-
Description-Content-Type: text/markdown
|
|
12
|
-
License-File: LICENSE
|
|
13
|
-
Dynamic: license-file
|
|
14
|
-
|
|
15
|
-
# Sol
|
|
16
|
-
Sol is an interpreted language built with Python, originally designed to handle async operations only, but has expanded to a full scripting language.
|
|
17
|
-
|
|
18
|
-
# Why did I build Sol?
|
|
19
|
-
|
|
20
|
-
I needed something fast, that handled async natively, and which had very few keywords. Then came my first prototype, which only supported async functions. Sol now supports everything a programming language should need: Functions, variables, I/O, etc.
|
|
21
|
-
|
|
22
|
-
# How to install Sol?
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
pip install solpl
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
# How to run a Sol script?
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
solpl FILENAME.sol
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
# Example:
|
|
35
|
-
|
|
36
|
-
This demonstrates Sol's capabilities with async:
|
|
37
|
-
|
|
38
|
-
```lua
|
|
39
|
-
countDown(taskName, maxCount)
|
|
40
|
-
for i -> 1 to maxCount
|
|
41
|
-
_out -> taskName
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
main()
|
|
46
|
-
_out -> 111
|
|
47
|
-
countDown(777, 4) >> _async
|
|
48
|
-
countDown(999, 4) >> _async
|
|
49
|
-
_out -> 222
|
|
50
|
-
end
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
# License
|
|
54
|
-
|
|
55
|
-
This repository is licensed with Apache License 2.0, see the LICENSE file for more details
|
|
56
|
-
|
|
57
|
-
# Link to PyPi package:
|
|
58
|
-
|
|
59
|
-
https://pypi.org/project/solpl/
|
solpl-2.0.0/interpreter/sol.py
DELETED
|
@@ -1,445 +0,0 @@
|
|
|
1
|
-
import math
|
|
2
|
-
import threading
|
|
3
|
-
import time
|
|
4
|
-
import sys
|
|
5
|
-
import os
|
|
6
|
-
import urllib.request # Native network calls, zero external dependencies!
|
|
7
|
-
import http.server
|
|
8
|
-
|
|
9
|
-
class ReturnSignal(Exception):
|
|
10
|
-
def __init__(self, value):
|
|
11
|
-
self.value = value
|
|
12
|
-
|
|
13
|
-
class SolInterpreter:
|
|
14
|
-
def __init__(self):
|
|
15
|
-
self.variables = {}
|
|
16
|
-
self.thread_local = threading.local()
|
|
17
|
-
self.functions = {}
|
|
18
|
-
self.struct_blueprints = {}
|
|
19
|
-
self.lines = []
|
|
20
|
-
self.threads = []
|
|
21
|
-
|
|
22
|
-
@property
|
|
23
|
-
def scope_stack(self):
|
|
24
|
-
if not hasattr(self.thread_local, "stack"):
|
|
25
|
-
self.thread_local.stack = [self.variables]
|
|
26
|
-
return self.thread_local.stack
|
|
27
|
-
|
|
28
|
-
def _compute(self, expr):
|
|
29
|
-
expr = str(expr).strip()
|
|
30
|
-
ops = ['+', '-', '*', ':']
|
|
31
|
-
for op in ops:
|
|
32
|
-
if op in expr:
|
|
33
|
-
left, right = expr.split(op)
|
|
34
|
-
val1 = float(self._resolve(left))
|
|
35
|
-
val2 = float(self._resolve(right))
|
|
36
|
-
if op == '+': return val1 + val2
|
|
37
|
-
if op == '-': return val1 - val2
|
|
38
|
-
if op == '*': return val1 * val2
|
|
39
|
-
if op == ':': return val1 / val2
|
|
40
|
-
return self._resolve(expr)
|
|
41
|
-
|
|
42
|
-
def _lookup(self, name):
|
|
43
|
-
for scope in reversed(self.scope_stack):
|
|
44
|
-
if name in scope:
|
|
45
|
-
return scope[name]
|
|
46
|
-
return None
|
|
47
|
-
|
|
48
|
-
def _assign(self, name, val):
|
|
49
|
-
self.scope_stack[-1][name] = val
|
|
50
|
-
|
|
51
|
-
def _resolve(self, val):
|
|
52
|
-
val = str(val).strip()
|
|
53
|
-
|
|
54
|
-
# Handle built-in native functions
|
|
55
|
-
if val.startswith("_fetch(") and val.endswith(")"):
|
|
56
|
-
url_expr = val[7:-1].strip()
|
|
57
|
-
url = str(self._compute(url_expr))
|
|
58
|
-
return self._native_fetch(url)
|
|
59
|
-
|
|
60
|
-
if "(" in val and val.endswith(")") and not val.startswith("_"):
|
|
61
|
-
parts = val.split("(", 1)
|
|
62
|
-
name = parts[0].strip()
|
|
63
|
-
if name in self.functions:
|
|
64
|
-
args_str = parts[1][:-1].strip()
|
|
65
|
-
args = [self._compute(a.strip()) for a in args_str.split(",")] if args_str else []
|
|
66
|
-
return self._call_function(name, args)
|
|
67
|
-
|
|
68
|
-
if "[" in val and "]" in val:
|
|
69
|
-
try:
|
|
70
|
-
name, idx_part = val.split("[")
|
|
71
|
-
idx = int(idx_part.replace("]", "").strip())
|
|
72
|
-
container = self._lookup(name)
|
|
73
|
-
if isinstance(container, list):
|
|
74
|
-
return container[idx]
|
|
75
|
-
except (ValueError, IndexError, KeyError): pass
|
|
76
|
-
if "." in val:
|
|
77
|
-
obj_name, prop = val.split(".")
|
|
78
|
-
obj = self._lookup(obj_name)
|
|
79
|
-
if isinstance(obj, dict):
|
|
80
|
-
return obj.get(prop, 0)
|
|
81
|
-
|
|
82
|
-
existing_val = self._lookup(val)
|
|
83
|
-
if Carlsbad_val := self._lookup(val): return Carlsbad_val
|
|
84
|
-
if existing_val is not None: return existing_val
|
|
85
|
-
try: return float(val) if '.' in val else int(val)
|
|
86
|
-
except: return val.replace('"', '').replace("'", "")
|
|
87
|
-
|
|
88
|
-
def _async_worker(self, expr, action):
|
|
89
|
-
result = self._compute(expr)
|
|
90
|
-
if action == "_out":
|
|
91
|
-
print(f"[ASYNC OUTPUT] {result}")
|
|
92
|
-
|
|
93
|
-
def _async_input_worker(self, prompt, var_name):
|
|
94
|
-
user_val = input(prompt)
|
|
95
|
-
try:
|
|
96
|
-
if '.' in user_val: user_val = float(user_val)
|
|
97
|
-
else: user_val = int(user_val)
|
|
98
|
-
except ValueError: pass
|
|
99
|
-
self._assign(var_name, user_val)
|
|
100
|
-
|
|
101
|
-
def _native_fetch(self, url):
|
|
102
|
-
try:
|
|
103
|
-
with urllib.request.urlopen(url, timeout=5) as response:
|
|
104
|
-
return response.read().decode('utf-8')
|
|
105
|
-
except Exception as e:
|
|
106
|
-
return f"Error fetching URL: {str(e)}"
|
|
107
|
-
|
|
108
|
-
def _native_listen(self, port, handler_name):
|
|
109
|
-
interpreter_instance = self
|
|
110
|
-
class SolHTTPHandler(http.server.BaseHTTPRequestHandler):
|
|
111
|
-
def do_GET(self):
|
|
112
|
-
self.send_response(200)
|
|
113
|
-
self.send_header("Content-type", "text/html")
|
|
114
|
-
self.end_headers()
|
|
115
|
-
response_body = interpreter_instance._call_function(handler_name, [self.path])
|
|
116
|
-
self.wfile.write(bytes(str(response_body), "utf-8"))
|
|
117
|
-
def log_message(self, format, *args):
|
|
118
|
-
pass
|
|
119
|
-
|
|
120
|
-
def server_thread():
|
|
121
|
-
server = http.server.HTTPServer(("0.0.0.0", int(port)), SolHTTPHandler)
|
|
122
|
-
server.serve_forever()
|
|
123
|
-
|
|
124
|
-
t = threading.Thread(target=server_thread, daemon=True)
|
|
125
|
-
t.start()
|
|
126
|
-
self.threads.append(t)
|
|
127
|
-
|
|
128
|
-
def _evaluate_condition(self, cond):
|
|
129
|
-
if "=" in cond:
|
|
130
|
-
left, right = cond.split("=")
|
|
131
|
-
return self._compute(left.strip()) == self._compute(right.strip())
|
|
132
|
-
elif "<" in cond:
|
|
133
|
-
left, right = cond.split("<")
|
|
134
|
-
return self._compute(left.strip()) < self._compute(right.strip())
|
|
135
|
-
elif ">" in cond:
|
|
136
|
-
left, right = cond.split(">")
|
|
137
|
-
return self._compute(left.strip()) > self._compute(right.strip())
|
|
138
|
-
return False
|
|
139
|
-
|
|
140
|
-
def _get_block_end(self, start_pc):
|
|
141
|
-
depth = 1
|
|
142
|
-
pc = start_pc + 1
|
|
143
|
-
while pc < len(self.lines):
|
|
144
|
-
line = self.lines[pc]
|
|
145
|
-
if line.startswith("if ") or line.startswith("while ") or line.startswith("for "):
|
|
146
|
-
depth += 1
|
|
147
|
-
elif line == "end":
|
|
148
|
-
depth -= 1
|
|
149
|
-
if depth == 0:
|
|
150
|
-
return pc
|
|
151
|
-
pc += 1
|
|
152
|
-
return pc
|
|
153
|
-
|
|
154
|
-
def execute(self, code):
|
|
155
|
-
self.lines = []
|
|
156
|
-
for raw_line in code.split('\n'):
|
|
157
|
-
if ';' in raw_line:
|
|
158
|
-
raw_line = raw_line.split(';', 1)[0]
|
|
159
|
-
trimmed = raw_line.strip()
|
|
160
|
-
if trimmed:
|
|
161
|
-
self.lines.append(trimmed)
|
|
162
|
-
|
|
163
|
-
self.threads = []
|
|
164
|
-
|
|
165
|
-
pc = 0
|
|
166
|
-
while pc < len(self.lines):
|
|
167
|
-
line = self.lines[pc]
|
|
168
|
-
if "(" in line and ")" in line and "main" not in line and "end" not in line and "->" not in line and ">>" not in line and "?" not in line and not line.startswith("if ") and not line.startswith("while ") and not line.startswith("for "):
|
|
169
|
-
parts = line.split("(")
|
|
170
|
-
name = parts[0].strip()
|
|
171
|
-
params_str = parts[1].replace(")", "").strip()
|
|
172
|
-
params = [p.strip() for p in params_str.split(",")] if params_str else []
|
|
173
|
-
self.functions[name] = {"start_pc": pc + 1, "params": params}
|
|
174
|
-
elif "{" in line:
|
|
175
|
-
pc = self._parse_struct(pc)
|
|
176
|
-
continue
|
|
177
|
-
pc += 1
|
|
178
|
-
|
|
179
|
-
for i, line in enumerate(self.lines):
|
|
180
|
-
if line == "main()":
|
|
181
|
-
try:
|
|
182
|
-
self._run_block(i + 1)
|
|
183
|
-
except ReturnSignal:
|
|
184
|
-
pass
|
|
185
|
-
break
|
|
186
|
-
|
|
187
|
-
for t in self.threads:
|
|
188
|
-
if t.is_alive() and not t.daemon:
|
|
189
|
-
t.join()
|
|
190
|
-
|
|
191
|
-
def _parse_struct(self, pc):
|
|
192
|
-
line = self.lines[pc]
|
|
193
|
-
struct_name = line.split("{}")[0].strip()
|
|
194
|
-
fields = {}
|
|
195
|
-
pc += 1
|
|
196
|
-
while pc < len(self.lines) and self.lines[pc] != "end":
|
|
197
|
-
if "->" in self.lines[pc]:
|
|
198
|
-
key, val = [x.strip() for x in self.lines[pc].split("->")]
|
|
199
|
-
fields[key] = self._resolve(val)
|
|
200
|
-
pc += 1
|
|
201
|
-
self.struct_blueprints[struct_name] = fields
|
|
202
|
-
self._assign(struct_name, fields.copy())
|
|
203
|
-
return pc
|
|
204
|
-
|
|
205
|
-
def _call_function(self, name, args):
|
|
206
|
-
func_info = self.functions[name]
|
|
207
|
-
start_pc = func_info["start_pc"]
|
|
208
|
-
params = func_info["params"]
|
|
209
|
-
|
|
210
|
-
local_scope = {}
|
|
211
|
-
for param, arg in zip(params, args):
|
|
212
|
-
local_scope[param] = arg
|
|
213
|
-
|
|
214
|
-
self.scope_stack.append(local_scope)
|
|
215
|
-
|
|
216
|
-
return_value = 0
|
|
217
|
-
try:
|
|
218
|
-
self._run_block(start_pc)
|
|
219
|
-
except ReturnSignal as sig:
|
|
220
|
-
return_value = sig.value
|
|
221
|
-
finally:
|
|
222
|
-
self.scope_stack.pop()
|
|
223
|
-
|
|
224
|
-
return return_value
|
|
225
|
-
|
|
226
|
-
def _execute_line(self, line):
|
|
227
|
-
# Pipeline Check for Asynchronous Custom Prompts: "Name: " >> _input >> a
|
|
228
|
-
if ">>" in line and "_input" in line:
|
|
229
|
-
parts = [p.strip() for p in line.split(">>")]
|
|
230
|
-
if len(parts) == 3 and parts[1] == "_input":
|
|
231
|
-
prompt_string = str(self._compute(parts[0]))
|
|
232
|
-
target_variable = parts[2]
|
|
233
|
-
|
|
234
|
-
t = threading.Thread(target=self._async_input_worker, args=(prompt_string, target_variable))
|
|
235
|
-
t.start()
|
|
236
|
-
self.threads.append(t)
|
|
237
|
-
return
|
|
238
|
-
|
|
239
|
-
is_async_func = False
|
|
240
|
-
if ">>" in line and "_async" in line and "(" in line and not line.startswith("_"):
|
|
241
|
-
is_async_func = True
|
|
242
|
-
line = line.split(">>")[0].strip()
|
|
243
|
-
|
|
244
|
-
if line.startswith("_return ->"):
|
|
245
|
-
val_expr = line.split("->", 1)[1].strip()
|
|
246
|
-
result = self._compute(val_expr)
|
|
247
|
-
raise ReturnSignal(result)
|
|
248
|
-
|
|
249
|
-
elif ">>" in line and "_async" in line and not is_async_func:
|
|
250
|
-
parts = line.split(">>")
|
|
251
|
-
t = threading.Thread(target=self._async_worker, args=(parts[0].strip(), parts[2].strip()))
|
|
252
|
-
t.start()
|
|
253
|
-
self.threads.append(t)
|
|
254
|
-
|
|
255
|
-
elif line.startswith("_in ->"):
|
|
256
|
-
var_name = line.split("->")[1].strip()
|
|
257
|
-
user_val = input(f"[INPUT REQUIRED FOR %s]: " % var_name)
|
|
258
|
-
try:
|
|
259
|
-
if '.' in user_val: user_val = float(user_val)
|
|
260
|
-
else: user_val = int(user_val)
|
|
261
|
-
except ValueError: pass
|
|
262
|
-
self._assign(var_name, user_val)
|
|
263
|
-
|
|
264
|
-
elif "_add(" in line:
|
|
265
|
-
content = line.replace("_add(", "").replace(")", "")
|
|
266
|
-
parts = [p.strip() for p in content.split(",")]
|
|
267
|
-
container = self._lookup(parts[0])
|
|
268
|
-
if isinstance(container, list):
|
|
269
|
-
container.insert(int(parts[1]), self._resolve(parts[2]))
|
|
270
|
-
elif "_remove(" in line:
|
|
271
|
-
content = line.replace("_remove(", "").replace(")", "")
|
|
272
|
-
parts = [p.strip() for p in content.split(",")]
|
|
273
|
-
container = self._lookup(parts[0])
|
|
274
|
-
if isinstance(container, list):
|
|
275
|
-
container.pop(int(parts[1]))
|
|
276
|
-
elif "_listen(" in line:
|
|
277
|
-
content = line.replace("_listen(", "").replace(")", "")
|
|
278
|
-
port_expr, handler_expr = [p.strip() for p in content.split(",")]
|
|
279
|
-
port = self._compute(port_expr)
|
|
280
|
-
self._native_listen(port, handler_expr)
|
|
281
|
-
elif "_out" in line:
|
|
282
|
-
val = line.split("->")[1].strip()
|
|
283
|
-
print(self._compute(val))
|
|
284
|
-
|
|
285
|
-
elif "mylist<" in line and ">" in line:
|
|
286
|
-
var_name = line.split("<")[1].split(">")[0]
|
|
287
|
-
self._assign(var_name, [])
|
|
288
|
-
|
|
289
|
-
elif "->" in line:
|
|
290
|
-
var, val = [x.strip() for x in line.split("->")]
|
|
291
|
-
if "." in var:
|
|
292
|
-
obj, prop = var.split(".")
|
|
293
|
-
target_obj = self._lookup(obj)
|
|
294
|
-
if isinstance(target_obj, dict):
|
|
295
|
-
target_obj[prop] = self._compute(val)
|
|
296
|
-
else:
|
|
297
|
-
self._assign(var, self._compute(val))
|
|
298
|
-
else:
|
|
299
|
-
if "(" in line and line.endswith(")") and not line.startswith("_"):
|
|
300
|
-
parts = line.split("(")
|
|
301
|
-
name = parts[0].strip()
|
|
302
|
-
if name in self.functions:
|
|
303
|
-
args_str = parts[1][:-1].strip()
|
|
304
|
-
args = [self._compute(a.strip()) for a in args_str.split(",")] if args_str else []
|
|
305
|
-
|
|
306
|
-
if is_async_func:
|
|
307
|
-
t = threading.Thread(target=self._call_function, args=(name, args))
|
|
308
|
-
t.start()
|
|
309
|
-
self.threads.append(t)
|
|
310
|
-
else:
|
|
311
|
-
self._call_function(name, args)
|
|
312
|
-
|
|
313
|
-
def _run_block(self, start_pc):
|
|
314
|
-
pc = start_pc
|
|
315
|
-
control_stack = []
|
|
316
|
-
|
|
317
|
-
while pc < len(self.lines):
|
|
318
|
-
line = self.lines[pc]
|
|
319
|
-
is_executing = all(level["executing"] for level in control_stack)
|
|
320
|
-
|
|
321
|
-
if line.startswith("if "):
|
|
322
|
-
cond = line.split("if ", 1)[1].strip()
|
|
323
|
-
if is_executing:
|
|
324
|
-
cond_true = self._evaluate_condition(cond)
|
|
325
|
-
control_stack.append({"type": "if", "executing": cond_true, "any_branch_true": cond_true})
|
|
326
|
-
else:
|
|
327
|
-
control_stack.append({"type": "if", "executing": False, "any_branch_true": True})
|
|
328
|
-
pc += 1
|
|
329
|
-
continue
|
|
330
|
-
|
|
331
|
-
elif line.startswith("elseif "):
|
|
332
|
-
cond = line.split("elseif ", 1)[1].strip()
|
|
333
|
-
parent_active = all(level["executing"] for level in control_stack[:-1]) if len(control_stack) > 1 else True
|
|
334
|
-
|
|
335
|
-
if control_stack and control_stack[-1]["type"] == "if":
|
|
336
|
-
if parent_active and not control_stack[-1]["any_branch_true"]:
|
|
337
|
-
cond_true = self._evaluate_condition(cond)
|
|
338
|
-
control_stack[-1]["executing"] = cond_true
|
|
339
|
-
control_stack[-1]["any_branch_true"] = cond_true
|
|
340
|
-
else:
|
|
341
|
-
control_stack[-1]["executing"] = False
|
|
342
|
-
pc += 1
|
|
343
|
-
continue
|
|
344
|
-
|
|
345
|
-
elif line == "else":
|
|
346
|
-
parent_active = all(level["executing"] for level in control_stack[:-1]) if len(control_stack) > 1 else True
|
|
347
|
-
if control_stack and control_stack[-1]["type"] == "if":
|
|
348
|
-
if parent_active and not control_stack[-1]["any_branch_true"]:
|
|
349
|
-
control_stack[-1]["executing"] = True
|
|
350
|
-
control_stack[-1]["any_branch_true"] = True
|
|
351
|
-
else:
|
|
352
|
-
control_stack[-1]["executing"] = False
|
|
353
|
-
pc += 1
|
|
354
|
-
continue
|
|
355
|
-
|
|
356
|
-
elif line.startswith("while "):
|
|
357
|
-
cond = line.split("while ", 1)[1].strip()
|
|
358
|
-
if is_executing:
|
|
359
|
-
end_pc = self._get_block_end(pc)
|
|
360
|
-
if self._evaluate_condition(cond):
|
|
361
|
-
control_stack.append({"type": "while", "executing": True, "start_pc": pc, "end_pc": end_pc})
|
|
362
|
-
pc += 1
|
|
363
|
-
else:
|
|
364
|
-
pc = end_pc + 1
|
|
365
|
-
else:
|
|
366
|
-
control_stack.append({"type": "while", "executing": False})
|
|
367
|
-
pc += 1
|
|
368
|
-
continue
|
|
369
|
-
|
|
370
|
-
elif line.startswith("for "):
|
|
371
|
-
if is_executing:
|
|
372
|
-
parts = line.split("for ", 1)[1].split("->")
|
|
373
|
-
var_name = parts[0].strip()
|
|
374
|
-
range_parts = parts[1].split(" to ")
|
|
375
|
-
start_val = int(self._compute(range_parts[0].strip()))
|
|
376
|
-
end_val = int(self._compute(range_parts[1].strip()))
|
|
377
|
-
|
|
378
|
-
self._assign(var_name, start_val)
|
|
379
|
-
end_pc = self._get_block_end(pc)
|
|
380
|
-
|
|
381
|
-
if start_val <= end_val:
|
|
382
|
-
control_stack.append({"type": "for", "executing": True, "var": var_name, "end_val": end_val, "start_pc": pc, "end_pc": end_pc})
|
|
383
|
-
pc += 1
|
|
384
|
-
else:
|
|
385
|
-
pc = end_pc + 1
|
|
386
|
-
else:
|
|
387
|
-
control_stack.append({"type": "for", "executing": False})
|
|
388
|
-
pc += 1
|
|
389
|
-
continue
|
|
390
|
-
|
|
391
|
-
elif line == "end":
|
|
392
|
-
if control_stack:
|
|
393
|
-
top = control_stack[-1]
|
|
394
|
-
if top.get("type") == "while" and top["executing"]:
|
|
395
|
-
pc = top["start_pc"]
|
|
396
|
-
control_stack.pop()
|
|
397
|
-
continue
|
|
398
|
-
elif top.get("type") == "for" and top["executing"]:
|
|
399
|
-
var_name = top["var"]
|
|
400
|
-
next_val = self._lookup(var_name) + 1
|
|
401
|
-
if next_val <= top["end_val"]:
|
|
402
|
-
self._assign(var_name, next_val)
|
|
403
|
-
pc = top["start_pc"] + 1
|
|
404
|
-
continue
|
|
405
|
-
else:
|
|
406
|
-
control_stack.pop()
|
|
407
|
-
pc += 1
|
|
408
|
-
continue
|
|
409
|
-
else:
|
|
410
|
-
control_stack.pop()
|
|
411
|
-
pc += 1
|
|
412
|
-
continue
|
|
413
|
-
else:
|
|
414
|
-
break
|
|
415
|
-
|
|
416
|
-
if is_executing:
|
|
417
|
-
if "?" in line:
|
|
418
|
-
cond, action = line.split("?", 1)
|
|
419
|
-
if self._evaluate_condition(cond.strip()):
|
|
420
|
-
self._execute_line(action.strip())
|
|
421
|
-
else:
|
|
422
|
-
self._execute_line(line)
|
|
423
|
-
pc += 1
|
|
424
|
-
|
|
425
|
-
def main():
|
|
426
|
-
if len(sys.argv) < 2:
|
|
427
|
-
print("Error: No script file provided.\nUsage: solpl <filename.sol>", file=sys.stderr)
|
|
428
|
-
sys.exit(1)
|
|
429
|
-
|
|
430
|
-
filename = sys.argv[1]
|
|
431
|
-
if not filename.endswith(".sol"):
|
|
432
|
-
print("Error: File must have a '.sol' extension.", file=sys.stderr)
|
|
433
|
-
sys.exit(1)
|
|
434
|
-
if not os.path.exists(filename):
|
|
435
|
-
print(f"Error: File '{filename}' not found.", file=sys.stderr)
|
|
436
|
-
sys.exit(1)
|
|
437
|
-
|
|
438
|
-
with open(filename, "r") as f:
|
|
439
|
-
code_content = f.read()
|
|
440
|
-
|
|
441
|
-
engine = SolInterpreter()
|
|
442
|
-
engine.execute(code_content)
|
|
443
|
-
|
|
444
|
-
if __name__ == "__main__":
|
|
445
|
-
main()
|
solpl-2.0.0/pyproject.toml
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
[build-system]
|
|
2
|
-
requires = ["setuptools>=61.0"]
|
|
3
|
-
build-backend = "setuptools.build_meta"
|
|
4
|
-
|
|
5
|
-
[project]
|
|
6
|
-
name = "solpl"
|
|
7
|
-
version = "2.0.0"
|
|
8
|
-
authors = [
|
|
9
|
-
{ name="Your Name", email="your.email@example.com" }
|
|
10
|
-
]
|
|
11
|
-
description = "A lightweight, multi-threaded interpreter for the Sol programming language."
|
|
12
|
-
readme = "README.md"
|
|
13
|
-
license = {text = "Apache-2.0"}
|
|
14
|
-
requires-python = ">=3.7"
|
|
15
|
-
classifiers = [
|
|
16
|
-
"Programming Language :: Python :: 3",
|
|
17
|
-
"License :: OSI Approved :: Apache Software License",
|
|
18
|
-
"Operating System :: OS Independent",
|
|
19
|
-
]
|
|
20
|
-
|
|
21
|
-
[project.scripts]
|
|
22
|
-
solpl = "interpreter.sol:main"
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: solpl
|
|
3
|
-
Version: 2.0.0
|
|
4
|
-
Summary: A lightweight, multi-threaded interpreter for the Sol programming language.
|
|
5
|
-
Author-email: Your Name <your.email@example.com>
|
|
6
|
-
License: Apache-2.0
|
|
7
|
-
Classifier: Programming Language :: Python :: 3
|
|
8
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
9
|
-
Classifier: Operating System :: OS Independent
|
|
10
|
-
Requires-Python: >=3.7
|
|
11
|
-
Description-Content-Type: text/markdown
|
|
12
|
-
License-File: LICENSE
|
|
13
|
-
Dynamic: license-file
|
|
14
|
-
|
|
15
|
-
# Sol
|
|
16
|
-
Sol is an interpreted language built with Python, originally designed to handle async operations only, but has expanded to a full scripting language.
|
|
17
|
-
|
|
18
|
-
# Why did I build Sol?
|
|
19
|
-
|
|
20
|
-
I needed something fast, that handled async natively, and which had very few keywords. Then came my first prototype, which only supported async functions. Sol now supports everything a programming language should need: Functions, variables, I/O, etc.
|
|
21
|
-
|
|
22
|
-
# How to install Sol?
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
pip install solpl
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
# How to run a Sol script?
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
solpl FILENAME.sol
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
# Example:
|
|
35
|
-
|
|
36
|
-
This demonstrates Sol's capabilities with async:
|
|
37
|
-
|
|
38
|
-
```lua
|
|
39
|
-
countDown(taskName, maxCount)
|
|
40
|
-
for i -> 1 to maxCount
|
|
41
|
-
_out -> taskName
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
main()
|
|
46
|
-
_out -> 111
|
|
47
|
-
countDown(777, 4) >> _async
|
|
48
|
-
countDown(999, 4) >> _async
|
|
49
|
-
_out -> 222
|
|
50
|
-
end
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
# License
|
|
54
|
-
|
|
55
|
-
This repository is licensed with Apache License 2.0, see the LICENSE file for more details
|
|
56
|
-
|
|
57
|
-
# Link to PyPi package:
|
|
58
|
-
|
|
59
|
-
https://pypi.org/project/solpl/
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
interpreter
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|