shell-lite 0.5.3.2__tar.gz → 0.5.3.4__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.
- {shell_lite-0.5.3.2/shell_lite.egg-info → shell_lite-0.5.3.4}/PKG-INFO +4 -4
- {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/README.md +3 -3
- {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/pyproject.toml +1 -1
- {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite/interpreter.py +13 -4
- {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite/main.py +2 -2
- {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite/parser_gbp.py +141 -1
- {shell_lite-0.5.3.2 → shell_lite-0.5.3.4/shell_lite.egg-info}/PKG-INFO +4 -4
- {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/LICENSE +0 -0
- {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/setup.cfg +0 -0
- {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/setup.py +0 -0
- {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite/__init__.py +0 -0
- {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite/ast_nodes.py +0 -0
- {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite/cli.py +0 -0
- {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite/compiler.py +0 -0
- {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite/js_compiler.py +0 -0
- {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite/lexer.py +0 -0
- {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite/parser.py +0 -0
- {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite/runtime.py +0 -0
- {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite.egg-info/SOURCES.txt +0 -0
- {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite.egg-info/dependency_links.txt +0 -0
- {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite.egg-info/entry_points.txt +0 -0
- {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite.egg-info/requires.txt +0 -0
- {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite.egg-info/top_level.txt +0 -0
- {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/tests/test_gbp_standalone.py +0 -0
- {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/tests/test_interpreter.py +0 -0
- {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/tests/test_lexer.py +0 -0
- {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/tests/test_parser.py +0 -0
- {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/tests/test_phase1.py +0 -0
- {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/tests/test_stdlib.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: shell-lite
|
|
3
|
-
Version: 0.5.3.
|
|
3
|
+
Version: 0.5.3.4
|
|
4
4
|
Summary: A lightweight, English-like scripting language.
|
|
5
5
|
Home-page: https://github.com/Shrey-N/ShellDesk
|
|
6
6
|
Author: Shrey Naithani
|
|
@@ -21,8 +21,8 @@ Requires-Dist: prompt_toolkit>=3.0.0
|
|
|
21
21
|
|
|
22
22
|
ShellLite is a modern programming language designed to prioritize human readability. It replaces complex syntax with natural English commands, making software development accessible and maintainable. With version 0.05.0, ShellLite now supports native compilation via LLVM alongside its interpreted mode.
|
|
23
23
|
|
|
24
|
-
[](https://www.gnu.org/licenses/gpl-3.0.html)
|
|
25
|
+
[]()
|
|
26
26
|
|
|
27
27
|
---
|
|
28
28
|
|
|
@@ -469,7 +469,7 @@ See [SECURITY.md](SECURITY.md) for reporting security vulnerabilities.
|
|
|
469
469
|
|
|
470
470
|
## License
|
|
471
471
|
|
|
472
|
-
|
|
472
|
+
GNU GPL V3 With Class Exception License - See [LICENSE](LICENSE) for details.
|
|
473
473
|
|
|
474
474
|
---
|
|
475
475
|
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
ShellLite is a modern programming language designed to prioritize human readability. It replaces complex syntax with natural English commands, making software development accessible and maintainable. With version 0.05.0, ShellLite now supports native compilation via LLVM alongside its interpreted mode.
|
|
8
8
|
|
|
9
|
-
[](https://www.gnu.org/licenses/gpl-3.0.html)
|
|
10
|
+
[]()
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
@@ -454,7 +454,7 @@ See [SECURITY.md](SECURITY.md) for reporting security vulnerabilities.
|
|
|
454
454
|
|
|
455
455
|
## License
|
|
456
456
|
|
|
457
|
-
|
|
457
|
+
GNU GPL V3 With Class Exception License - See [LICENSE](LICENSE) for details.
|
|
458
458
|
|
|
459
459
|
---
|
|
460
460
|
|
|
@@ -490,9 +490,9 @@ class Interpreter:
|
|
|
490
490
|
code_parts.append(colors[node.color.lower()])
|
|
491
491
|
if code_parts:
|
|
492
492
|
ansi_code = "\033[" + ";".join(code_parts) + "m"
|
|
493
|
-
print(f"{ansi_code}{value}\033[0m")
|
|
493
|
+
print(f"{ansi_code}{value}\033[0m", flush=True)
|
|
494
494
|
return value
|
|
495
|
-
print(value)
|
|
495
|
+
print(value, flush=True)
|
|
496
496
|
return value
|
|
497
497
|
def visit_If(self, node: If):
|
|
498
498
|
condition = self.visit(node.condition)
|
|
@@ -615,7 +615,6 @@ class Interpreter:
|
|
|
615
615
|
finally:
|
|
616
616
|
self.web.pop()
|
|
617
617
|
return result
|
|
618
|
-
return result
|
|
619
618
|
try:
|
|
620
619
|
func = self.current_env.get(node.name)
|
|
621
620
|
if callable(func):
|
|
@@ -1397,6 +1396,16 @@ class Interpreter:
|
|
|
1397
1396
|
class ReusableHTTPServer(ThreadingHTTPServer):
|
|
1398
1397
|
allow_reuse_address = True
|
|
1399
1398
|
daemon_threads = True
|
|
1399
|
+
|
|
1400
|
+
def handle_error(self, request, client_address):
|
|
1401
|
+
# Suppress output for connection resets (common with browser disconnects)
|
|
1402
|
+
try:
|
|
1403
|
+
_, exc, _ = sys.exc_info()
|
|
1404
|
+
if isinstance(exc, (ConnectionResetError, BrokenPipeError)):
|
|
1405
|
+
return
|
|
1406
|
+
except:
|
|
1407
|
+
pass
|
|
1408
|
+
super().handle_error(request, client_address)
|
|
1400
1409
|
class ShellLiteHandler(BaseHTTPRequestHandler):
|
|
1401
1410
|
def log_message(self, format, *args): pass
|
|
1402
1411
|
def do_GET(self):
|
|
@@ -1504,7 +1513,7 @@ class Interpreter:
|
|
|
1504
1513
|
self.wfile.write(str(e).encode())
|
|
1505
1514
|
except: pass
|
|
1506
1515
|
server = ReusableHTTPServer(('0.0.0.0', port_val), ShellLiteHandler)
|
|
1507
|
-
print(f"\n ShellLite Server v0.5.3.
|
|
1516
|
+
print(f"\n ShellLite Server v0.5.3.4 is running!")
|
|
1508
1517
|
print(f" \u001b[1;36m➜\u001b[0m Local: \u001b[1;4;36mhttp://localhost:{port_val}/\u001b[0m\n")
|
|
1509
1518
|
try: server.serve_forever()
|
|
1510
1519
|
except KeyboardInterrupt:
|
|
@@ -150,7 +150,7 @@ def install_globally():
|
|
|
150
150
|
return
|
|
151
151
|
ps_cmd = f'$oldPath = [Environment]::GetEnvironmentVariable("Path", "User"); if ($oldPath -notlike "*ShellLite*") {{ [Environment]::SetEnvironmentVariable("Path", "$oldPath;{install_dir}", "User") }}'
|
|
152
152
|
subprocess.run(["powershell", "-Command", ps_cmd], capture_output=True)
|
|
153
|
-
print(f"\n[SUCCESS] ShellLite (v0.5.3.
|
|
153
|
+
print(f"\n[SUCCESS] ShellLite (v0.5.3.3) is installed!")
|
|
154
154
|
print(f"Location: {install_dir}")
|
|
155
155
|
print("\nIMPORTANT STEP REQUIRED:")
|
|
156
156
|
print("1. Close ALL open terminal windows (CMD, PowerShell, VS Code).")
|
|
@@ -448,7 +448,7 @@ def main():
|
|
|
448
448
|
from importlib.metadata import version
|
|
449
449
|
print(f"ShellLite v{version('shell-lite')}")
|
|
450
450
|
except Exception:
|
|
451
|
-
print("ShellLite v0.5.3.
|
|
451
|
+
print("ShellLite v0.5.3.3")
|
|
452
452
|
elif cmd == "get":
|
|
453
453
|
if len(sys.argv) > 2:
|
|
454
454
|
package_name = sys.argv[2]
|
|
@@ -105,6 +105,8 @@ class GeometricBindingParser:
|
|
|
105
105
|
return self.bind_return(node)
|
|
106
106
|
elif head_type == 'REPEAT':
|
|
107
107
|
return self.bind_repeat(node)
|
|
108
|
+
elif head_type == 'FOREVER':
|
|
109
|
+
return self.bind_forever(node)
|
|
108
110
|
elif head_type == 'START':
|
|
109
111
|
return self.bind_start(node)
|
|
110
112
|
elif head_type == 'LISTEN':
|
|
@@ -139,6 +141,112 @@ class GeometricBindingParser:
|
|
|
139
141
|
count = self.parse_expr_iterative(expr_tokens)
|
|
140
142
|
body = [self.bind_node(child) for child in node.children]
|
|
141
143
|
return Repeat(count, body)
|
|
144
|
+
|
|
145
|
+
def bind_forever(self, node: GeoNode) -> Forever:
|
|
146
|
+
body = [self.bind_node(child) for child in node.children]
|
|
147
|
+
return Forever(body)
|
|
148
|
+
|
|
149
|
+
def bind_for(self, node: GeoNode) -> Node:
|
|
150
|
+
# 'for i in range 1 10' or 'for item in list'
|
|
151
|
+
# node.tokens starts with FOR/LOOP
|
|
152
|
+
# Next should be ID (var name)
|
|
153
|
+
if len(node.tokens) < 3:
|
|
154
|
+
return None # Error?
|
|
155
|
+
|
|
156
|
+
var_name = node.tokens[1].value
|
|
157
|
+
|
|
158
|
+
# Check for 'IN'
|
|
159
|
+
in_index = -1
|
|
160
|
+
for i, t in enumerate(node.tokens):
|
|
161
|
+
if t.type == 'IN':
|
|
162
|
+
in_index = i
|
|
163
|
+
break
|
|
164
|
+
|
|
165
|
+
if in_index == -1:
|
|
166
|
+
# Maybe 'loop 10 times'? No, that's Repeat (handled by bind_repeat if HEAD is REPEAT)
|
|
167
|
+
# But if HEAD is LOOP?
|
|
168
|
+
if node.head_token.type == 'LOOP':
|
|
169
|
+
# loop 200 times
|
|
170
|
+
# Delegated to bind_repeat logic if we can re-route, OR implement here
|
|
171
|
+
# Look for TIMES
|
|
172
|
+
if node.tokens[-1].type == 'TIMES':
|
|
173
|
+
expr_tokens = self._extract_expr_tokens(node.tokens, start=1)
|
|
174
|
+
expr_tokens.pop() # remove TIMES
|
|
175
|
+
count = self.parse_expr_iterative(expr_tokens)
|
|
176
|
+
body = [self.bind_node(child) for child in node.children]
|
|
177
|
+
return Repeat(count, body)
|
|
178
|
+
return None
|
|
179
|
+
|
|
180
|
+
# It is a FOR loop
|
|
181
|
+
# Check for RANGE
|
|
182
|
+
range_index = -1
|
|
183
|
+
for i, t in enumerate(node.tokens):
|
|
184
|
+
if t.type == 'RANGE':
|
|
185
|
+
range_index = i
|
|
186
|
+
break
|
|
187
|
+
|
|
188
|
+
if range_index != -1:
|
|
189
|
+
# for i in range 1 10
|
|
190
|
+
# Extract args after RANGE
|
|
191
|
+
args_tokens = node.tokens[range_index+1:]
|
|
192
|
+
# We need to split by space/comma? parse_expr_iterative might consume all?
|
|
193
|
+
# Range takes start, end, step.
|
|
194
|
+
# We can cheat and wrap them in a Call to 'range'?
|
|
195
|
+
# Or parse sub-expressions.
|
|
196
|
+
# Simplification: Assume numbers/vars separated by nothing (since lexer doesn't produce commas for spaces)
|
|
197
|
+
# But parse_expr_iterative consumes everything.
|
|
198
|
+
# We need to split manually if they are distinct expressions.
|
|
199
|
+
# Let's try to parse one expr, see where it ends? Not easy with shunting yard.
|
|
200
|
+
|
|
201
|
+
# Fallback: Create a Call('range', ...)
|
|
202
|
+
# Actually, interpreter expects 'count' for For loop?
|
|
203
|
+
# No, AST For node: For(count, body) -> interpreted as Repeat?
|
|
204
|
+
# Wait, AST For(count, body) vs ForIn(var_name, iterable, body)
|
|
205
|
+
|
|
206
|
+
# Let's see AST definition.
|
|
207
|
+
pass
|
|
208
|
+
|
|
209
|
+
# It is likely a ForIn
|
|
210
|
+
# iterable is everything after IN
|
|
211
|
+
iterable_tokens = self._extract_expr_tokens(node.tokens, start=in_index+1)
|
|
212
|
+
iterable = self.parse_expr_iterative(iterable_tokens)
|
|
213
|
+
body = [self.bind_node(child) for child in node.children]
|
|
214
|
+
|
|
215
|
+
# Handle 'range 1 10' as an iterable (Call to range)
|
|
216
|
+
if node.tokens[in_index+1].type == 'RANGE':
|
|
217
|
+
# tokens: FOR i IN RANGE 1 10
|
|
218
|
+
# We want Call('range', [1, 10])
|
|
219
|
+
# Extract numbers after RANGE
|
|
220
|
+
args_tokens = self._extract_expr_tokens(node.tokens, start=in_index+2)
|
|
221
|
+
# Assumption: args are space separated expressions.
|
|
222
|
+
# parse_expr_iterative consumes all.
|
|
223
|
+
# We need to manually split if there are multiple args?
|
|
224
|
+
# But 'range 1 10' in ShellLite usually means two numbers.
|
|
225
|
+
# If we just Pass all tokens to parse_expr_iterative, it might just return the first one if not connected by operator.
|
|
226
|
+
# For 'range 1 10', we have NUMBER 1, NUMBER 10.
|
|
227
|
+
# We need to build a list of args.
|
|
228
|
+
range_args = []
|
|
229
|
+
k = 0
|
|
230
|
+
while k < len(args_tokens):
|
|
231
|
+
# Try to parse one expression?
|
|
232
|
+
# This is hard with current parser structure.
|
|
233
|
+
# SIMPLE HACK: Just take the next two tokens as numbers?
|
|
234
|
+
# Or treat them as separate expression?
|
|
235
|
+
if args_tokens[k].type in ('NUMBER', 'STRING', 'ID'):
|
|
236
|
+
t = args_tokens[k]
|
|
237
|
+
val = None
|
|
238
|
+
if t.type == 'NUMBER':
|
|
239
|
+
val = Number(int(t.value) if '.' not in t.value else float(t.value))
|
|
240
|
+
elif t.type == 'STRING':
|
|
241
|
+
val = String(t.value)
|
|
242
|
+
elif t.type == 'ID':
|
|
243
|
+
val = VarAccess(t.value)
|
|
244
|
+
if val: range_args.append(val)
|
|
245
|
+
k += 1
|
|
246
|
+
|
|
247
|
+
iterable = Call('range', range_args)
|
|
248
|
+
|
|
249
|
+
return ForIn(var_name, iterable, body)
|
|
142
250
|
def bind_print(self, node: GeoNode) -> Print:
|
|
143
251
|
expr_tokens = self._extract_expr_tokens(node.tokens, start=1)
|
|
144
252
|
expr = self.parse_expr_iterative(expr_tokens)
|
|
@@ -352,7 +460,39 @@ class GeometricBindingParser:
|
|
|
352
460
|
i = j # Advance past list
|
|
353
461
|
elif t.type == 'ID':
|
|
354
462
|
if i+1 < len(tokens) and tokens[i+1].type == 'LPAREN':
|
|
355
|
-
|
|
463
|
+
# Function call: ID(args)
|
|
464
|
+
name = t.value
|
|
465
|
+
|
|
466
|
+
# Find matching RPAREN
|
|
467
|
+
depth = 1
|
|
468
|
+
j = i + 2 # Skip ID and LPAREN
|
|
469
|
+
elements_tokens = []
|
|
470
|
+
current_elem = []
|
|
471
|
+
|
|
472
|
+
arg_tokens_start = j
|
|
473
|
+
# Check for empty call "func()"
|
|
474
|
+
if j < len(tokens) and tokens[j].type == 'RPAREN':
|
|
475
|
+
i = j # Advance to RPAREN
|
|
476
|
+
values.append(Call(name, []))
|
|
477
|
+
else:
|
|
478
|
+
while j < len(tokens):
|
|
479
|
+
if tokens[j].type == 'LPAREN': depth += 1
|
|
480
|
+
elif tokens[j].type == 'RPAREN': depth -= 1
|
|
481
|
+
|
|
482
|
+
if depth == 0:
|
|
483
|
+
if current_elem: elements_tokens.append(current_elem)
|
|
484
|
+
break
|
|
485
|
+
|
|
486
|
+
if tokens[j].type == 'COMMA' and depth == 1:
|
|
487
|
+
elements_tokens.append(current_elem)
|
|
488
|
+
current_elem = []
|
|
489
|
+
else:
|
|
490
|
+
current_elem.append(tokens[j])
|
|
491
|
+
j += 1
|
|
492
|
+
|
|
493
|
+
args = [self.parse_expr_iterative(elem) for elem in elements_tokens if elem]
|
|
494
|
+
values.append(Call(name, args))
|
|
495
|
+
i = j # Advance to RPAREN
|
|
356
496
|
else:
|
|
357
497
|
values.append(VarAccess(t.value))
|
|
358
498
|
elif t.type == 'LPAREN':
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: shell-lite
|
|
3
|
-
Version: 0.5.3.
|
|
3
|
+
Version: 0.5.3.4
|
|
4
4
|
Summary: A lightweight, English-like scripting language.
|
|
5
5
|
Home-page: https://github.com/Shrey-N/ShellDesk
|
|
6
6
|
Author: Shrey Naithani
|
|
@@ -21,8 +21,8 @@ Requires-Dist: prompt_toolkit>=3.0.0
|
|
|
21
21
|
|
|
22
22
|
ShellLite is a modern programming language designed to prioritize human readability. It replaces complex syntax with natural English commands, making software development accessible and maintainable. With version 0.05.0, ShellLite now supports native compilation via LLVM alongside its interpreted mode.
|
|
23
23
|
|
|
24
|
-
[](https://www.gnu.org/licenses/gpl-3.0.html)
|
|
25
|
+
[]()
|
|
26
26
|
|
|
27
27
|
---
|
|
28
28
|
|
|
@@ -469,7 +469,7 @@ See [SECURITY.md](SECURITY.md) for reporting security vulnerabilities.
|
|
|
469
469
|
|
|
470
470
|
## License
|
|
471
471
|
|
|
472
|
-
|
|
472
|
+
GNU GPL V3 With Class Exception License - See [LICENSE](LICENSE) for details.
|
|
473
473
|
|
|
474
474
|
---
|
|
475
475
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|