shell-lite 0.5.3__py3-none-any.whl → 0.5.3.2__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.
shell_lite/interpreter.py CHANGED
@@ -240,8 +240,10 @@ class Interpreter:
240
240
  for k, v in self.builtins.items():
241
241
  self.global_env.set(k, v)
242
242
  def _make_tag_fn(self, tag_name):
243
- def tag_fn(*args):
243
+ def tag_fn(*args, **kwargs):
244
244
  attrs = {}
245
+ # Add kwargs directly as attributes
246
+ attrs.update(kwargs)
245
247
  content = []
246
248
  for arg in args:
247
249
  if isinstance(arg, dict):
@@ -1502,7 +1504,7 @@ class Interpreter:
1502
1504
  self.wfile.write(str(e).encode())
1503
1505
  except: pass
1504
1506
  server = ReusableHTTPServer(('0.0.0.0', port_val), ShellLiteHandler)
1505
- print(f"\n ShellLite Server v0.5.3 is running!")
1507
+ print(f"\n ShellLite Server v0.5.3.2 is running!")
1506
1508
  print(f" \u001b[1;36m➜\u001b[0m Local: \u001b[1;4;36mhttp://localhost:{port_val}/\u001b[0m\n")
1507
1509
  try: server.serve_forever()
1508
1510
  except KeyboardInterrupt:
shell_lite/main.py CHANGED
@@ -17,7 +17,6 @@ def execute_source(source: str, interpreter: Interpreter):
17
17
  lexer = Lexer(source)
18
18
  tokens = lexer.tokenize()
19
19
  if os.environ.get('USE_LEGACY_PARSER') == '1':
20
- from .parser import Parser
21
20
  parser = Parser(tokens)
22
21
  else:
23
22
  from .parser_gbp import GeometricBindingParser
@@ -151,7 +150,7 @@ def install_globally():
151
150
  return
152
151
  ps_cmd = f'$oldPath = [Environment]::GetEnvironmentVariable("Path", "User"); if ($oldPath -notlike "*ShellLite*") {{ [Environment]::SetEnvironmentVariable("Path", "$oldPath;{install_dir}", "User") }}'
153
152
  subprocess.run(["powershell", "-Command", ps_cmd], capture_output=True)
154
- print(f"\n[SUCCESS] ShellLite (v0.5.3) is installed!")
153
+ print(f"\n[SUCCESS] ShellLite (v0.5.3.2) is installed!")
155
154
  print(f"Location: {install_dir}")
156
155
  print("\nIMPORTANT STEP REQUIRED:")
157
156
  print("1. Close ALL open terminal windows (CMD, PowerShell, VS Code).")
@@ -444,6 +443,12 @@ def main():
444
443
  print("Usage: shl llvm <filename>")
445
444
  elif cmd == "help" or cmd == "--help" or cmd == "-h":
446
445
  show_help()
446
+ elif cmd == "--version" or cmd == "-v":
447
+ try:
448
+ from importlib.metadata import version
449
+ print(f"ShellLite v{version('shell-lite')}")
450
+ except Exception:
451
+ print("ShellLite v0.5.3.1")
447
452
  elif cmd == "get":
448
453
  if len(sys.argv) > 2:
449
454
  package_name = sys.argv[2]
shell_lite/parser_gbp.py CHANGED
@@ -43,20 +43,24 @@ class GeometricBindingParser:
43
43
  node_stack: List[GeoNode] = [] # The active parents
44
44
  current_tokens_accumulator = []
45
45
  current_node: Optional[GeoNode] = None
46
+ last_line_node: Optional[GeoNode] = None # Track the last completed line's node
46
47
  block_stack: List[GeoNode] = []
47
48
  for token in self.tokens:
48
49
  if token.type == 'EOF':
49
50
  break
50
51
  if token.type == 'INDENT':
51
- if current_node:
52
- block_stack.append(current_node)
53
- current_node = None # We are stepping "inside", so no current line active node yet
52
+ # Use last_line_node as parent if current_node is None (NEWLINE came before INDENT)
53
+ parent_to_push = current_node if current_node else last_line_node
54
+ if parent_to_push:
55
+ block_stack.append(parent_to_push)
56
+ current_node = None
54
57
  continue
55
58
  if token.type == 'DEDENT':
56
59
  if block_stack:
57
60
  block_stack.pop()
58
61
  continue
59
62
  if token.type == 'NEWLINE':
63
+ last_line_node = current_node # Save before resetting
60
64
  current_node = None
61
65
  continue
62
66
  if current_node is None:
@@ -83,7 +87,17 @@ class GeometricBindingParser:
83
87
  return self.bind_while(node)
84
88
  elif head_type == 'FOR' or head_type == 'LOOP':
