IncludeCPP 3.4.2__py3-none-any.whl → 3.4.10__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.
@@ -12,6 +12,10 @@ from .cssl_parser import ASTNode, parse_cssl, parse_cssl_program, CSSLSyntaxErro
12
12
  from .cssl_events import CSSLEventManager, EventType, EventData, get_event_manager
13
13
  from .cssl_builtins import CSSLBuiltins
14
14
  from .cssl_modules import get_module_registry, get_standard_module
15
+ from .cssl_types import (
16
+ Parameter, DataStruct, Shuffled, Iterator, Combo,
17
+ Stack, Vector, DataSpace, OpenQuote
18
+ )
15
19
 
16
20
 
17
21
  class CSSLRuntimeError(Exception):
@@ -290,6 +294,12 @@ class CSSLRuntime:
290
294
  self._exec_struct(child)
291
295
  elif child.type == 'function':
292
296
  self._exec_function(child)
297
+ elif child.type == 'global_assignment':
298
+ # Handle global variable declaration: global Name = value
299
+ result = self._exec_global_assignment(child)
300
+ elif child.type == 'typed_declaration':
301
+ # Handle typed variable declaration: type<T> varName = value;
302
+ result = self._exec_typed_declaration(child)
293
303
  elif child.type in ('assignment', 'expression', 'inject', 'receive', 'flow',
294
304
  'if', 'while', 'for', 'foreach', 'switch', 'try'):
295
305
  result = self._execute_node(child)
@@ -563,20 +573,123 @@ class CSSLRuntime:
563
573
  self.scope.set(func_name, node)
564
574
  return None
565
575
 
576
+ def _exec_typed_declaration(self, node: ASTNode) -> Any:
577
+ """Execute typed variable declaration: type<T> varName = value;
578
+
579
+ Creates appropriate type instances for stack, vector, datastruct, etc.
580
+ """
581
+ decl = node.value
582
+ type_name = decl.get('type')
583
+ element_type = decl.get('element_type', 'dynamic')
584
+ var_name = decl.get('name')
585
+ value_node = decl.get('value')
586
+
587
+ # Create the appropriate type instance
588
+ if type_name == 'stack':
589
+ instance = Stack(element_type)
590
+ elif type_name == 'vector':
591
+ instance = Vector(element_type)
592
+ elif type_name == 'datastruct':
593
+ instance = DataStruct(element_type)
594
+ elif type_name == 'shuffled':
595
+ instance = Shuffled(element_type)
596
+ elif type_name == 'iterator':
597
+ instance = Iterator(element_type)
598
+ elif type_name == 'combo':
599
+ instance = Combo(element_type)
600
+ elif type_name == 'dataspace':
601
+ instance = DataSpace(element_type)
602
+ elif type_name == 'openquote':
603
+ instance = OpenQuote()
604
+ elif type_name in ('int', 'integer'):
605
+ instance = 0 if value_node is None else self._evaluate(value_node)
606
+ elif type_name in ('string', 'str'):
607
+ instance = "" if value_node is None else self._evaluate(value_node)
608
+ elif type_name in ('float', 'double'):
609
+ instance = 0.0 if value_node is None else self._evaluate(value_node)
610
+ elif type_name == 'bool':
611
+ instance = False if value_node is None else self._evaluate(value_node)
612
+ elif type_name == 'dynamic':
613
+ instance = None if value_node is None else self._evaluate(value_node)
614
+ elif type_name == 'json':
615
+ instance = {} if value_node is None else self._evaluate(value_node)
616
+ elif type_name == 'array':
617
+ instance = [] if value_node is None else self._evaluate(value_node)
618
+ else:
619
+ # Default: evaluate the value or set to None
620
+ instance = self._evaluate(value_node) if value_node else None
621
+
622
+ # If there's an explicit value, use it instead
623
+ if value_node and type_name not in ('int', 'integer', 'string', 'str', 'float', 'double', 'bool', 'dynamic', 'json', 'array'):
624
+ # For container types, the value might be initialization data
625
+ init_value = self._evaluate(value_node)
626
+ if isinstance(init_value, (list, tuple)):
627
+ instance.extend(init_value)
628
+ elif init_value is not None:
629
+ if hasattr(instance, 'append'):
630
+ instance.append(init_value)
631
+
632
+ # Store in scope
633
+ self.scope.set(var_name, instance)
634
+ return instance
635
+
636
+ def _exec_global_assignment(self, node: ASTNode) -> Any:
637
+ """Execute global variable assignment: global Name = value
638
+
639
+ Stores the value in _promoted_globals so it can be accessed via @Name
640
+ """
641
+ inner = node.value # The wrapped assignment/expression node
642
+
643
+ if inner is None:
644
+ return None
645
+
646
+ # Handle assignment node: global Name = value
647
+ if inner.type == 'assignment':
648
+ target = inner.value.get('target')
649
+ value = self._evaluate(inner.value.get('value'))
650
+
651
+ # Get variable name from target
652
+ if isinstance(target, ASTNode) and target.type == 'identifier':
653
+ var_name = target.value
654
+ elif isinstance(target, str):
655
+ var_name = target
656
+ else:
657
+ var_name = str(target)
658
+
659
+ # Store in promoted globals for @Name access
660
+ self._promoted_globals[var_name] = value
661
+ # Also store in global scope for regular access
662
+ self.global_scope.set(var_name, value)
663
+ return value
664
+
665
+ # Handle expression that results in assignment
666
+ elif inner.type == 'expression':
667
+ result = self._evaluate(inner.value)
668
+ return result
669
+
670
+ # Fallback: execute normally
671
+ return self._execute_node(inner)
672
+
566
673
  def _call_function(self, func_node: ASTNode, args: List[Any]) -> Any:
