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.
Files changed (29) hide show
  1. {shell_lite-0.5.3.2/shell_lite.egg-info → shell_lite-0.5.3.4}/PKG-INFO +4 -4
  2. {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/README.md +3 -3
  3. {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/pyproject.toml +1 -1
  4. {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite/interpreter.py +13 -4
  5. {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite/main.py +2 -2
  6. {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite/parser_gbp.py +141 -1
  7. {shell_lite-0.5.3.2 → shell_lite-0.5.3.4/shell_lite.egg-info}/PKG-INFO +4 -4
  8. {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/LICENSE +0 -0
  9. {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/setup.cfg +0 -0
  10. {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/setup.py +0 -0
  11. {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite/__init__.py +0 -0
  12. {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite/ast_nodes.py +0 -0
  13. {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite/cli.py +0 -0
  14. {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite/compiler.py +0 -0
  15. {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite/js_compiler.py +0 -0
  16. {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite/lexer.py +0 -0
  17. {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite/parser.py +0 -0
  18. {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite/runtime.py +0 -0
  19. {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite.egg-info/SOURCES.txt +0 -0
  20. {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite.egg-info/dependency_links.txt +0 -0
  21. {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite.egg-info/entry_points.txt +0 -0
  22. {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite.egg-info/requires.txt +0 -0
  23. {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/shell_lite.egg-info/top_level.txt +0 -0
  24. {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/tests/test_gbp_standalone.py +0 -0
  25. {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/tests/test_interpreter.py +0 -0
  26. {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/tests/test_lexer.py +0 -0
  27. {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/tests/test_parser.py +0 -0
  28. {shell_lite-0.5.3.2 → shell_lite-0.5.3.4}/tests/test_phase1.py +0 -0
  29. {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.2
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
- [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
25
- [![Version](https://img.shields.io/badge/version-0.05.0-green.svg)]()
24
+ [![License: GPL v3](https://img.shields.io/badge/License-GPLv3--with--classpath--exception-blue.svg)](https://www.gnu.org/licenses/gpl-3.0.html)
25
+ [![Version](https://img.shields.io/badge/version-0.5.3.2-green.svg)]()
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
- MIT License - See [LICENSE](LICENSE) for details.
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
- [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
10
- [![Version](https://img.shields.io/badge/version-0.05.0-green.svg)]()
9
+ [![License: GPL v3](https://img.shields.io/badge/License-GPLv3--with--classpath--exception-blue.svg)](https://www.gnu.org/licenses/gpl-3.0.html)
10
+ [![Version](https://img.shields.io/badge/version-0.5.3.2-green.svg)]()
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
- MIT License - See [LICENSE](LICENSE) for details.
457
+ GNU GPL V3 With Class Exception License - See [LICENSE](LICENSE) for details.
458
458
 
459
459
  ---
460
460
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "shell-lite"
7
- version = "0.5.3.2"
7
+ version = "0.5.3.4"
8
8
  description = "A lightweight, English-like scripting language."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -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.2 is running!")
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.2) is installed!")
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.1")
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
- values.append(VarAccess(t.value))
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.2
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
- [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
25
- [![Version](https://img.shields.io/badge/version-0.05.0-green.svg)]()
24
+ [![License: GPL v3](https://img.shields.io/badge/License-GPLv3--with--classpath--exception-blue.svg)](https://www.gnu.org/licenses/gpl-3.0.html)
25
+ [![Version](https://img.shields.io/badge/version-0.5.3.2-green.svg)]()
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
- MIT License - See [LICENSE](LICENSE) for details.
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