85
89
  return self.bind_for(node)
86
- elif head_type == 'FUNCTION' or head_type == 'TO' or (head_type == 'DEFINE' and self.peek_type(node, 1) == 'FUNCTION'):
90
+ elif head_type == 'USE':
91
+ return self.bind_use(node)
92
+ elif head_type == 'SERVE':
93
+ return self.bind_serve(node)
94
+ elif head_type == 'DEFINE':
95
+ return self.bind_define(node)
96
+ elif head_type == 'WHEN':
97
+ return self.bind_when(node)
98
+ elif head_type == 'ON':
99
+ return self.bind_on(node)
100
+ elif head_type == 'FUNCTION' or head_type == 'TO':
87
101
  return self.bind_func(node)
88
102
  elif head_type == 'PRINT' or head_type == 'SAY':
89
103
  return self.bind_print(node)
@@ -96,11 +110,13 @@ class GeometricBindingParser:
96
110
  elif head_type == 'LISTEN':
97
111
  return self.bind_listen(node)
98
112
  elif head_type == 'ID':
99
- if any(t.type == 'ASSIGN' for t in node.tokens):
113
+ # Assignment: ID ASSIGN ... (second token must be ASSIGN)
114
+ # Function call with kwargs: ID ID ASSIGN ... (ASSIGN comes later)
115
+ if len(node.tokens) >= 2 and node.tokens[1].type == 'ASSIGN':
100
116
  return self.bind_assignment(node)
101
- return self.bind_expression_stmt(node)
117
+ return self.bind_call_or_expr(node)
102
118
  else:
103
- return self.bind_expression_stmt(node)
119
+ return self.bind_call_or_expr(node)
104
120
  def peek_type(self, node: GeoNode, offset: int) -> str:
105
121
  if offset < len(node.tokens):
106
122
  return node.tokens[offset].type
@@ -159,12 +175,119 @@ class GeometricBindingParser:
159
175
  if node.tokens[0].type == 'DEFINE': start = 2
160
176
  name = node.tokens[start].value
161
177
  args = []
178
+ # Look for 'using' keyword (which is tokenized as ID)
179
+ collecting_args = False
162
180
  for t in node.tokens[start+1:]:
163
- if t.type == 'ID':
164
- args.append((t.value, None, None))
165
- elif t.type == 'COLON': break # End of signature
181
+ if t.type == 'USING':
182
+ collecting_args = True
183
+ continue
184
+ if t.type == 'ID' and collecting_args:
185
+ args.append((t.value, None, None))
186
+ elif t.type == 'COLON': break
187
+ elif t.type == 'COMMA': continue
188
+ body = [self.bind_node(child) for child in node.children]
189
+ return FunctionDef(name, args, body)
190
+ def bind_use(self, node: GeoNode) -> Import:
191
+ # 'use "filename.shl"'
192
+ for t in node.tokens:
193
+ if t.type == 'STRING':
194
+ return Import(t.value)
195
+ return Import(node.tokens[1].value if len(node.tokens) > 1 else '')
196
+ def bind_serve(self, node: GeoNode) -> ServeStatic:
197
+ # 'serve files from "public" at "/static"'
198
+ folder = String('public')
199
+ url = String('/static')
200
+ tokens = node.tokens
201
+ for i, t in enumerate(tokens):
202
+ if t.type == 'FROM' and i+1 < len(tokens):
203
+ folder = self.parse_expr_iterative([tokens[i+1]])
204
+ if t.type == 'AT' and i+1 < len(tokens):
205
+ url = self.parse_expr_iterative([tokens[i+1]])
206
+ return ServeStatic(folder, url)
207
+ def bind_define(self, node: GeoNode) -> FunctionDef:
208
+ # 'define page Name using arg1, arg2'
209
+ tokens = node.tokens
210
+ name = ''
211
+ args = []
212
+ i = 1
213
+ # Skip 'page' or 'component' if present
214
+ if i < len(tokens) and tokens[i].type == 'PAGE':
215
+ i += 1
216
+ if i < len(tokens) and tokens[i].type == 'ID':
217
+ name = tokens[i].value
218
+ i += 1
219
+ # Parse 'using' args
220
+ if i < len(tokens) and tokens[i].type == 'USING':
221
+ i += 1
222
+ while i < len(tokens):
223
+ if tokens[i].type == 'ID':
224
+ args.append((tokens[i].value, None, None))
225
+ elif tokens[i].type == 'COMMA':
226
+ pass
227
+ else:
228
+ break
229
+ i += 1
166
230
  body = [self.bind_node(child) for child in node.children]
167
231
  return FunctionDef(name, args, body)