567
674
  """Call a function node with arguments"""
568
675
  func_info = func_node.value
569
676
  params = func_info.get('params', [])
677
+ modifiers = func_info.get('modifiers', [])
678
+
679
+ # Check for undefined modifier - suppress errors if present
680
+ is_undefined = 'undefined' in modifiers
570
681
 
571
682
  # Create new scope
572
683
  new_scope = Scope(parent=self.scope)
573
684
 
574
- # Bind parameters
685
+ # Bind parameters - handle both string and dict formats
575
686
  for i, param in enumerate(params):
687
+ # Extract param name from dict format: {'name': 'a', 'type': 'int'}
688
+ param_name = param['name'] if isinstance(param, dict) else param
576
689
  if i < len(args):
577
- new_scope.set(param, args[i])
690
+ new_scope.set(param_name, args[i])
578
691
  else:
579
- new_scope.set(param, None)
692
+ new_scope.set(param_name, None)
580
693
 
581
694
  # Execute body
582
695
  old_scope = self.scope
@@ -587,6 +700,11 @@ class CSSLRuntime:
587
700
  self._execute_node(child)
588
701
  except CSSLReturn as ret:
589
702
  return ret.value
703
+ except Exception as e:
704
+ # If undefined modifier, suppress all errors
705
+ if is_undefined:
706
+ return None
707
+ raise
590
708
  finally:
591
709
  self.scope = old_scope
592
710
 
@@ -881,7 +999,11 @@ class CSSLRuntime:
881
999
  # Get current target value for add/move modes
882
1000
  current_value = None
883
1001
  if mode in ('add', 'move'):
884
- current_value = self._evaluate(target)
1002
+ try:
1003
+ current_value = self._evaluate(target)
1004
+ except Exception:
1005
+ # Target might not exist yet, that's okay for add mode
1006
+ current_value = None
885
1007
 
886
1008
  # Determine final value based on mode
887
1009
  if mode == 'replace':
@@ -1078,6 +1200,10 @@ class CSSLRuntime:
1078
1200
  if isinstance(target, ASTNode):
1079
1201
  if target.type == 'identifier':
1080
1202
  self.scope.set(target.value, value)
1203
+ elif target.type == 'global_ref':
1204
+ # r@Name = value - store in promoted globals
1205
+ self._promoted_globals[target.value] = value
1206
+ self.global_scope.set(target.value, value)
1081
1207
  elif target.type == 'member_access':
1082
1208
  self._set_member(target, value)
1083
1209
  elif target.type == 'index_access':
@@ -1161,12 +1287,26 @@ class CSSLRuntime:
1161
1287
  return value
1162
1288
 
1163
1289
  if node.type == 'module_ref':
1164
- return self.get_module(node.value)
1290
+ # Check modules first, then promoted globals, then scope
1291
+ value = self.get_module(node.value)
1292
+ if value is None:
1293
+ value = self._promoted_globals.get(node.value)
1294
+ if value is None:
1295
+ value = self.global_scope.get(node.value)
1296
+ return value
1165
1297
 
1166
1298
  if node.type == 'self_ref':
1167
1299
  # s@<name> reference to global struct
1168
1300
  return self.get_global_struct(node.value)
1169
1301
 
1302
+ if node.type == 'global_ref':
1303
+ # r@<name> global variable reference
1304
+ # Check promoted globals first, then global scope
1305
+ value = self._promoted_globals.get(node.value)
1306
+ if value is None:
1307
+ value = self.global_scope.get(node.value)
1308
+ return value
1309
+
1170
1310
  if node.type == 'binary':
1171
1311
  return self._eval_binary(node)
1172
1312
 
@@ -1188,6 +1328,17 @@ class CSSLRuntime:
1188
1328
  if node.type == 'object':
