shell-lite 0.4.3__tar.gz → 0.4.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.4.3/shell_lite.egg-info → shell_lite-0.4.4}/PKG-INFO +1 -1
- {shell_lite-0.4.3 → shell_lite-0.4.4}/pyproject.toml +1 -1
- shell_lite-0.4.3/shell_lite/interpreter_final.py → shell_lite-0.4.4/shell_lite/interpreter.py +10 -4
- shell_lite-0.4.3/shell_lite/lexer_new.py → shell_lite-0.4.4/shell_lite/lexer.py +2 -1
- {shell_lite-0.4.3 → shell_lite-0.4.4}/shell_lite/main.py +5 -5
- shell_lite-0.4.3/shell_lite/parser_new.py → shell_lite-0.4.4/shell_lite/parser.py +17 -3
- {shell_lite-0.4.3 → shell_lite-0.4.4/shell_lite.egg-info}/PKG-INFO +1 -1
- {shell_lite-0.4.3 → shell_lite-0.4.4}/shell_lite.egg-info/SOURCES.txt +0 -10
- shell_lite-0.4.3/shell_lite/fix_nulls.py +0 -29
- shell_lite-0.4.3/shell_lite/formatter.py +0 -75
- shell_lite-0.4.3/shell_lite/interpreter.py +0 -1779
- shell_lite-0.4.3/shell_lite/interpreter_backup.py +0 -1781
- shell_lite-0.4.3/shell_lite/interpreter_new.py +0 -1773
- shell_lite-0.4.3/shell_lite/js_compiler.py +0 -220
- shell_lite-0.4.3/shell_lite/lexer.py +0 -245
- shell_lite-0.4.3/shell_lite/minimal_interpreter.py +0 -25
- shell_lite-0.4.3/shell_lite/parser.py +0 -2093
- shell_lite-0.4.3/shell_lite/patch_parser.py +0 -41
- {shell_lite-0.4.3 → shell_lite-0.4.4}/LICENSE +0 -0
- {shell_lite-0.4.3 → shell_lite-0.4.4}/README.md +0 -0
- {shell_lite-0.4.3 → shell_lite-0.4.4}/setup.cfg +0 -0
- {shell_lite-0.4.3 → shell_lite-0.4.4}/shell_lite/__init__.py +0 -0
- {shell_lite-0.4.3 → shell_lite-0.4.4}/shell_lite/ast_nodes.py +0 -0
- {shell_lite-0.4.3 → shell_lite-0.4.4}/shell_lite/cli.py +0 -0
- {shell_lite-0.4.3 → shell_lite-0.4.4}/shell_lite/compiler.py +0 -0
- {shell_lite-0.4.3 → shell_lite-0.4.4}/shell_lite/runtime.py +0 -0
- {shell_lite-0.4.3 → shell_lite-0.4.4}/shell_lite.egg-info/dependency_links.txt +0 -0
- {shell_lite-0.4.3 → shell_lite-0.4.4}/shell_lite.egg-info/entry_points.txt +0 -0
- {shell_lite-0.4.3 → shell_lite-0.4.4}/shell_lite.egg-info/requires.txt +0 -0
- {shell_lite-0.4.3 → shell_lite-0.4.4}/shell_lite.egg-info/top_level.txt +0 -0
- {shell_lite-0.4.3 → shell_lite-0.4.4}/tests/test_interpreter.py +0 -0
- {shell_lite-0.4.3 → shell_lite-0.4.4}/tests/test_lexer.py +0 -0
- {shell_lite-0.4.3 → shell_lite-0.4.4}/tests/test_parser.py +0 -0
- {shell_lite-0.4.3 → shell_lite-0.4.4}/tests/test_stdlib.py +0 -0
shell_lite-0.4.3/shell_lite/interpreter_final.py → shell_lite-0.4.4/shell_lite/interpreter.py
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from typing import Any, Dict, List, Callable
|
|
2
2
|
from .ast_nodes import *
|
|
3
|
-
from .
|
|
4
|
-
from .
|
|
3
|
+
from .lexer import Token, Lexer
|
|
4
|
+
from .parser import Parser
|
|
5
5
|
import importlib
|
|
6
6
|
import operator
|
|
7
7
|
import re
|
|
@@ -128,7 +128,7 @@ class WebBuilder:
|
|
|
128
128
|
pass
|
|
129
129
|
class Interpreter:
|
|
130
130
|
def __init__(self):
|
|
131
|
-
print('DEBUG:
|
|
131
|
+
print('DEBUG: ShellLite v0.04.4')
|
|
132
132
|
self.global_env = Environment()
|
|
133
133
|
self.global_env.set('str', str)
|
|
134
134
|
self.global_env.set('int', int)
|
|
@@ -278,6 +278,12 @@ class Interpreter:
|
|
|
278
278
|
def _builtin_push(self, lst, item):
|
|
279
279
|
lst.append(item)
|
|
280
280
|
return None
|
|
281
|
+
def _builtin_upper(self, s):
|
|
282
|
+
return str(s).upper()
|
|
283
|
+
def _builtin_sum_range(self, start, end):
|
|
284
|
+
return sum(range(int(start), int(end)))
|
|
285
|
+
def _builtin_range_list(self, start, end):
|
|
286
|
+
return list(range(int(start), int(end)))
|
|
281
287
|
def _init_std_modules(self):
|
|
282
288
|
self.std_modules = {
|
|
283
289
|
'math': {
|
|
@@ -1534,7 +1540,7 @@ class Interpreter:
|
|
|
1534
1540
|
self.wfile.write(str(e).encode())
|
|
1535
1541
|
except: pass
|
|
1536
1542
|
server = HTTPServer(('0.0.0.0', port_val), ShellLiteHandler)
|
|
1537
|
-
print(f"\n ShellLite Server v0.04.
|
|
1543
|
+
print(f"\n ShellLite Server v0.04.4 is running!")
|
|
1538
1544
|
print(f" \u001b[1;36m➜\u001b[0m Local: \u001b[1;4;36mhttp://localhost:{port_val}/\u001b[0m\n")
|
|
1539
1545
|
try: server.serve_forever()
|
|
1540
1546
|
except KeyboardInterrupt:
|
|
@@ -165,7 +165,8 @@ class Lexer:
|
|
|
165
165
|
'while': 'WHILE', 'until': 'UNTIL',
|
|
166
166
|
'repeat': 'REPEAT', 'forever': 'FOREVER',
|
|
167
167
|
'stop': 'STOP', 'skip': 'SKIP', 'exit': 'EXIT',
|
|
168
|
-
'each': '
|
|
168
|
+
'each': 'EACH',
|
|
169
|
+
'check': 'CHECK',
|
|
169
170
|
'unless': 'UNLESS', 'when': 'WHEN', 'otherwise': 'OTHERWISE',
|
|
170
171
|
'then': 'THEN', 'do': 'DO',
|
|
171
172
|
'print': 'PRINT', 'say': 'SAY', 'show': 'SAY',
|
|
@@ -5,9 +5,9 @@ import urllib.request
|
|
|
5
5
|
import zipfile
|
|
6
6
|
import io
|
|
7
7
|
import subprocess
|
|
8
|
-
from .
|
|
9
|
-
from .
|
|
10
|
-
from .
|
|
8
|
+
from .lexer import Lexer
|
|
9
|
+
from .parser import Parser
|
|
10
|
+
from .interpreter import Interpreter
|
|
11
11
|
from .ast_nodes import *
|
|
12
12
|
import json
|
|
13
13
|
def execute_source(source: str, interpreter: Interpreter):
|
|
@@ -72,7 +72,7 @@ def run_repl():
|
|
|
72
72
|
print("\n" + "="*40)
|
|
73
73
|
print(" ShellLite REPL - English Syntax")
|
|
74
74
|
print("="*40)
|
|
75
|
-
print("Version: v0.04.
|
|
75
|
+
print("Version: v0.04.4 | Made by Shrey Naithani")
|
|
76
76
|
print("Commands: Type 'exit' to quit, 'help' for examples.")
|
|
77
77
|
print("Note: Terminal commands (like 'shl install') must be run in CMD/PowerShell, not here.")
|
|
78
78
|
|
|
@@ -203,7 +203,7 @@ def install_globally():
|
|
|
203
203
|
ps_cmd = f'$oldPath = [Environment]::GetEnvironmentVariable("Path", "User"); if ($oldPath -notlike "*ShellLite*") {{ [Environment]::SetEnvironmentVariable("Path", "$oldPath;{install_dir}", "User") }}'
|
|
204
204
|
subprocess.run(["powershell", "-Command", ps_cmd], capture_output=True)
|
|
205
205
|
|
|
206
|
-
print(f"\n[SUCCESS] ShellLite (v0.04.
|
|
206
|
+
print(f"\n[SUCCESS] ShellLite (v0.04.4) is installed!")
|
|
207
207
|
print(f"Location: {install_dir}")
|
|
208
208
|
print("\nIMPORTANT STEP REQUIRED:")
|
|
209
209
|
print("1. Close ALL open terminal windows (CMD, PowerShell, VS Code).")
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from typing import List, Optional
|
|
2
|
-
from .
|
|
2
|
+
from .lexer import Token, Lexer
|
|
3
3
|
from .ast_nodes import *
|
|
4
4
|
import re
|
|
5
5
|
class Parser:
|
|
@@ -84,6 +84,16 @@ class Parser:
|
|
|
84
84
|
input_token = self.consume()
|
|
85
85
|
return self.parse_id_start_statement(passed_name_token=input_token)
|
|
86
86
|
return self.parse_expression_stmt()
|
|
87
|
+
elif self.check('BUTTON'):
|
|
88
|
+
return self.parse_id_start_statement(passed_name_token=self.consume('BUTTON'))
|
|
89
|
+
elif self.check('COLUMN'):
|
|
90
|
+
return self.parse_id_start_statement(passed_name_token=self.consume('COLUMN'))
|
|
91
|
+
elif self.check('ROW'):
|
|
92
|
+
return self.parse_id_start_statement(passed_name_token=self.consume('ROW'))
|
|
93
|
+
elif self.check('IMAGE'):
|
|
94
|
+
return self.parse_id_start_statement(passed_name_token=self.consume('IMAGE'))
|
|
95
|
+
elif self.check('SIZE'):
|
|
96
|
+
return self.parse_id_start_statement(passed_name_token=self.consume('SIZE'))
|
|
87
97
|
elif self.check('ID'):
|
|
88
98
|
return self.parse_id_start_statement()
|
|
89
99
|
elif self.check('SPAWN'):
|
|
@@ -173,6 +183,9 @@ class Parser:
|
|
|
173
183
|
# Standalone ask statement? e.g. ask "Questions?"
|
|
174
184
|
# Or ask is expression. If statement, maybe just expression statement.
|
|
175
185
|
return self.parse_expression_statement()
|
|
186
|
+
elif self.check('CHECK'):
|
|
187
|
+
self.consume('CHECK')
|
|
188
|
+
return self.parse_if()
|
|
176
189
|
elif self.check('SET'):
|
|
177
190
|
return self.parse_set()
|
|
178
191
|
else:
|
|
@@ -940,8 +953,8 @@ class Parser:
|
|
|
940
953
|
return node
|
|
941
954
|
def parse_start_server(self) -> Node:
|
|
942
955
|
token = self.consume('START')
|
|
943
|
-
if self.check('SERVER'):
|
|
944
|
-
self.consume(
|
|
956
|
+
if self.check('SERVER') or self.check('WEBSITE') or (self.check('ID') and self.peek().value == 'website'):
|
|
957
|
+
self.consume()
|
|
945
958
|
port = Number(8080)
|
|
946
959
|
if self.check('ON'):
|
|
947
960
|
self.consume('ON')
|
|
@@ -1667,6 +1680,7 @@ class Parser:
|
|
|
1667
1680
|
node.line = start_token.line
|
|
1668
1681
|
return node
|
|
1669
1682
|
start_token = self.consume('FOR')
|
|
1683
|
+
if self.check('EACH'): self.consume('EACH')
|
|
1670
1684
|
if self.check('ID') and self.peek(1).type == 'IN':
|
|
1671
1685
|
var_name = self.consume('ID').value
|
|
1672
1686
|
self.consume('IN')
|
|
@@ -5,20 +5,10 @@ shell_lite/__init__.py
|
|
|
5
5
|
shell_lite/ast_nodes.py
|
|
6
6
|
shell_lite/cli.py
|
|
7
7
|
shell_lite/compiler.py
|
|
8
|
-
shell_lite/fix_nulls.py
|
|
9
|
-
shell_lite/formatter.py
|
|
10
8
|
shell_lite/interpreter.py
|
|
11
|
-
shell_lite/interpreter_backup.py
|
|
12
|
-
shell_lite/interpreter_final.py
|
|
13
|
-
shell_lite/interpreter_new.py
|
|
14
|
-
shell_lite/js_compiler.py
|
|
15
9
|
shell_lite/lexer.py
|
|
16
|
-
shell_lite/lexer_new.py
|
|
17
10
|
shell_lite/main.py
|
|
18
|
-
shell_lite/minimal_interpreter.py
|
|
19
11
|
shell_lite/parser.py
|
|
20
|
-
shell_lite/parser_new.py
|
|
21
|
-
shell_lite/patch_parser.py
|
|
22
12
|
shell_lite/runtime.py
|
|
23
13
|
shell_lite.egg-info/PKG-INFO
|
|
24
14
|
shell_lite.egg-info/SOURCES.txt
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import sys
|
|
3
|
-
import glob
|
|
4
|
-
import os
|
|
5
|
-
|
|
6
|
-
files = [
|
|
7
|
-
r'c:\Users\shrey\OneDrive\Desktop\oka\shell-lite\shell_lite\parser.py',
|
|
8
|
-
r'c:\Users\shrey\OneDrive\Desktop\oka\shell-lite\shell_lite\lexer.py',
|
|
9
|
-
r'c:\Users\shrey\OneDrive\Desktop\oka\shell-lite\shell_lite\interpreter.py',
|
|
10
|
-
r'c:\Users\shrey\OneDrive\Desktop\oka\shell-lite\shell_lite\main.py',
|
|
11
|
-
r'c:\Users\shrey\OneDrive\Desktop\oka\shell-lite\shell_lite\ast_nodes.py',
|
|
12
|
-
r'c:\Users\shrey\OneDrive\Desktop\oka\tests_suite\repro_issues.shl'
|
|
13
|
-
]
|
|
14
|
-
|
|
15
|
-
for path in files:
|
|
16
|
-
try:
|
|
17
|
-
with open(path, 'rb') as f:
|
|
18
|
-
content = f.read()
|
|
19
|
-
|
|
20
|
-
if b'\x00' in content:
|
|
21
|
-
print(f"Null bytes found in {path}! Fixing...")
|
|
22
|
-
new_content = content.replace(b'\x00', b'')
|
|
23
|
-
with open(path, 'wb') as f:
|
|
24
|
-
f.write(new_content)
|
|
25
|
-
print(f"Fixed {path}.")
|
|
26
|
-
else:
|
|
27
|
-
print(f"No null bytes in {path}.")
|
|
28
|
-
except Exception as e:
|
|
29
|
-
print(f"Error checking {path}: {e}")
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
from typing import List
|
|
2
|
-
from .lexer import Lexer, Token
|
|
3
|
-
class Formatter:
|
|
4
|
-
def __init__(self, source_code: str):
|
|
5
|
-
self.source_code = source_code
|
|
6
|
-
self.indent_size = 4
|
|
7
|
-
def format(self) -> str:
|
|
8
|
-
lexer = Lexer(self.source_code)
|
|
9
|
-
try:
|
|
10
|
-
tokens = lexer.tokenize()
|
|
11
|
-
except Exception:
|
|
12
|
-
raise
|
|
13
|
-
formatted_lines = []
|
|
14
|
-
current_indent = 0
|
|
15
|
-
current_line_tokens: List[Token] = []
|
|
16
|
-
def flush_line():
|
|
17
|
-
nonlocal current_line_tokens
|
|
18
|
-
if not current_line_tokens:
|
|
19
|
-
pass
|
|
20
|
-
line_str = self._format_line_tokens(current_line_tokens, current_indent)
|
|
21
|
-
formatted_lines.append(line_str)
|
|
22
|
-
current_line_tokens.clear()
|
|
23
|
-
for token in tokens:
|
|
24
|
-
if token.type == 'EOF':
|
|
25
|
-
if current_line_tokens:
|
|
26
|
-
flush_line()
|
|
27
|
-
break
|
|
28
|
-
elif token.type == 'INDENT':
|
|
29
|
-
current_indent += 1
|
|
30
|
-
elif token.type == 'DEDENT':
|
|
31
|
-
current_indent -= 1
|
|
32
|
-
if current_indent < 0: current_indent = 0
|
|
33
|
-
elif token.type == 'NEWLINE':
|
|
34
|
-
flush_line()
|
|
35
|
-
pass
|
|
36
|
-
else:
|
|
37
|
-
current_line_tokens.append(token)
|
|
38
|
-
return '\n'.join(formatted_lines)
|
|
39
|
-
def _format_line_tokens(self, tokens: List[Token], indent_level: int) -> str:
|
|
40
|
-
if not tokens:
|
|
41
|
-
return ''
|
|
42
|
-
line_parts = []
|
|
43
|
-
line_parts.append(' ' * (indent_level * self.indent_size))
|
|
44
|
-
for i, token in enumerate(tokens):
|
|
45
|
-
val = token.value
|
|
46
|
-
type = token.type
|
|
47
|
-
if type == 'STRING':
|
|
48
|
-
if '"' in val and "'" not in val:
|
|
49
|
-
val = f"'{val}'"
|
|
50
|
-
else:
|
|
51
|
-
val = val.replace('"', '\\"')
|
|
52
|
-
val = f'"{val}"'
|
|
53
|
-
elif type == 'REGEX':
|
|
54
|
-
val = f"/{val}/"
|
|
55
|
-
if i > 0:
|
|
56
|
-
prev = tokens[i-1]
|
|
57
|
-
need_space = True
|
|
58
|
-
if prev.type in ('LPAREN', 'LBRACKET', 'LBRACE', 'DOT', 'AT'):
|
|
59
|
-
need_space = False
|
|
60
|
-
if type in ('RPAREN', 'RBRACKET', 'RBRACE', 'DOT', 'COMMA', 'COLON'):
|
|
61
|
-
need_space = False
|
|
62
|
-
if type == 'LPAREN':
|
|
63
|
-
if prev.type == 'ID':
|
|
64
|
-
need_space = False
|
|
65
|
-
elif prev.type in ('RPAREN', 'RBRACKET', 'STRING'):
|
|
66
|
-
need_space = False
|
|
67
|
-
else:
|
|
68
|
-
pass
|
|
69
|
-
if type == 'LBRACKET':
|
|
70
|
-
if prev.type in ('ID', 'STRING', 'RPAREN', 'RBRACKET'):
|
|
71
|
-
need_space = False
|
|
72
|
-
if need_space:
|
|
73
|
-
line_parts.append(' ')
|
|
74
|
-
line_parts.append(val)
|
|
75
|
-
return "".join(line_parts).rstrip()
|