zexus 1.8.1 → 1.8.2
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.
- package/bin/zexus +12 -2
- package/bin/zpics +12 -2
- package/bin/zpm +12 -2
- package/bin/zx +12 -2
- package/bin/zx-deploy +12 -2
- package/bin/zx-dev +12 -2
- package/bin/zx-run +12 -2
- package/package.json +1 -1
- package/scripts/postinstall.js +192 -41
- package/src/zexus/__init__.py +1 -1
- package/src/zexus/cli/main.py +1 -1
- package/src/zexus/cli/zpm.py +1 -1
- package/src/zexus/parser/parser.py +34 -9
- package/src/zexus/parser/strategy_context.py +91 -2
- package/src/zexus/vm/compiler.py +469 -48
- package/src/zexus/vm/vm.py +249 -32
- package/src/zexus/zpm/package_manager.py +1 -1
- package/src/zexus.egg-info/PKG-INFO +1 -1
- package/src/zexus.egg-info/SOURCES.txt +9 -0
- package/src/zexus.egg-info/entry_points.txt +8 -0
package/src/zexus/vm/compiler.py
CHANGED
|
@@ -67,9 +67,9 @@ class BytecodeCompiler:
|
|
|
67
67
|
if op == Opcode.NOP and isinstance(operand, str) and operand.startswith('L'):
|
|
68
68
|
labels[operand] = i
|
|
69
69
|
|
|
70
|
-
# 2. Update jumps
|
|
70
|
+
# 2. Update jumps (including SETUP_TRY which also uses label targets)
|
|
71
71
|
for i, (op, operand) in enumerate(self.instructions):
|
|
72
|
-
if op in (Opcode.JUMP, Opcode.JUMP_IF_FALSE, Opcode.JUMP_IF_TRUE):
|
|
72
|
+
if op in (Opcode.JUMP, Opcode.JUMP_IF_FALSE, Opcode.JUMP_IF_TRUE, Opcode.SETUP_TRY):
|
|
73
73
|
if isinstance(operand, str) and operand in labels:
|
|
74
74
|
self.instructions[i] = (op, labels[operand])
|
|
75
75
|
|
|
@@ -155,25 +155,8 @@ class BytecodeCompiler:
|
|
|
155
155
|
|
|
156
156
|
def _unsupported_message(self, node_type: str) -> str:
|
|
157
157
|
"""Return a friendly message for unsupported nodes."""
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
"FromStatement": "Module imports",
|
|
161
|
-
"EntityStatement": "Entity declarations",
|
|
162
|
-
"ContractStatement": "Contract declarations",
|
|
163
|
-
"ActionStatement": "Action/function declarations",
|
|
164
|
-
"FunctionStatement": "Function declarations",
|
|
165
|
-
"IfStatement": "If statements",
|
|
166
|
-
"WhileStatement": "While loops",
|
|
167
|
-
"ForStatement": "For loops",
|
|
168
|
-
"ForEachStatement": "For-each loops",
|
|
169
|
-
"TxStatement": "Transaction blocks",
|
|
170
|
-
"RequireStatement": "Require statements",
|
|
171
|
-
"RevertStatement": "Revert statements",
|
|
172
|
-
}
|
|
173
|
-
prefix = hints.get(node_type)
|
|
174
|
-
if prefix:
|
|
175
|
-
return f"{prefix} are not yet supported by the VM bytecode compiler"
|
|
176
|
-
return f"Node type '{node_type}' is not supported by the VM bytecode compiler"
|
|
158
|
+
msg = f"Node type '{node_type}' is not currently supported by the bytecode compiler."
|
|
159
|
+
return msg
|
|
177
160
|
|
|
178
161
|
# ==================== Program & Statements ====================
|
|
179
162
|
|
|
@@ -360,6 +343,9 @@ class BytecodeCompiler:
|
|
|
360
343
|
'>=': Opcode.GTE,
|
|
361
344
|
'&&': Opcode.AND,
|
|
362
345
|
'||': Opcode.OR,
|
|
346
|
+
'and': Opcode.AND,
|
|
347
|
+
'or': Opcode.OR,
|
|
348
|
+
'..': Opcode.ADD, # string concat alias
|
|
363
349
|
}
|
|
364
350
|
|
|
365
351
|
opcode = op_map.get(node.operator)
|
|
@@ -374,7 +360,7 @@ class BytecodeCompiler:
|
|
|
374
360
|
|
|
375
361
|
if node.operator == '-':
|
|
376
362
|
self._emit(Opcode.NEG)
|
|
377
|
-
elif node.operator
|
|
363
|
+
elif node.operator in ('!', 'not'):
|
|
378
364
|
self._emit(Opcode.NOT)
|
|
379
365
|
else:
|
|
380
366
|
raise NotImplementedError(f"Prefix operator {node.operator} not implemented")
|
|
@@ -382,35 +368,33 @@ class BytecodeCompiler:
|
|
|
382
368
|
# ==================== Control Flow ====================
|
|
383
369
|
|
|
384
370
|
def _compile_IfExpression(self, node):
|
|
385
|
-
"""Compile if/else statement"""
|
|
386
|
-
# Compile condition
|
|
387
|
-
self._compile_node(node.condition)
|
|
388
|
-
|
|
389
|
-
# Jump if false
|
|
390
|
-
else_label = self._make_label()
|
|
371
|
+
"""Compile if/elif/else statement"""
|
|
391
372
|
end_label = self._make_label()
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
373
|
+
|
|
374
|
+
# --- Main if ---
|
|
375
|
+
self._compile_node(node.condition)
|
|
376
|
+
next_label = self._make_label()
|
|
377
|
+
self._emit(Opcode.JUMP_IF_FALSE, next_label)
|
|
396
378
|
self._compile_node(node.consequence)
|
|
397
379
|
self._emit(Opcode.JUMP, end_label)
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
380
|
+
self._mark_label(next_label)
|
|
381
|
+
|
|
382
|
+
# --- elif chains ---
|
|
383
|
+
elif_parts = getattr(node, 'elif_parts', None) or []
|
|
384
|
+
for elif_cond, elif_body in elif_parts:
|
|
385
|
+
self._compile_node(elif_cond)
|
|
386
|
+
next_elif_label = self._make_label()
|
|
387
|
+
self._emit(Opcode.JUMP_IF_FALSE, next_elif_label)
|
|
388
|
+
self._compile_node(elif_body)
|
|
389
|
+
self._emit(Opcode.JUMP, end_label)
|
|
390
|
+
self._mark_label(next_elif_label)
|
|
391
|
+
|
|
392
|
+
# --- else ---
|
|
403
393
|
if node.alternative:
|
|
404
394
|
self._compile_node(node.alternative)
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
self._emit(Opcode.LOAD_CONST, null_idx)
|
|
409
|
-
|
|
410
|
-
# End label
|
|
411
|
-
self._emit(Opcode.NOP)
|
|
412
|
-
self.instructions[-1] = (Opcode.NOP, end_label)
|
|
413
|
-
|
|
395
|
+
|
|
396
|
+
self._mark_label(end_label)
|
|
397
|
+
|
|
414
398
|
_compile_IfStatement = _compile_IfExpression
|
|
415
399
|
|
|
416
400
|
def _compile_TernaryExpression(self, node):
|
|
@@ -508,7 +492,84 @@ class BytecodeCompiler:
|
|
|
508
492
|
self.instructions[exit_jump_idx] = (Opcode.JUMP_IF_FALSE, end_label)
|
|
509
493
|
|
|
510
494
|
self.loop_stack.pop()
|
|
511
|
-
|
|
495
|
+
|
|
496
|
+
def _compile_ForEachStatement(self, node):
|
|
497
|
+
"""Compile for-each loop: for item in iterable { ... }
|
|
498
|
+
|
|
499
|
+
Strategy: index-based iteration using GET_LENGTH + INDEX.
|
|
500
|
+
Generates equivalent of:
|
|
501
|
+
_iter = <iterable>
|
|
502
|
+
_index = 0
|
|
503
|
+
loop_start:
|
|
504
|
+
if _index >= len(_iter): goto end
|
|
505
|
+
item = _iter[_index]
|
|
506
|
+
<body>
|
|
507
|
+
continue_label:
|
|
508
|
+
_index = _index + 1
|
|
509
|
+
goto loop_start
|
|
510
|
+
end:
|
|
511
|
+
"""
|
|
512
|
+
# --- Compile iterable and store in a hidden temp ---
|
|
513
|
+
self._compile_node(node.iterable)
|
|
514
|
+
iter_var = self._make_temp_name("iter")
|
|
515
|
+
iter_const = self._add_constant(iter_var)
|
|
516
|
+
self._emit(Opcode.STORE_NAME, iter_const)
|
|
517
|
+
|
|
518
|
+
# --- Initialise index = 0 ---
|
|
519
|
+
index_var = self._make_temp_name("idx")
|
|
520
|
+
index_const = self._add_constant(index_var)
|
|
521
|
+
zero_const = self._add_constant(0)
|
|
522
|
+
self._emit(Opcode.LOAD_CONST, zero_const)
|
|
523
|
+
self._emit(Opcode.STORE_NAME, index_const)
|
|
524
|
+
|
|
525
|
+
# --- Labels ---
|
|
526
|
+
start_label = self._make_label()
|
|
527
|
+
end_label = self._make_label()
|
|
528
|
+
continue_label = self._make_label()
|
|
529
|
+
|
|
530
|
+
self.loop_stack.append({
|
|
531
|
+
'start': start_label,
|
|
532
|
+
'end': end_label,
|
|
533
|
+
'continue': continue_label,
|
|
534
|
+
})
|
|
535
|
+
|
|
536
|
+
# --- Condition: index < len(iterable) ---
|
|
537
|
+
self._mark_label(start_label)
|
|
538
|
+
self._emit(Opcode.LOAD_NAME, index_const) # push index
|
|
539
|
+
self._emit(Opcode.LOAD_NAME, iter_const) # push iterable
|
|
540
|
+
self.instructions.append(("GET_LENGTH", None)) # push len(iterable)
|
|
541
|
+
self._emit(Opcode.LT) # index < length
|
|
542
|
+
exit_jump_idx = len(self.instructions)
|
|
543
|
+
self._emit(Opcode.JUMP_IF_FALSE, None) # jump to end if false
|
|
544
|
+
|
|
545
|
+
# --- Extract item: item = iterable[index] ---
|
|
546
|
+
self._emit(Opcode.LOAD_NAME, iter_const) # push iterable
|
|
547
|
+
self._emit(Opcode.LOAD_NAME, index_const) # push index
|
|
548
|
+
self._emit(Opcode.INDEX) # iterable[index]
|
|
549
|
+
item_name = node.item.value if hasattr(node.item, 'value') else str(node.item)
|
|
550
|
+
item_const = self._add_constant(item_name)
|
|
551
|
+
self._emit(Opcode.STORE_NAME, item_const) # store as loop variable
|
|
552
|
+
|
|
553
|
+
# --- Body ---
|
|
554
|
+
self._compile_node(node.body)
|
|
555
|
+
|
|
556
|
+
# --- Continue: index += 1 ---
|
|
557
|
+
self._mark_label(continue_label)
|
|
558
|
+
one_const = self._add_constant(1)
|
|
559
|
+
self._emit(Opcode.LOAD_NAME, index_const)
|
|
560
|
+
self._emit(Opcode.LOAD_CONST, one_const)
|
|
561
|
+
self._emit(Opcode.ADD)
|
|
562
|
+
self._emit(Opcode.STORE_NAME, index_const)
|
|
563
|
+
|
|
564
|
+
# --- Jump back ---
|
|
565
|
+
self._emit(Opcode.JUMP, start_label)
|
|
566
|
+
|
|
567
|
+
# --- End ---
|
|
568
|
+
self._mark_label(end_label)
|
|
569
|
+
self.instructions[exit_jump_idx] = (Opcode.JUMP_IF_FALSE, end_label)
|
|
570
|
+
|
|
571
|
+
self.loop_stack.pop()
|
|
572
|
+
|
|
512
573
|
# ==================== Function Calls ====================
|
|
513
574
|
|
|
514
575
|
def _compile_CallExpression(self, node):
|
|
@@ -653,6 +714,37 @@ class BytecodeCompiler:
|
|
|
653
714
|
_compile_FunctionStatement = _compile_ActionStatement
|
|
654
715
|
_compile_PureFunctionStatement = _compile_ActionStatement
|
|
655
716
|
|
|
717
|
+
def _compile_LambdaExpression(self, node):
|
|
718
|
+
"""Compile lambda/anonymous function expression.
|
|
719
|
+
|
|
720
|
+
Lambda differs from ActionStatement: it has no name and its value should
|
|
721
|
+
be *pushed* onto the stack (not stored) so it can be used inline, e.g.
|
|
722
|
+
as an argument to a higher-order function.
|
|
723
|
+
"""
|
|
724
|
+
from .bytecode import Bytecode
|
|
725
|
+
|
|
726
|
+
func_compiler = self.__class__()
|
|
727
|
+
func_compiler._compile_node(node.body)
|
|
728
|
+
|
|
729
|
+
# Implicit return of last expression value
|
|
730
|
+
null_idx = func_compiler._add_constant(None)
|
|
731
|
+
func_compiler._emit(Opcode.LOAD_CONST, null_idx)
|
|
732
|
+
func_compiler._emit(Opcode.RETURN)
|
|
733
|
+
|
|
734
|
+
func_compiler._resolve_labels()
|
|
735
|
+
func_bytecode = Bytecode(func_compiler.instructions, func_compiler.constants)
|
|
736
|
+
|
|
737
|
+
params = [p.value if hasattr(p, 'value') else str(p) for p in node.parameters]
|
|
738
|
+
func_desc = {
|
|
739
|
+
"bytecode": func_bytecode,
|
|
740
|
+
"params": params,
|
|
741
|
+
"is_async": False,
|
|
742
|
+
"name": "<lambda>",
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
func_idx = self._add_constant(func_desc)
|
|
746
|
+
self._emit(Opcode.LOAD_CONST, func_idx)
|
|
747
|
+
|
|
656
748
|
def _compile_ConstStatement(self, node):
|
|
657
749
|
"""Compile const declaration (same as Let for current VM)"""
|
|
658
750
|
self._compile_LetStatement(node)
|
|
@@ -967,7 +1059,8 @@ class BytecodeCompiler:
|
|
|
967
1059
|
|
|
968
1060
|
def _compile_AwaitExpression(self, node):
|
|
969
1061
|
"""Compile await expression"""
|
|
970
|
-
|
|
1062
|
+
expr = getattr(node, 'expression', None) or getattr(node, 'argument', None)
|
|
1063
|
+
self._compile_node(expr)
|
|
971
1064
|
self._emit(Opcode.AWAIT)
|
|
972
1065
|
|
|
973
1066
|
def _compile_ThisExpression(self, node):
|
|
@@ -1206,6 +1299,334 @@ class BytecodeCompiler:
|
|
|
1206
1299
|
# Alias MatchExpression to logic (it's similar enough for basic cases)
|
|
1207
1300
|
_compile_MatchExpression = _compile_PatternStatement
|
|
1208
1301
|
|
|
1302
|
+
# ==================== Debug / Verify / Watch ====================
|
|
1303
|
+
|
|
1304
|
+
def _compile_DebugStatement(self, node):
|
|
1305
|
+
"""Compile debug statement — prints the value (conditional on condition if present)."""
|
|
1306
|
+
if node.condition:
|
|
1307
|
+
skip_label = self._make_label()
|
|
1308
|
+
self._compile_node(node.condition)
|
|
1309
|
+
self._emit(Opcode.JUMP_IF_FALSE, skip_label)
|
|
1310
|
+
self._compile_node(node.value)
|
|
1311
|
+
self._emit(Opcode.PRINT)
|
|
1312
|
+
end_label = self._make_label()
|
|
1313
|
+
self._emit(Opcode.JUMP, end_label)
|
|
1314
|
+
self._mark_label(skip_label)
|
|
1315
|
+
self._mark_label(end_label)
|
|
1316
|
+
else:
|
|
1317
|
+
self._compile_node(node.value)
|
|
1318
|
+
self._emit(Opcode.PRINT)
|
|
1319
|
+
|
|
1320
|
+
def _compile_VerifyStatement(self, node):
|
|
1321
|
+
"""Compile verify statement.
|
|
1322
|
+
|
|
1323
|
+
Simple assertion form: verify condition, "message"
|
|
1324
|
+
Compiles to: if (!condition) { require(false, message) }
|
|
1325
|
+
Complex forms: delegate to the evaluator via VM-builtin call.
|
|
1326
|
+
"""
|
|
1327
|
+
if node.condition and not node.mode:
|
|
1328
|
+
# Simple assertion: verify cond, msg
|
|
1329
|
+
self._compile_node(node.condition)
|
|
1330
|
+
ok_label = self._make_label()
|
|
1331
|
+
self._emit(Opcode.JUMP_IF_TRUE, ok_label)
|
|
1332
|
+
# Verification failed — emit require(false, message)
|
|
1333
|
+
false_idx = self._add_constant(False)
|
|
1334
|
+
self._emit(Opcode.LOAD_CONST, false_idx)
|
|
1335
|
+
if node.message:
|
|
1336
|
+
self._compile_node(node.message)
|
|
1337
|
+
else:
|
|
1338
|
+
msg_idx = self._add_constant("Verification failed")
|
|
1339
|
+
self._emit(Opcode.LOAD_CONST, msg_idx)
|
|
1340
|
+
self._emit(Opcode.REQUIRE)
|
|
1341
|
+
self._mark_label(ok_label)
|
|
1342
|
+
else:
|
|
1343
|
+
# Complex form — delegate to higher-level evaluator
|
|
1344
|
+
self._emit_vm_builtin_call("__verify__", node)
|
|
1345
|
+
|
|
1346
|
+
def _compile_WatchStatement(self, node):
|
|
1347
|
+
"""Compile watch statement — reactive state management.
|
|
1348
|
+
|
|
1349
|
+
In a bytecode context, watch compiles the reaction body inline.
|
|
1350
|
+
Full reactivity tracking requires runtime support; here we compile the
|
|
1351
|
+
body so it can at least execute once (eager evaluation).
|
|
1352
|
+
"""
|
|
1353
|
+
if node.watched_expr:
|
|
1354
|
+
self._compile_node(node.watched_expr)
|
|
1355
|
+
self._emit(Opcode.POP)
|
|
1356
|
+
self._compile_node(node.reaction)
|
|
1357
|
+
|
|
1358
|
+
def _compile_NullishExpression(self, node):
|
|
1359
|
+
"""Compile nullish coalescing: left ?? right"""
|
|
1360
|
+
self._compile_node(node.left)
|
|
1361
|
+
self._emit(Opcode.DUP)
|
|
1362
|
+
# If not null, skip to end
|
|
1363
|
+
end_label = self._make_label()
|
|
1364
|
+
null_idx = self._add_constant(None)
|
|
1365
|
+
self._emit(Opcode.LOAD_CONST, null_idx)
|
|
1366
|
+
self._emit(Opcode.NEQ)
|
|
1367
|
+
self._emit(Opcode.JUMP_IF_TRUE, end_label)
|
|
1368
|
+
# Left was null, pop it and use right
|
|
1369
|
+
self._emit(Opcode.POP)
|
|
1370
|
+
self._compile_node(node.right)
|
|
1371
|
+
self._mark_label(end_label)
|
|
1372
|
+
|
|
1373
|
+
def _compile_ThrowStatement(self, node):
|
|
1374
|
+
"""Compile throw statement"""
|
|
1375
|
+
expr = getattr(node, 'message', None) or getattr(node, 'expression', None)
|
|
1376
|
+
if expr:
|
|
1377
|
+
self._compile_node(expr)
|
|
1378
|
+
else:
|
|
1379
|
+
self._emit(Opcode.LOAD_CONST, self._add_constant("Unknown error"))
|
|
1380
|
+
self._emit(Opcode.THROW)
|
|
1381
|
+
|
|
1382
|
+
def _compile_EnumStatement(self, node):
|
|
1383
|
+
"""Compile enum declaration"""
|
|
1384
|
+
self._emit_vm_builtin_call("__define_enum__", node)
|
|
1385
|
+
|
|
1386
|
+
def _compile_StringInterpolationExpression(self, node):
|
|
1387
|
+
"""Compile string interpolation: `hello {name}`
|
|
1388
|
+
|
|
1389
|
+
Compiles each part and concatenates with ADD.
|
|
1390
|
+
"""
|
|
1391
|
+
parts = node.parts if hasattr(node, 'parts') else []
|
|
1392
|
+
if not parts:
|
|
1393
|
+
self._emit(Opcode.LOAD_CONST, self._add_constant(""))
|
|
1394
|
+
return
|
|
1395
|
+
|
|
1396
|
+
self._compile_node(parts[0])
|
|
1397
|
+
for part in parts[1:]:
|
|
1398
|
+
self._compile_node(part)
|
|
1399
|
+
self._emit(Opcode.ADD)
|
|
1400
|
+
|
|
1401
|
+
# ==================== ActionLiteral / AsyncExpression / ProtectStatement ====================
|
|
1402
|
+
|
|
1403
|
+
def _compile_ActionLiteral(self, node):
|
|
1404
|
+
"""Compile action literal (anonymous function expression).
|
|
1405
|
+
|
|
1406
|
+
ActionLiteral is semantically identical to LambdaExpression — an
|
|
1407
|
+
anonymous function with parameters and a body. It pushes a function
|
|
1408
|
+
descriptor onto the stack so it can be passed as an argument or
|
|
1409
|
+
assigned to a variable.
|
|
1410
|
+
"""
|
|
1411
|
+
from .bytecode import Bytecode
|
|
1412
|
+
|
|
1413
|
+
func_compiler = self.__class__()
|
|
1414
|
+
func_compiler._compile_node(node.body)
|
|
1415
|
+
|
|
1416
|
+
# Implicit return null if execution flows off the end
|
|
1417
|
+
null_idx = func_compiler._add_constant(None)
|
|
1418
|
+
func_compiler._emit(Opcode.LOAD_CONST, null_idx)
|
|
1419
|
+
func_compiler._emit(Opcode.RETURN)
|
|
1420
|
+
|
|
1421
|
+
func_compiler._resolve_labels()
|
|
1422
|
+
func_bytecode = Bytecode(func_compiler.instructions, func_compiler.constants)
|
|
1423
|
+
|
|
1424
|
+
params = [p.value if hasattr(p, 'value') else str(p) for p in node.parameters]
|
|
1425
|
+
func_desc = {
|
|
1426
|
+
"bytecode": func_bytecode,
|
|
1427
|
+
"params": params,
|
|
1428
|
+
"is_async": False,
|
|
1429
|
+
"name": "<action>",
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
func_idx = self._add_constant(func_desc)
|
|
1433
|
+
self._emit(Opcode.LOAD_CONST, func_idx)
|
|
1434
|
+
|
|
1435
|
+
def _compile_AsyncExpression(self, node):
|
|
1436
|
+
"""Compile async expression: ``async <expr>``
|
|
1437
|
+
|
|
1438
|
+
Compiles the inner expression, then emits SPAWN to schedule it
|
|
1439
|
+
asynchronously. The resulting task handle is left on the stack.
|
|
1440
|
+
"""
|
|
1441
|
+
self._compile_node(node.expression)
|
|
1442
|
+
self._emit(Opcode.SPAWN)
|
|
1443
|
+
|
|
1444
|
+
def _compile_ProtectStatement(self, node):
|
|
1445
|
+
"""Compile protect() security guardrail.
|
|
1446
|
+
|
|
1447
|
+
protect(target, rules) is a high-level security directive.
|
|
1448
|
+
We compile target and rules, then call the VM builtin __protect__.
|
|
1449
|
+
If the builtin is not registered at runtime the VM will silently
|
|
1450
|
+
skip (same behaviour as NativeStatement etc.).
|
|
1451
|
+
"""
|
|
1452
|
+
# Compile target
|
|
1453
|
+
self._compile_node(node.target)
|
|
1454
|
+
# Compile rules
|
|
1455
|
+
self._compile_node(node.rules)
|
|
1456
|
+
# Call builtin
|
|
1457
|
+
name_idx = self._add_constant("__protect__")
|
|
1458
|
+
self._emit(Opcode.CALL_NAME, (name_idx, 2))
|
|
1459
|
+
self._emit(Opcode.POP)
|
|
1460
|
+
|
|
1461
|
+
# ==================== Additional commonly-used nodes ====================
|
|
1462
|
+
|
|
1463
|
+
def _compile_SandboxStatement(self, node):
|
|
1464
|
+
"""Compile sandbox statement — wraps body in an isolated scope."""
|
|
1465
|
+
self._compile_node(node.body)
|
|
1466
|
+
|
|
1467
|
+
def _compile_MiddlewareStatement(self, node):
|
|
1468
|
+
"""Compile middleware registration."""
|
|
1469
|
+
self._emit_vm_builtin_call("__middleware__", node)
|
|
1470
|
+
|
|
1471
|
+
def _compile_AuthStatement(self, node):
|
|
1472
|
+
"""Compile auth statement."""
|
|
1473
|
+
self._emit_vm_builtin_call("__auth__", node)
|
|
1474
|
+
|
|
1475
|
+
def _compile_ThrottleStatement(self, node):
|
|
1476
|
+
"""Compile throttle statement."""
|
|
1477
|
+
self._emit_vm_builtin_call("__throttle__", node)
|
|
1478
|
+
|
|
1479
|
+
def _compile_CacheStatement(self, node):
|
|
1480
|
+
"""Compile cache statement."""
|
|
1481
|
+
self._emit_vm_builtin_call("__cache__", node)
|
|
1482
|
+
|
|
1483
|
+
def _compile_SealStatement(self, node):
|
|
1484
|
+
"""Compile seal statement."""
|
|
1485
|
+
self._emit_vm_builtin_call("__seal__", node)
|
|
1486
|
+
|
|
1487
|
+
def _compile_StreamStatement(self, node):
|
|
1488
|
+
"""Compile stream statement."""
|
|
1489
|
+
self._emit_vm_builtin_call("__stream__", node)
|
|
1490
|
+
|
|
1491
|
+
def _compile_LogStatement(self, node):
|
|
1492
|
+
"""Compile log statement — same as print."""
|
|
1493
|
+
if hasattr(node, 'message'):
|
|
1494
|
+
self._compile_node(node.message)
|
|
1495
|
+
elif hasattr(node, 'value'):
|
|
1496
|
+
self._compile_node(node.value)
|
|
1497
|
+
elif hasattr(node, 'expression'):
|
|
1498
|
+
self._compile_node(node.expression)
|
|
1499
|
+
else:
|
|
1500
|
+
self._emit(Opcode.LOAD_CONST, self._add_constant(""))
|
|
1501
|
+
self._emit(Opcode.PRINT)
|
|
1502
|
+
|
|
1503
|
+
def _compile_ImmutableStatement(self, node):
|
|
1504
|
+
"""Compile immutable declaration — treat as const."""
|
|
1505
|
+
self._compile_LetStatement(node)
|
|
1506
|
+
|
|
1507
|
+
def _compile_ValidateStatement(self, node):
|
|
1508
|
+
"""Compile validate statement."""
|
|
1509
|
+
self._emit_vm_builtin_call("__validate__", node)
|
|
1510
|
+
|
|
1511
|
+
def _compile_SanitizeStatement(self, node):
|
|
1512
|
+
"""Compile sanitize statement."""
|
|
1513
|
+
self._emit_vm_builtin_call("__sanitize__", node)
|
|
1514
|
+
|
|
1515
|
+
def _compile_InjectStatement(self, node):
|
|
1516
|
+
"""Compile inject statement (dependency injection)."""
|
|
1517
|
+
self._emit_vm_builtin_call("__inject__", node)
|
|
1518
|
+
|
|
1519
|
+
def _compile_InterfaceStatement(self, node):
|
|
1520
|
+
"""Compile interface statement — define type contract."""
|
|
1521
|
+
self._emit_vm_builtin_call("__interface__", node)
|
|
1522
|
+
|
|
1523
|
+
def _compile_TypeAliasStatement(self, node):
|
|
1524
|
+
"""Compile type alias — no-op at runtime."""
|
|
1525
|
+
pass
|
|
1526
|
+
|
|
1527
|
+
def _compile_ModuleStatement(self, node):
|
|
1528
|
+
"""Compile module statement."""
|
|
1529
|
+
if hasattr(node, 'body'):
|
|
1530
|
+
self._compile_node(node.body)
|
|
1531
|
+
|
|
1532
|
+
def _compile_PackageStatement(self, node):
|
|
1533
|
+
"""Compile package statement."""
|
|
1534
|
+
if hasattr(node, 'body'):
|
|
1535
|
+
self._compile_node(node.body)
|
|
1536
|
+
|
|
1537
|
+
def _compile_TrailStatement(self, node):
|
|
1538
|
+
"""Compile trail/audit-trail statement."""
|
|
1539
|
+
self._emit_vm_builtin_call("__trail__", node)
|
|
1540
|
+
|
|
1541
|
+
def _compile_EmbeddedCodeStatement(self, node):
|
|
1542
|
+
"""Compile embedded code — no-op in VM (Python-only)."""
|
|
1543
|
+
pass
|
|
1544
|
+
|
|
1545
|
+
def _compile_EmbeddedLiteral(self, node):
|
|
1546
|
+
"""Compile embedded literal — push as string constant."""
|
|
1547
|
+
code = getattr(node, 'code', '') or getattr(node, 'value', '') or ''
|
|
1548
|
+
self._emit(Opcode.LOAD_CONST, self._add_constant(code))
|
|
1549
|
+
|
|
1550
|
+
def _compile_ExternalDeclaration(self, node):
|
|
1551
|
+
"""Compile external declaration — no-op (type hint only)."""
|
|
1552
|
+
pass
|
|
1553
|
+
|
|
1554
|
+
def _compile_ImportLogStatement(self, node):
|
|
1555
|
+
"""Compile import log statement — no-op at compile time."""
|
|
1556
|
+
pass
|
|
1557
|
+
|
|
1558
|
+
def _compile_ExactlyStatement(self, node):
|
|
1559
|
+
"""Compile exactly statement (type-exact check)."""
|
|
1560
|
+
self._emit_vm_builtin_call("__exactly__", node)
|
|
1561
|
+
|
|
1562
|
+
def _compile_FindExpression(self, node):
|
|
1563
|
+
"""Compile find expression."""
|
|
1564
|
+
self._emit_vm_builtin_call("__find__", node, discard_result=False)
|
|
1565
|
+
|
|
1566
|
+
def _compile_LoadExpression(self, node):
|
|
1567
|
+
"""Compile load expression."""
|
|
1568
|
+
self._emit_vm_builtin_call("__load__", node, discard_result=False)
|
|
1569
|
+
|
|
1570
|
+
def _compile_DestructurePattern(self, node):
|
|
1571
|
+
"""Compile destructure pattern — push null (placeholder)."""
|
|
1572
|
+
self._emit(Opcode.LOAD_CONST, self._add_constant(None))
|
|
1573
|
+
|
|
1574
|
+
def _compile_AtomicStatement(self, node):
|
|
1575
|
+
"""Compile atomic statement — executes body/expr as a single unit.
|
|
1576
|
+
|
|
1577
|
+
In the current VM, atomic simply compiles the inner body or expression
|
|
1578
|
+
directly. True atomicity would require runtime locking which the VM
|
|
1579
|
+
can add later.
|
|
1580
|
+
"""
|
|
1581
|
+
if node.body:
|
|
1582
|
+
self._compile_node(node.body)
|
|
1583
|
+
elif node.expr:
|
|
1584
|
+
self._compile_node(node.expr)
|
|
1585
|
+
self._emit(Opcode.POP)
|
|
1586
|
+
|
|
1587
|
+
# ==================== Channel / Concurrency statements ====================
|
|
1588
|
+
|
|
1589
|
+
def _compile_ChannelStatement(self, node):
|
|
1590
|
+
"""Compile channel declaration: channel<T>[capacity] name
|
|
1591
|
+
|
|
1592
|
+
Emits a call to the ``__create_channel__`` VM builtin which creates a
|
|
1593
|
+
:class:`Channel` object and stores it in the environment.
|
|
1594
|
+
"""
|
|
1595
|
+
# Push channel name
|
|
1596
|
+
ch_name = node.name.value if hasattr(node.name, 'value') else str(node.name)
|
|
1597
|
+
self._emit(Opcode.LOAD_CONST, self._add_constant(ch_name))
|
|
1598
|
+
|
|
1599
|
+
# Push element type (string or None)
|
|
1600
|
+
elem_type = None
|
|
1601
|
+
if hasattr(node, 'element_type') and node.element_type is not None:
|
|
1602
|
+
elem_type = node.element_type.value if hasattr(node.element_type, 'value') else str(node.element_type)
|
|
1603
|
+
self._emit(Opcode.LOAD_CONST, self._add_constant(elem_type))
|
|
1604
|
+
|
|
1605
|
+
# Push capacity
|
|
1606
|
+
if hasattr(node, 'capacity') and node.capacity is not None:
|
|
1607
|
+
self._compile_node(node.capacity)
|
|
1608
|
+
else:
|
|
1609
|
+
self._emit(Opcode.LOAD_CONST, self._add_constant(0))
|
|
1610
|
+
|
|
1611
|
+
# Call __create_channel__(name, element_type, capacity)
|
|
1612
|
+
fn_idx = self._add_constant("__create_channel__")
|
|
1613
|
+
self._emit(Opcode.CALL_NAME, (fn_idx, 3))
|
|
1614
|
+
self._emit(Opcode.POP) # discard result (channel stored internally)
|
|
1615
|
+
|
|
1616
|
+
def _compile_SendStatement(self, node):
|
|
1617
|
+
"""Compile send statement: send(channel, value)"""
|
|
1618
|
+
self._compile_node(node.channel_expr)
|
|
1619
|
+
self._compile_node(node.value_expr)
|
|
1620
|
+
fn_idx = self._add_constant("send")
|
|
1621
|
+
self._emit(Opcode.CALL_NAME, (fn_idx, 2))
|
|
1622
|
+
self._emit(Opcode.POP)
|
|
1623
|
+
|
|
1624
|
+
def _compile_ReceiveStatement(self, node):
|
|
1625
|
+
"""Compile receive statement: value = receive(channel)"""
|
|
1626
|
+
self._compile_node(node.channel_expr)
|
|
1627
|
+
fn_idx = self._add_constant("receive")
|
|
1628
|
+
self._emit(Opcode.CALL_NAME, (fn_idx, 1))
|
|
1629
|
+
|
|
1209
1630
|
# ==================== Fallback for unsupported nodes ====================
|
|
1210
1631
|
|
|
1211
1632
|
def __getattr__(self, name):
|