232
+ def bind_when(self, node: GeoNode) -> OnRequest:
233
+ # 'when someone visits "/path"'
234
+ tokens = node.tokens
235
+ path = String('/')
236
+ for i, t in enumerate(tokens):
237
+ if t.type == 'STRING':
238
+ path = String(t.value)
239
+ break
240
+ body = [self.bind_node(child) for child in node.children]
241
+ return OnRequest(path, body)
242
+ def bind_on(self, node: GeoNode) -> OnRequest:
243
+ # 'on request to "/path"'
244
+ tokens = node.tokens
245
+ path = String('/')
246
+ for t in tokens:
247
+ if t.type == 'STRING':
248
+ path = String(t.value)
249
+ break
250
+ body = [self.bind_node(child) for child in node.children]
251
+ return OnRequest(path, body)
252
+ def bind_call_or_expr(self, node: GeoNode) -> Any:
253
+ # Handle function calls like 'Head "title"' or 'Navbar'
254
+ tokens = node.tokens
255
+ if len(tokens) >= 1 and tokens[0].type == 'ID':
256
+ name = tokens[0].value
257
+ args = []
258
+ kwargs = []
259
+ # Parse remaining tokens as arguments, handling key=value for HTML attributes
260
+ i = 1
261
+ while i < len(tokens):
262
+ t = tokens[i]
263
+ # Check for key=value pattern (e.g. class="container", style="...", href="...")
264
+ # HTML attributes may be tokenized as various types: ID, STRUCTURE, HREF, REL, NAME, etc.
265
+ is_attr_key = t.type in ('ID', 'STRUCTURE', 'HREF', 'REL', 'NAME', 'STYLE', 'CONTENT', 'CHARSET', 'SRC', 'ALT', 'TYPE', 'VALUE', 'PLACEHOLDER', 'METHOD', 'ACTION')
266
+ is_kwarg = (is_attr_key and i + 2 < len(tokens) and tokens[i + 1].type == 'ASSIGN')
267
+ if is_kwarg:
268
+ key = t.value
269
+ val_token = tokens[i + 2]
270
+ if val_token.type == 'STRING':
271
+ kwargs.append((key, String(val_token.value)))
272
+ elif val_token.type == 'NUMBER':
273
+ kwargs.append((key, Number(int(val_token.value) if '.' not in val_token.value else float(val_token.value))))
274
+ else:
275
+ kwargs.append((key, VarAccess(val_token.value)))
276
+ i += 3
277
+ continue
278
+ elif t.type == 'STRING':
279
+ args.append(String(t.value))
280
+ elif t.type == 'NUMBER':
281
+ args.append(Number(int(t.value) if '.' not in t.value else float(t.value)))
282
+ elif t.type == 'ID':
283
+ args.append(VarAccess(t.value))
284
+ i += 1
285
+ # Check for children (indented body)
286
+ body = None
287
+ if node.children:
288
+ body = [self.bind_node(child) for child in node.children]
289
+ return Call(name, args, kwargs=kwargs, body=body)
290
+ return self.parse_expr_iterative(tokens)
168
291
  def _extract_expr_tokens(self, tokens: List[Token], start: int = 0) -> List[Token]:
169
292
  end = len(tokens)
170
293
  if tokens[-1].type == 'COLON':
@@ -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.2
4
4
  Summary: A lightweight, English-like scripting language.
5
5
  Home-page: https://github.com/Shrey-N/ShellDesk
6
6
  Author: Shrey Naithani