1189
1329
  return {k: self._evaluate(v) for k, v in node.value.items()}
1190
1330
 
1331
+ if node.type == 'reference':
1332
+ # &variable - return a reference object wrapping the actual value
1333
+ inner = node.value
1334
+ if isinstance(inner, ASTNode):
1335
+ if inner.type == 'identifier':
1336
+ # Return a reference wrapper with the variable name
1337
+ return {'__ref__': True, 'name': inner.value, 'value': self.scope.get(inner.value)}
1338
+ elif inner.type == 'module_ref':
1339
+ return {'__ref__': True, 'name': inner.value, 'value': self.get_module(inner.value)}
1340
+ return {'__ref__': True, 'value': self._evaluate(inner)}
1341
+
1191
1342
  return None
1192
1343
 
1193
1344
  def _eval_binary(self, node: ASTNode) -> Any:
@@ -1263,6 +1414,11 @@ class CSSLRuntime:
1263
1414
  if obj is None:
1264
1415
  return None
1265
1416
 
1417
+ # Special handling for Parameter.return() -> Parameter.return_()
1418
+ # since 'return' is a Python keyword
1419
+ if isinstance(obj, Parameter) and member == 'return':
1420
+ member = 'return_'
1421
+
1266
1422
  if hasattr(obj, member):
1267
1423
  return getattr(obj, member)
1268
1424
 
@@ -1388,15 +1544,26 @@ class CSSLRuntime:
1388
1544
 
1389
1545
  # NEW: Execute injected code for a function
1390
1546
  def _execute_function_injections(self, func_name: str):
1391
- """Execute all injected code blocks for a function - NEW"""
1547
+ """Execute all injected code blocks for a function - NEW
1548
+
1549
+ Includes protection against recursive execution to prevent doubled output.
1550
+ """
1551
+ # Prevent recursive injection execution (fixes doubled output bug)
1552
+ if getattr(self, '_injection_executing', False):
1553
+ return
1554
+
1392
1555
  if func_name in self._function_injections:
1393
- for code_block in self._function_injections[func_name]:
1394
- if isinstance(code_block, ASTNode):
1395
- if code_block.type == 'action_block':
1396
- for child in code_block.children:
1397
- self._execute_node(child)
1398
- else:
1399
- self._execute_node(code_block)
1556
+ self._injection_executing = True
1557
+ try:
1558
+ for code_block in self._function_injections[func_name]:
1559
+ if isinstance(code_block, ASTNode):
1560
+ if code_block.type == 'action_block':
1561
+ for child in code_block.children:
1562
+ self._execute_node(child)
1563
+ else:
1564
+ self._execute_node(code_block)
1565
+ finally:
1566
+ self._injection_executing = False
1400
1567
 
1401
1568
  # Output functions for builtins
1402
1569
  def set_output_callback(self, callback: Callable[[str, str], None]):
@@ -65,6 +65,90 @@ class DataStruct(list):
65
65
  return None
66
66
 
67
67
 
68
+ class Stack(list):
69
+ """Stack data structure (LIFO).
70
+
71
+ Standard stack with push/pop operations.
72
+
73
+ Usage:
74
+ stack<string> myStack;
75
+ myStack.push("Item1");
76
+ myStack.push("Item2");
77
+ item = myStack.pop(); # Returns "Item2"
78
+ """
79
+
80
+ def __init__(self, element_type: str = 'dynamic'):
81
+ super().__init__()
82
+ self._element_type = element_type
83
+
84
+ def push(self, item: Any) -> 'Stack':
85
+ """Push item onto stack"""
86
+ self.append(item)
87
+ return self
88
+
89
+ def peek(self) -> Any:
90
+ """View top item without removing"""
91
+ return self[-1] if self else None
92
+
93
+ def is_empty(self) -> bool:
94
+ """Check if stack is empty"""
95
+ return len(self) == 0
96
+
97
+ def size(self) -> int:
98
+ """Return stack size"""
99
+ return len(self)
100
+
101
+
102
+ class Vector(list):
103
+ """Dynamic array (vector) data structure.
104
+
105
+ Resizable array with efficient random access.
106
+
107
+ Usage:
108
+ vector<int> myVector;
109
+ myVector.push(1);
110
+ myVector.push(2);
111
+ myVector.at(0); # Returns 1
112
+ """
113
+
114
+ def __init__(self, element_type: str = 'dynamic'):
115
+ super().__init__()
116
+ self._element_type = element_type
117
+
118
+ def push(self, item: Any) -> 'Vector':
119
+ """Add item to end"""
120
+ self.append(item)
121
+ return self
122
+
123
+ def at(self, index: int) -> Any:
124
+ """Get item at index"""
125
+ if 0 <= index < len(self):
126
+ return self[index]
127
+ return None
128
+
129
+ def set(self, index: int, value: Any) -> 'Vector':
130
+ """Set item at index"""
131
+ if 0 <= index < len(self):
132
+ self[index] = value
133
+ return self
134
+
135
+ def size(self) -> int:
136
+ """Return vector size"""
137
+ return len(self)
138
+
139
+ def empty(self) -> bool:
140
+ """Check if vector is empty"""
141
+ return len(self) == 0
142
+
143
+ def front(self) -> Any:
144
+ """Get first element"""
145
+ return self[0] if self else None
146
+
147
+ def back(self) -> Any:
148
+ """Get last element"""
149
+ return self[-1] if self else None
150
+
151
+
68
152
  class Shuffled(list):