@@ -0,0 +1,17 @@
1
+ shell_lite/__init__.py,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
2
+ shell_lite/ast_nodes.py,sha256=W2oefXuRjqnQybR5ZcdPU0qC5gxHZHcotQc3LAVDLM0,6129
3
+ shell_lite/cli.py,sha256=14Kq1ohSXS3p-xdh0DPi7eXskUtSX81huSyGhktoOMA,250
4
+ shell_lite/compiler.py,sha256=t2Imae9h03v3GIIKrCo16qCDDLKSxrpjrp83tv0SzUQ,24982
5
+ shell_lite/interpreter.py,sha256=zQE7NopelZeHYT94ZbZYGTBSd_ZgaOCWNU86ugUwYuw,75964
6
+ shell_lite/js_compiler.py,sha256=yEGIkkIvHGU7o1htHEqlQr6BE0wL35PtL5PssNld9fc,5606
7
+ shell_lite/lexer.py,sha256=cNLk_N59a7eKQaQp7Mqcnxy1um64-QgtDEi2eAsAWKE,14913
8
+ shell_lite/main.py,sha256=Vg-BUReR3JsK-sdcwFYUIx5vy8AkSLmqfsOQRWAVFdU,20150
9
+ shell_lite/parser.py,sha256=qsR2wQUWjUPXbXgnmv8pmOgfX99lYYH6tpxKH3PEnfQ,88471
10
+ shell_lite/parser_gbp.py,sha256=IV5lD1IipDOqgoC6UdVpFnuWQBb73WmEAYMigDGTfcQ,16555
11
+ shell_lite/runtime.py,sha256=pSjBeA1dTQ-a94q3FLdv9lqZurdd6MJmfhFGHhOoQEM,16057
12
+ shell_lite-0.5.3.2.dist-info/LICENSE,sha256=LlK8rVgwqMiti6NfaXa8xfvXAwfYe5SVrvcz3YpwHgg,37277
13
+ shell_lite-0.5.3.2.dist-info/METADATA,sha256=ReF60tgHn2PTAYXb-W2lKM3B8F25iq-l8SukauYzKrc,10586
14
+ shell_lite-0.5.3.2.dist-info/WHEEL,sha256=hPN0AlP2dZM_3ZJZWP4WooepkmU9wzjGgCLCeFjkHLA,92
15
+ shell_lite-0.5.3.2.dist-info/entry_points.txt,sha256=tglL8tjyPIh1W85j6zFpNZjMpQe_xC-k-7BOhHLWfxc,45
16
+ shell_lite-0.5.3.2.dist-info/top_level.txt,sha256=hIln5ltrok_Mn3ijlQeqMFF6hHBHCyhzqCO7KL358cg,11
17
+ shell_lite-0.5.3.2.dist-info/RECORD,,
File without changes
@@ -1,39 +0,0 @@
1
- import llvmlite.binding as llvm
2
- from .codegen import LLVMCompiler
3
- from ..lexer import Lexer
4
- from ..parser import Parser
5
- import os
6
- def build_llvm(filename: str):
7
- print(f"Compiling {filename} with LLVM Backend...")
8
- with open(filename, 'r', encoding='utf-8') as f:
9
- source = f.read()
10
- lexer = Lexer(source)
11
- tokens = lexer.tokenize()
12
- parser = Parser(tokens)
13
- statements = parser.parse()
14
- compiler = LLVMCompiler()
15
- module = compiler.compile(statements)
16
- llvm_ir = str(module)
17
- print("\n--- Generated LLVM IR ---")
18
- print(llvm_ir)
19
- print("-------------------------\n")
20
- ll_filename = os.path.splitext(filename)[0] + ".ll"
21
- with open(ll_filename, 'w') as f:
22
- f.write(llvm_ir)
23
- print(f"[SUCCESS] Generated LLVM IR: {ll_filename}")
24
- print("\nTo compile to executable, you can use Clang:")
25
- print(f" clang {ll_filename} -o {os.path.splitext(filename)[0]}.exe")
26
- """
27
- try:
28
- print("Initializing LLVM...")
29
- llvm.initialize()
30
- llvm.initialize_native_target()
31
- llvm.initialize_native_asmprinter()
32
- print("LLVM Initialized.")
33
- print("Creating Target...")
34
- target = llvm.Target.from_default_triple()
35
- print(f"Target Triple: {target}")
36
- target_machine = target.create_target_machine()
37
- except Exception as e:
38
- print(f"Native binding skipped due to: {e}")
39
- """
@@ -1,311 +0,0 @@
1
- from llvmlite import ir
2
- from ..ast_nodes import *
3
- class LLVMCompiler:
4
- def __init__(self):
5
- self.module = ir.Module(name="shell_lite_module")
6
- self.module.triple = "x86_64-pc-windows-msvc" # Assume Windows for now based on user OS
7
- self.int32 = ir.IntType(32)
8
- self.char_ptr = ir.IntType(8).as_pointer()
9
- voidptr_ty = ir.IntType(8).as_pointer()
10
- printf_ty = ir.FunctionType(self.int32, [voidptr_ty], var_arg=True)
11
- self.printf = ir.Function(self.module, printf_ty, name="printf")
12
- malloc_ty = ir.FunctionType(voidptr_ty, [self.int32])
13
- self.malloc = ir.Function(self.module, malloc_ty, name="malloc")
14
- free_ty = ir.FunctionType(ir.VoidType(), [voidptr_ty])
15
- self.free = ir.Function(self.module, free_ty, name="free")
16
- strlen_ty = ir.FunctionType(self.int32, [voidptr_ty])
17
- self.strlen = ir.Function(self.module, strlen_ty, name="strlen")
18
- strcpy_ty = ir.FunctionType(voidptr_ty, [voidptr_ty, voidptr_ty])
19
- self.strcpy = ir.Function(self.module, strcpy_ty, name="strcpy")
20
- strcat_ty = ir.FunctionType(voidptr_ty, [voidptr_ty, voidptr_ty])
21
- self.strcat = ir.Function(self.module, strcat_ty, name="strcat")
22
- fopen_ty = ir.FunctionType(voidptr_ty, [voidptr_ty, voidptr_ty])
23
- self.fopen = ir.Function(self.module, fopen_ty, name="fopen")
24
- fclose_ty = ir.FunctionType(self.int32, [voidptr_ty])
25
- self.fclose = ir.Function(self.module, fclose_ty, name="fclose")
26
- fwrite_ty = ir.FunctionType(self.int32, [voidptr_ty, self.int32, self.int32, voidptr_ty])
27
- self.fwrite = ir.Function(self.module, fwrite_ty, name="fwrite")
28
- fread_ty = ir.FunctionType(self.int32, [voidptr_ty, self.int32, self.int32, voidptr_ty])
29
- self.fread = ir.Function(self.module, fread_ty, name="fread")
30
- fgets_ty = ir.FunctionType(voidptr_ty, [voidptr_ty, self.int32, voidptr_ty])
31
- self.fgets = ir.Function(self.module, fgets_ty, name="fgets")
32
- fseek_ty = ir.FunctionType(self.int32, [voidptr_ty, self.int32, self.int32])
33
- self.fseek = ir.Function(self.module, fseek_ty, name="fseek")
34
- ftell_ty = ir.FunctionType(self.int32, [voidptr_ty])
35
- self.ftell = ir.Function(self.module, ftell_ty, name="ftell")
36
- rewind_ty = ir.FunctionType(ir.VoidType(), [voidptr_ty])
37
- self.rewind = ir.Function(self.module, rewind_ty, name="rewind")
38
- get_stdin_ty = ir.FunctionType(voidptr_ty, [self.int32])
39
- self.get_stdin = ir.Function(self.module, get_stdin_ty, name="__acrt_iob_func")
40
- system_ty = ir.FunctionType(self.int32, [voidptr_ty])
41
- self.system = ir.Function(self.module, system_ty, name="system")
42
- func_type = ir.FunctionType(self.int32, [], var_arg=False)
43
- self.main_func = ir.Function(self.module, func_type, name="main")
44
- block = self.main_func.append_basic_block(name="entry")
45
- self.builder = ir.IRBuilder(block)
46
- self.scopes = [{}]
47
- self.loop_stack = []
48
- self.str_constants = {}
49
- def _get_scope(self):
50
- return self.scopes[-1]
51
- def _alloca(self, name, typ=None):
52
- if typ is None: typ = self.int32
53
- with self.builder.goto_entry_block():
54
- ptr = self.builder.alloca(typ, size=None, name=name)
55
- return ptr
56
- def compile(self, statements):
57
- for stmt in statements:
58
- self.visit(stmt)
59
- self.builder.ret(ir.Constant(self.int32, 0))
60
- return self.module
61
- def visit(self, node):
62
- method_name = f'visit_{type(node).__name__}'
63
- visitor = getattr(self, method_name, self.generic_visit)
64
- return visitor(node)
65
- def generic_visit(self, node):
66
- print(f"Warning: LLVM Backend does not support {type(node).__name__} yet.")
67
- return None
68
- def visit_Number(self, node: Number):
69
- return ir.Constant(self.int32, int(node.value))
70
- def visit_String(self, node: String):
71
- return self._get_string_constant(node.value)
72
- def visit_BinOp(self, node: BinOp):
73
- left = self.visit(node.left)
74
- right = self.visit(node.right)
75
- op = node.op
76
- if op == '+':
77
- is_str_op = False
78
- if left.type == self.char_ptr or right.type == self.char_ptr:
79
- is_str_op = True
80
- if is_str_op:
81
- if left.type == self.int32:
82
- left = self.builder.inttoptr(left, self.char_ptr, name="cast_l")
83
- if right.type == self.int32:
84
- right = self.builder.inttoptr(right, self.char_ptr, name="cast_r")
85
- if is_str_op:
86
- len1 = self.builder.call(self.strlen, [left], name="len1")
87
- len2 = self.builder.call(self.strlen, [right], name="len2")
88
- total_len = self.builder.add(len1, len2, name="total_len")
89
- total_len_null = self.builder.add(total_len, ir.Constant(self.int32, 1), name="alloc_len")
90
- new_str = self.builder.call(self.malloc, [total_len_null], name="new_str")
91
- self.builder.call(self.strcpy, [new_str, left])
92
- self.builder.call(self.strcat, [new_str, right])
93
- return new_str
94
- return self.builder.add(left, right, name="addtmp")
95
- elif op == '-':
96
- return self.builder.sub(left, right, name="subtmp")
97
- elif op == '*':
98
- return self.builder.mul(left, right, name="multmp")
99
- elif op == '/':
100
- return self.builder.sdiv(left, right, name="divtmp")
101
- elif op == '==' or op == 'is':
102
- return self.builder.icmp_signed('==', left, right, name="eqtmp")
103
- elif op == '!=' or op == 'is not':
104
- return self.builder.icmp_signed('!=', left, right, name="netmp")
105
- elif op == '<':
106
- return self.builder.icmp_signed('<', left, right, name="lttmp")
107
- elif op == '<=':
108
- return self.builder.icmp_signed('<=', left, right, name="letmp")
109
- elif op == '>':
110
- return self.builder.icmp_signed('>', left, right, name="gttmp")
111
- elif op == '>=':
112
- return self.builder.icmp_signed('>=', left, right, name="getmp")
113
- else:
114
- raise Exception(f"Unknown operator: {op}")
115
- def visit_If(self, node: If):
116
- cond_val = self.visit(node.condition)
117
- if cond_val.type != ir.IntType(1):
118
- cond_val = self.builder.icmp_signed('!=', cond_val, ir.Constant(self.int32, 0), name="ifcond")
119
- then_bb = self.builder.append_basic_block(name="then")
120
- else_bb = self.builder.append_basic_block(name="else")
121
- merge_bb = self.builder.append_basic_block(name="ifcont")
122
- self.builder.cbranch(cond_val, then_bb, else_bb)
123
- self.builder.position_at_end(then_bb)
124
- for stmt in node.body:
125
- self.visit(stmt)
126
- if not self.builder.block.is_terminated:
127
- self.builder.branch(merge_bb)
128
- self.builder.position_at_end(else_bb)
129
- if node.else_body:
130
- for stmt in node.else_body:
131
- self.visit(stmt)
132
- if not self.builder.block.is_terminated:
133
- self.builder.branch(merge_bb)
134
- self.builder.position_at_end(merge_bb)
135
- def visit_While(self, node: While):
136
- cond_bb = self.builder.append_basic_block(name="loop.cond")
137
- body_bb = self.builder.append_basic_block(name="loop.body")
138
- after_bb = self.builder.append_basic_block(name="loop.after")
139
- self.loop_stack.append((cond_bb, after_bb))
140
- self.builder.branch(cond_bb)
141
- self.builder.position_at_end(cond_bb)
142
- cond_val = self.visit(node.condition)
143
- if cond_val.type != ir.IntType(1):
144
- cond_val = self.builder.icmp_signed('!=', cond_val, ir.Constant(self.int32, 0), name="loopcond")
145
- self.builder.cbranch(cond_val, body_bb, after_bb)
146
- self.builder.position_at_end(body_bb)
147
- for stmt in node.body:
148
- self.visit(stmt)
149
- self.builder.branch(cond_bb) # Loop back
150
- self.builder.position_at_end(after_bb)
151
- self.loop_stack.pop()
152
- def visit_Repeat(self, node: Repeat):
153
- count_val = self.visit(node.count)
154
- import random
155
- uid = random.randint(0, 10000)
156
- i_ptr = self._alloca(f"_loop_i_{uid}")
157
- self.builder.store(ir.Constant(self.int32, 0), i_ptr)
158
- cond_bb = self.builder.append_basic_block(name="repeat.cond")
159
- body_bb = self.builder.append_basic_block(name="repeat.body")
160
- after_bb = self.builder.append_basic_block(name="repeat.after")
161
- self.loop_stack.append((cond_bb, after_bb))
162
- self.builder.branch(cond_bb)
163
- self.builder.position_at_end(cond_bb)
164
- curr_i = self.builder.load(i_ptr, name="i_load")
165
- cmp = self.builder.icmp_signed('<', curr_i, count_val, name="loopcheck")
166
- self.builder.cbranch(cmp, body_bb, after_bb)
167
- self.builder.position_at_end(body_bb)
168
- for stmt in node.body:
169
- self.visit(stmt)
170
- curr_i_Body = self.builder.load(i_ptr)
171
- next_i = self.builder.add(curr_i_Body, ir.Constant(self.int32, 1), name="inc_i")
172
- self.builder.store(next_i, i_ptr)
173
- self.builder.branch(cond_bb)
174
- self.builder.position_at_end(after_bb)
175
- self.loop_stack.pop()
176
- def visit_FunctionDef(self, node: FunctionDef):
177
- arg_types = [self.int32] * len(node.args)
178
- arg_types = []
179
- for arg in node.args:
180
- name, _, hint = arg # arg is tuple
181
- if True: # FORCE ALL ARGS TO STRINGS FOR SHELL LITE (Phase 7 Fix)
182
- arg_types.append(self.char_ptr)
183
- else:
184
- arg_types.append(self.int32)
185
- func_ty = ir.FunctionType(self.int32, arg_types) # Return int32 (or pointer casted)
186
- func = ir.Function(self.module, func_ty, name=node.name)
187
- old_builder = self.builder
188
- block = func.append_basic_block(name="entry")
189
- self.builder = ir.IRBuilder(block)
190
- self.scopes.append({}) # New scope
191
- for i, arg in enumerate(func.args):
192
- arg_name = node.args[i][0]
193
- arg.name = arg_name
194
- ptr = self.builder.alloca(arg.type, name=arg_name)
195
- self.builder.store(arg, ptr)
196
- self.scopes[-1][arg_name] = ptr
197
- for stmt in node.body:
198
- self.visit(stmt)
199
- if not self.builder.block.is_terminated:
200
- self.builder.ret(ir.Constant(self.int32, 0))
201
- self.scopes.pop()
202
- self.builder = old_builder
203
- def visit_Return(self, node: Return):
204
- val = self.visit(node.value)
205
- if val.type == self.char_ptr:
206
- val = self.builder.ptrtoint(val, self.int32)
207
- self.builder.ret(val)
208
- def visit_Call(self, node: Call):
209
- if node.name in self.module.globals:
210
- func = self.module.globals[node.name]
211
- elif node.name == 'read':
212
- if len(node.args) > 0:
213
- return self.visit_FileRead(FileRead(node.args[0]))
214
- else:
215
- return ir.Constant(self.int32, 0)
216
- else:
217
- print(f"Warning: Function {node.name} not found")
218
- return ir.Constant(self.int32, 0)
219
- args = [self.visit(a) for a in node.args]
220
- return self.builder.call(func, args, name="calltmp")
221
- def visit_Assign(self, node: Assign):
222
- value = self.visit(node.value)
223
- scope = self._get_scope()
224
- if node.name not in scope:
225
- ptr = self._alloca(node.name, typ=value.type)
226
- scope[node.name] = ptr
227
- else:
228
- ptr = scope[node.name]
229
- self.builder.store(value, ptr)
230
- return value
231
- def visit_Execute(self, node: Execute):
232
- cmd = self.visit(node.code)
233
- self.builder.call(self.system, [cmd])
234
- return ir.Constant(self.int32, 0)
235
- def visit_Stop(self, node: Stop):
236
- if not self.loop_stack:
237
- print("Error: stop used outside of loop")
238
- return
239
- after_bb = self.loop_stack[-1][1]
240
- self.builder.branch(after_bb)
241
- dead_bb = self.builder.append_basic_block(name="dead")
242
- self.builder.position_at_end(dead_bb)
243
- def visit_Skip(self, node: Skip):
244
- if not self.loop_stack:
245
- print("Error: skip used outside of loop")
246
- return
247
- cond_bb = self.loop_stack[-1][0]
248
- self.builder.branch(cond_bb)
249
- dead_bb = self.builder.append_basic_block(name="dead")
250
- self.builder.position_at_end(dead_bb)
251
- def _get_stdin_handle(self):
252
- return self.builder.call(self.get_stdin, [ir.Constant(self.int32, 0)])
253
- def visit_Input(self, node: Input):
254
- buffer_len = ir.Constant(self.int32, 256)
255
- buffer = self.builder.call(self.malloc, [buffer_len], name="input_buf")
256
- stdin = self._get_stdin_handle()
257
- self.builder.call(self.fgets, [buffer, buffer_len, stdin])
258
- return buffer
259
- def visit_FileWrite(self, node: FileWrite):
260
- path = self.visit(node.path)
261
- content = self.visit(node.content)
262
- mode = self._get_string_constant("w")
263
- fp = self.builder.call(self.fopen, [path, mode], name="fp")
264
- length = self.builder.call(self.strlen, [content])
265
- self.builder.call(self.fwrite, [content, ir.Constant(self.int32, 1), length, fp])
266
- self.builder.call(self.fclose, [fp])
267
- return ir.Constant(self.int32, 0)
268
- def visit_FileRead(self, node: FileRead):
269
- path = self.visit(node.path)
270
- mode = self._get_string_constant("rb") # Binary to avoid text translation issues? Or "r"
271
- fp = self.builder.call(self.fopen, [path, mode], name="fp")
272
- self.builder.call(self.fseek, [fp, ir.Constant(self.int32, 0), ir.Constant(self.int32, 2)])
273
- size = self.builder.call(self.ftell, [fp], name="fsize")
274
- self.builder.call(self.rewind, [fp])
275
- alloc_size = self.builder.add(size, ir.Constant(self.int32, 1))
276
- buffer = self.builder.call(self.malloc, [alloc_size], name="fbuf")
277
- self.builder.call(self.fread, [buffer, ir.Constant(self.int32, 1), size, fp])
278
- null_term_ptr = self.builder.gep(buffer, [size])
279
- self.builder.store(ir.Constant(ir.IntType(8), 0), null_term_ptr)
280
- self.builder.call(self.fclose, [fp])
281
- return buffer
282
- def visit_VarAccess(self, node: VarAccess):
283
- scope = self._get_scope()
284
- if node.name in scope:
285
- ptr = scope[node.name]
286
- return self.builder.load(ptr, name=node.name)
287
- else:
288
- raise Exception(f"Variable '{node.name}' not defined")
289
- def _get_string_constant(self, text):
290
- text += '\0'
291
- if text in self.str_constants:
292
- return self.str_constants[text]
293
- byte_arr = bytearray(text.encode("utf8"))
294
- c_str_ty = ir.ArrayType(ir.IntType(8), len(byte_arr))
295
- global_var = ir.GlobalVariable(self.module, c_str_ty, name=f".str_{len(self.str_constants)}")
296
- global_var.linkage = 'internal'
297
- global_var.global_constant = True
298
- global_var.initializer = ir.Constant(c_str_ty, byte_arr)
299
- ptr = self.builder.bitcast(global_var, self.char_ptr)
300
- self.str_constants[text] = ptr
301
- return ptr
302
- def visit_Print(self, node: Print):
303
- value = self.visit(node.expression)
304
- if value.type == self.char_ptr:
305
- fmt_str = self._get_string_constant("%s\n")
306
- self.builder.call(self.printf, [fmt_str, value])
307
- else:
308
- if value.type != self.int32:
309
- pass
310
- fmt_str = self._get_string_constant("%d\n")
311
- self.builder.call(self.printf, [fmt_str, value])
@@ -1,20 +0,0 @@
1
- shell_lite/__init__.py,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
2
- shell_lite/ast_nodes.py,sha256=W2oefXuRjqnQybR5ZcdPU0qC5gxHZHcotQc3LAVDLM0,6129
3
- shell_lite/cli.py,sha256=14Kq1ohSXS3p-xdh0DPi7eXskUtSX81huSyGhktoOMA,250
4
- shell_lite/compiler.py,sha256=t2Imae9h03v3GIIKrCo16qCDDLKSxrpjrp83tv0SzUQ,24982
5
- shell_lite/interpreter.py,sha256=iMjaxHIjulm6Ed8A7ybrwQgx5OLq8e8g3LAiiOY4phE,75869
6
- shell_lite/js_compiler.py,sha256=yEGIkkIvHGU7o1htHEqlQr6BE0wL35PtL5PssNld9fc,5606
7
- shell_lite/lexer.py,sha256=cNLk_N59a7eKQaQp7Mqcnxy1um64-QgtDEi2eAsAWKE,14913
8
- shell_lite/main.py,sha256=Vj8hYF98GMDyze3wAQXHDkb0_jX8WXj7HTK0-ZALrmE,19927
9
- shell_lite/parser.py,sha256=qsR2wQUWjUPXbXgnmv8pmOgfX99lYYH6tpxKH3PEnfQ,88471
10
- shell_lite/parser_gbp.py,sha256=SoERuuuiL6cnFKtwZW2DQizDIgfwRCezX8l-P8V9qOs,10877
11
- shell_lite/runtime.py,sha256=pSjBeA1dTQ-a94q3FLdv9lqZurdd6MJmfhFGHhOoQEM,16057
12
- shell_lite/llvm_backend/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
- shell_lite/llvm_backend/builder.py,sha256=WjDj65DePu8LPpOpnjfS2XREy9vQt7aySAqRYvBMq5w,1434
14
- shell_lite/llvm_backend/codegen.py,sha256=sTpYxSdrOOqyjf9lj7TLQ5ZFOUM17RykL1QNeariZZM,15875
15
- shell_lite-0.5.3.dist-info/LICENSE,sha256=LlK8rVgwqMiti6NfaXa8xfvXAwfYe5SVrvcz3YpwHgg,37277
16
- shell_lite-0.5.3.dist-info/METADATA,sha256=SgVwBRE0f1LXu8wDCwcAx3_JEaSYUhct0R8Ur8yIeO8,10584
17
- shell_lite-0.5.3.dist-info/WHEEL,sha256=hPN0AlP2dZM_3ZJZWP4WooepkmU9wzjGgCLCeFjkHLA,92
18
- shell_lite-0.5.3.dist-info/entry_points.txt,sha256=tglL8tjyPIh1W85j6zFpNZjMpQe_xC-k-7BOhHLWfxc,45
19
- shell_lite-0.5.3.dist-info/top_level.txt,sha256=hIln5ltrok_Mn3ijlQeqMFF6hHBHCyhzqCO7KL358cg,11
20
- shell_lite-0.5.3.dist-info/RECORD,,