69
153
  """Unorganized fast storage for multiple returns.
70
154
 
@@ -346,6 +430,73 @@ class OpenQuote:
346
430
  return self._data
347
431
 
348
432
 
433
+ class Parameter:
434
+ """Parameter accessor for CSSL exec() arguments.
435
+
436
+ Provides access to arguments passed to CSSL.exec() via parameter.get(index).
437
+
438
+ Usage in CSSL:
439
+ parameter.get(0) # Get first argument
440
+ parameter.get(1) # Get second argument
441
+ parameter.count() # Get total argument count
442
+ parameter.all() # Get all arguments as list
443
+ parameter.return(value) # Yield a return value (generator-like)
444
+ parameter.returns() # Get all yielded return values
445
+ """
446
+
447
+ def __init__(self, args: List[Any] = None):
448
+ self._args = args if args is not None else []
449
+ self._returns: List[Any] = []
450
+
451
+ def get(self, index: int, default: Any = None) -> Any:
452
+ """Get argument at index, returns default if not found"""
453
+ if 0 <= index < len(self._args):
454
+ return self._args[index]
455
+ return default
456
+
457
+ def count(self) -> int:
458
+ """Return total number of arguments"""
459
+ return len(self._args)
460
+
461
+ def all(self) -> List[Any]:
462
+ """Return all arguments as a list"""
463
+ return list(self._args)
464
+
465
+ def has(self, index: int) -> bool:
466
+ """Check if argument exists at index"""
467
+ return 0 <= index < len(self._args)
468
+
469
+ # Using 'return_' to avoid Python keyword conflict
470
+ def return_(self, value: Any) -> None:
471
+ """Yield a return value (generator-like behavior).
472
+
473
+ Multiple calls accumulate values that can be retrieved via returns().
474
+ The CSSL runtime will collect these as the exec() return value.
475
+ """
476
+ self._returns.append(value)
477
+
478
+ def returns(self) -> List[Any]:
479
+ """Get all yielded return values"""
480
+ return list(self._returns)
481
+
482
+ def clear_returns(self) -> None:
483
+ """Clear all yielded return values"""
484
+ self._returns.clear()
485
+
486
+ def has_returns(self) -> bool:
487
+ """Check if any values have been returned"""
488
+ return len(self._returns) > 0
489
+
490
+ def __iter__(self):
491
+ return iter(self._args)
492
+
493
+ def __len__(self):
494
+ return len(self._args)
495
+
496
+ def __getitem__(self, index: int) -> Any:
497
+ return self.get(index)
498
+
499
+
349
500
  def OpenFind(combo_or_type: Union[Combo, type], index: int = 0) -> Optional[Any]:
350
501
  """Find open parameter by type or combo space.
351
502
 
@@ -381,10 +532,21 @@ def create_dataspace(space_type: str = 'dynamic') -> DataSpace:
381
532
  def create_openquote(db_ref: Any = None) -> OpenQuote:
382
533
  return OpenQuote(db_ref)
383
534
 
535
+ def create_stack(element_type: str = 'dynamic') -> Stack:
536
+ return Stack(element_type)
537
+
538
+ def create_vector(element_type: str = 'dynamic') -> Vector:
539
+ return Vector(element_type)
540
+
541
+ def create_parameter(args: List[Any] = None) -> Parameter:
542
+ """Create a Parameter object for accessing exec arguments"""
543
+ return Parameter(args)
544
+
384
545
 
385
546
  __all__ = [
386
547
  'DataStruct', 'Shuffled', 'Iterator', 'Combo', 'DataSpace', 'OpenQuote',
387
- 'OpenFind',
548
+ 'OpenFind', 'Parameter', 'Stack', 'Vector',
388
549
  'create_datastruct', 'create_shuffled', 'create_iterator',
389
- 'create_combo', 'create_dataspace', 'create_openquote'
550
+ 'create_combo', 'create_dataspace', 'create_openquote', 'create_parameter',
551
+ 'create_stack', 'create_vector'
390
552
  ]