IncludeCPP 3.7.1__py3-none-any.whl → 3.7.25__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.
@@ -1,5 +1,5 @@
1
1
  """
2
- CSSL Parser - Lexer and Parser for CSO Service Script Language
2
+ CSSL Parser - Lexer and Parser for CSSL Language
3
3
 
4
4
  Features:
5
5
  - Complete tokenization of CSSL syntax
@@ -108,6 +108,8 @@ class TokenType(Enum):
108
108
  COMMENT = auto()
109
109
  NEWLINE = auto()
110
110
  EOF = auto()
111
+ # Super-functions for .cssl-pl payload files (v3.8.0)
112
+ SUPER_FUNC = auto() # #$run(), #$exec(), #$printl() - pre-execution hooks
111
113
 
112
114
 
113
115
  KEYWORDS = {
@@ -212,9 +214,14 @@ class CSSLLexer:
212
214
 
213
215
  char = self.source[self.pos]
214
216
 
215
- # Comments: both # and // style
217
+ # Super-functions (#$) or Comments (# and // style)
216
218
  if char == '#':
217
- self._skip_comment()
219
+ if self._peek(1) == '$':
220
+ # Super-function: #$run(), #$exec(), #$printl()
221
+ self._read_super_function()
222
+ else:
223
+ # Regular comment
224
+ self._skip_comment()
218
225
  elif char == '/' and self._peek(1) == '/':
219
226
  # C-style // comment - NEW
220
227
  self._skip_comment()
@@ -245,8 +252,15 @@ class CSSLLexer:
245
252
  # $<name> shared object reference
246
253
  self._read_shared_ref()
247
254
  elif char == '%':
248
- # %<name> captured reference (for infusion)
249
- self._read_captured_ref()
255
+ # Check if this is %<name> captured reference or % modulo operator
256
+ next_char = self._peek(1)
257
+ if next_char and (next_char.isalpha() or next_char == '_'):
258
+ # %<name> captured reference (for infusion)
259
+ self._read_captured_ref()
260
+ else:
261
+ # % modulo operator
262
+ self._add_token(TokenType.MODULO, '%')
263
+ self._advance()
250
264
  elif char == '&':
251
265
  # & for references
252
266
  if self._peek(1) == '&':
@@ -314,9 +328,6 @@ class CSSLLexer:
314
328
  else:
315
329
  # Already handled by // comment check above, but just in case
316
330
  self._skip_comment()
317
- elif char == '%':
318
- self._add_token(TokenType.MODULO, '%')
319
- self._advance()
320
331
  elif char == '<':
321
332
  self._read_less_than()
322
333
  elif char == '>':
@@ -446,6 +457,31 @@ class CSSLLexer:
446
457
  else:
447
458
  self._add_token(TokenType.IDENTIFIER, value)
448
459
 
460
+ def _read_super_function(self):
461
+ """Read #$<name>(...) super-function call for .cssl-pl payloads.
462
+
463
+ Super-functions are pre-execution hooks that run when a payload is loaded.
464
+ Valid super-functions: #$run(), #$exec(), #$printl()
465
+
466
+ Syntax:
467
+ #$run(initFunction); // Call a function at load time
468
+ #$exec(setup()); // Execute expression at load time
469
+ #$printl("Payload loaded"); // Print at load time
470
+ """
471
+ start = self.pos
472
+ self._advance() # skip '#'
473
+ self._advance() # skip '$'
474
+
475
+ # Read the super-function name (run, exec, printl, etc.)
476
+ name_start = self.pos
477
+ while self.pos < len(self.source) and (self.source[self.pos].isalnum() or self.source[self.pos] == '_'):
478
+ self._advance()
479
+ func_name = self.source[name_start:self.pos]
480
+
481
+ # Store as #$<name> token value
482
+ value = f'#${func_name}'
483
+ self._add_token(TokenType.SUPER_FUNC, value)
484
+
449
485
  def _read_self_ref(self):
450
486
  """Read s@<name> or s@<name>.<member>... self-reference"""
451
487
  start = self.pos
@@ -816,7 +852,7 @@ class CSSLParser:
816
852
  if self._match_keyword('open'):
817
853
  param_info['open'] = True
818
854
 
819
- # Handle type annotations
855
+ # Handle type annotations (builtin types like int, string, etc.)
820
856
  if self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value):
821
857
  param_info['type'] = self._advance().value
822
858
 
@@ -840,6 +876,39 @@ class CSSLParser:
840
876
  self._advance()
841
877
  param_info['generic'] = ''.join(generic_parts)
842
878
 
879
+ # Handle custom class types (identifier followed by another identifier = type + name)
880
+ elif self._check(TokenType.IDENTIFIER):
881
+ # Look ahead: if next token is also an identifier, current is the type
882
+ saved_pos = self.pos
883
+ potential_type = self._advance().value
884
+
885
+ # Check for generic type parameter <T> on custom type
886
+ if self._check(TokenType.COMPARE_LT):
887
+ self._advance()
888
+ generic_parts = []
889
+ depth = 1
890
+ while depth > 0 and not self._is_at_end():
891
+ if self._check(TokenType.COMPARE_LT):
892
+ depth += 1
893
+ generic_parts.append('<')
894
+ elif self._check(TokenType.COMPARE_GT):
895
+ depth -= 1
896
+ if depth > 0:
897
+ generic_parts.append('>')
898
+ elif self._check(TokenType.COMMA):
899
+ generic_parts.append(',')
900
+ else:
901
+ generic_parts.append(self._current().value)
902
+ self._advance()
903
+ param_info['generic'] = ''.join(generic_parts)
904
+
905
+ # If followed by identifier, this is "Type name" pattern
906
+ if self._check(TokenType.IDENTIFIER):
907
+ param_info['type'] = potential_type
908
+ else:
909
+ # Not a type, restore position - this is just a param name
910
+ self.pos = saved_pos
911
+
843
912
  # Handle reference operator &
844
913
  if self._match(TokenType.AMPERSAND):
845
914
  param_info['ref'] = True
@@ -882,6 +951,27 @@ class CSSLParser:
882
951
  self._expect(TokenType.BLOCK_END)
883
952
  return node
884
953
 
954
+ def _looks_like_namespace_call(self) -> bool:
955
+ """Check if current position looks like a namespace function call.
956
+
957
+ Pattern: keyword::identifier(...) like json::write(), string::cut()
958
+ This allows type keywords to be used as namespace prefixes for function calls.
959
+ """
960
+ if not self._check(TokenType.KEYWORD):
961
+ return False
962
+
963
+ # Save position
964
+ saved_pos = self.pos
965
+
966
+ self._advance() # Skip keyword
967
+
968
+ # Must be followed by ::
969
+ result = self._check(TokenType.DOUBLE_COLON)
970
+
971
+ # Restore position
972
+ self.pos = saved_pos
973
+ return result
974
+
885
975
  def _looks_like_typed_variable(self) -> bool:
886
976
  """Check if current position looks like a typed variable declaration:
887
977
  type_name varName; or type_name<T> varName; or type_name varName = value;
@@ -1377,10 +1467,14 @@ class CSSLParser:
1377
1467
  elif self._looks_like_function_declaration():
1378
1468
  # Nested typed function (e.g., void Level2() { ... })
1379
1469
  return self._parse_typed_function()
1470
+ elif self._check(TokenType.SUPER_FUNC):
1471
+ # Super-function for .cssl-pl payload files
1472
+ return self._parse_super_function()
1380
1473
  elif (self._check(TokenType.IDENTIFIER) or self._check(TokenType.AT) or
1381
1474
  self._check(TokenType.CAPTURED_REF) or self._check(TokenType.SHARED_REF) or
1382
1475
  self._check(TokenType.GLOBAL_REF) or self._check(TokenType.SELF_REF) or
1383
- (self._check(TokenType.KEYWORD) and self._current().value in ('this', 'new'))):
1476
+ (self._check(TokenType.KEYWORD) and self._current().value in ('this', 'new')) or
1477
+ self._looks_like_namespace_call()):
1384
1478
  return self._parse_expression_statement()
1385
1479
  else:
1386
1480
  self._advance()
@@ -1594,23 +1688,42 @@ class CSSLParser:
1594
1688
  return ASTNode('c_for_update', value={'var': var_name, 'op': 'none'})
1595
1689
 
1596
1690
  def _parse_python_style_for(self) -> ASTNode:
1597
- """Parse Python-style for loop: for (i in range(...)) { }
1691
+ """Parse Python-style for loop: for (i in range(...)) { } or for (item in collection) { }
1598
1692
 
1599
1693
  Supports:
1600
1694
  for (i in range(n)) { } - 0 to n-1
1601
1695
  for (i in range(start, end)) { } - start to end-1
1602
1696
  for (i in range(start, end, step)) { }
1697
+ for (item in collection) { } - iterate over list/vector
1698
+ for (item in @global_collection) { } - iterate over global
1603
1699
  """
1604
1700
  var_name = self._advance().value
1605
1701
  self._expect(TokenType.KEYWORD) # 'in'
1606
1702
 
1607
- # 'range' can be keyword or identifier
1703
+ # Check if this is range() or collection iteration
1704
+ is_range = False
1608
1705
  if self._check(TokenType.KEYWORD) and self._peek().value == 'range':
1609
1706
  self._advance() # consume 'range' keyword
1707
+ is_range = True
1610
1708
  elif self._check(TokenType.IDENTIFIER) and self._peek().value == 'range':
1611
1709
  self._advance() # consume 'range' identifier
1612
- else:
1613
- self.error(f"Expected 'range', got {self._peek().value}")
1710
+ is_range = True
1711
+
1712
+ # If not range, parse as collection iteration
1713
+ if not is_range:
1714
+ iterable = self._parse_expression()
1715
+ self._expect(TokenType.PAREN_END)
1716
+
1717
+ node = ASTNode('foreach', value={'var': var_name, 'iterable': iterable}, children=[])
1718
+ self._expect(TokenType.BLOCK_START)
1719
+
1720
+ while not self._check(TokenType.BLOCK_END) and not self._is_at_end():
1721
+ stmt = self._parse_statement()
1722
+ if stmt:
1723
+ node.children.append(stmt)
1724
+
1725
+ self._expect(TokenType.BLOCK_END)
1726
+ return node
1614
1727
 
1615
1728
  self._expect(TokenType.PAREN_START)
1616
1729
  first_arg = self._parse_expression()
@@ -1722,11 +1835,56 @@ class CSSLParser:
1722
1835
  return node
1723
1836
 
1724
1837
  def _parse_return(self) -> ASTNode:
1725
- value = None
1838
+ """Parse return statement, supporting multiple values for shuffled functions.
1839
+
1840
+ Syntax:
1841
+ return; // Return None
1842
+ return value; // Return single value
1843
+ return a, b, c; // Return multiple values (for shuffled)
1844
+ """
1845
+ values = []
1726
1846
  if not self._check(TokenType.SEMICOLON) and not self._check(TokenType.BLOCK_END):
1727
- value = self._parse_expression()
1847
+ values.append(self._parse_expression())
1848
+
1849
+ # Check for comma-separated return values (shuffled return)
1850
+ while self._check(TokenType.COMMA):
1851
+ self._advance() # consume comma
1852
+ values.append(self._parse_expression())
1853
+
1728
1854
  self._match(TokenType.SEMICOLON)
1729
- return ASTNode('return', value=value)
1855
+
1856
+ if len(values) == 0:
1857
+ return ASTNode('return', value=None)
1858
+ elif len(values) == 1:
1859
+ return ASTNode('return', value=values[0])
1860
+ else:
1861
+ # Multiple return values - create tuple return
1862
+ return ASTNode('return', value={'multiple': True, 'values': values})
1863
+
1864
+ def _parse_super_function(self) -> ASTNode:
1865
+ """Parse super-function for .cssl-pl payload files.
1866
+
1867
+ Syntax:
1868
+ #$run(initFunction); // Call function at load time
1869
+ #$exec(setup()); // Execute expression at load time
1870
+ #$printl("Payload loaded"); // Print at load time
1871
+
1872
+ These are pre-execution hooks that run when payload() loads the file.
1873
+ """
1874
+ token = self._advance() # Get the SUPER_FUNC token
1875
+ super_name = token.value # e.g., "#$run", "#$exec", "#$printl"
1876
+
1877
+ # Parse the arguments
1878
+ self._expect(TokenType.PAREN_START)
1879
+ args = []
1880
+ if not self._check(TokenType.PAREN_END):
1881
+ args.append(self._parse_expression())
1882
+ while self._match(TokenType.COMMA):
1883
+ args.append(self._parse_expression())
1884
+ self._expect(TokenType.PAREN_END)
1885
+ self._match(TokenType.SEMICOLON)
1886
+
1887
+ return ASTNode('super_func', value={'name': super_name, 'args': args})
1730
1888
 
1731
1889
  def _parse_try(self) -> ASTNode:
1732
1890
  node = ASTNode('try', children=[])
@@ -1783,36 +1941,65 @@ class CSSLParser:
1783
1941
  self._expect(TokenType.BLOCK_END)
1784
1942
  return node
1785
1943
 
1786
- def _parse_injection_filter(self) -> Optional[dict]:
1787
- """Parse injection filter: [type::helper=value]"""
1788
- if not self._match(TokenType.BRACKET_START):
1944
+ def _parse_injection_filter(self) -> Optional[list]:
1945
+ """Parse injection filter(s): [type::helper=value] or [f1][f2][f3]...
1946
+
1947
+ Returns a list of filter dictionaries to support chained filters.
1948
+ """
1949
+ if not self._check(TokenType.BRACKET_START):
1789
1950
  return None
1790
1951
 
1791
- filter_info = {}
1792
- # Parse type::helper=value patterns
1793
- while not self._check(TokenType.BRACKET_END) and not self._is_at_end():
1794
- if self._check(TokenType.IDENTIFIER) or self._check(TokenType.KEYWORD):
1795
- filter_type = self._advance().value
1796
- if self._match(TokenType.DOUBLE_COLON):
1797
- helper = self._advance().value
1798
- if self._match(TokenType.EQUALS):
1799
- value = self._parse_expression()
1800
- filter_info[f'{filter_type}::{helper}'] = value
1952
+ filters = []
1953
+
1954
+ # Parse multiple consecutive filter brackets
1955
+ while self._match(TokenType.BRACKET_START):
1956
+ filter_info = {}
1957
+ # Parse type::helper=value patterns within this bracket
1958
+ while not self._check(TokenType.BRACKET_END) and not self._is_at_end():
1959
+ if self._check(TokenType.IDENTIFIER) or self._check(TokenType.KEYWORD):
1960
+ filter_type = self._advance().value
1961
+ if self._match(TokenType.DOUBLE_COLON):
1962
+ helper = self._advance().value
1963
+ if self._match(TokenType.EQUALS):
1964
+ value = self._parse_expression()
1965
+ filter_info[f'{filter_type}::{helper}'] = value
1966
+ else:
1967
+ filter_info[f'{filter_type}::{helper}'] = True
1801
1968
  else:
1802
- filter_info[f'{filter_type}::{helper}'] = True
1969
+ filter_info['type'] = filter_type
1970
+ elif self._check(TokenType.COMMA):
1971
+ self._advance()
1803
1972
  else:
1804
- filter_info['type'] = filter_type
1805
- elif self._check(TokenType.COMMA):
1806
- self._advance()
1807
- else:
1808
- break
1973
+ break
1809
1974
 
1810
- self._expect(TokenType.BRACKET_END)
1811
- return filter_info if filter_info else None
1975
+ self._expect(TokenType.BRACKET_END)
1976
+ if filter_info:
1977
+ filters.append(filter_info)
1978
+
1979
+ return filters if filters else None
1812
1980
 
1813
1981
  def _parse_expression_statement(self) -> Optional[ASTNode]:
1814
1982
  expr = self._parse_expression()
1815
1983
 
1984
+ # === TUPLE UNPACKING: a, b, c = shuffled_func() ===
1985
+ # Check if we have comma-separated identifiers before =
1986
+ if expr.type == 'identifier' and self._check(TokenType.COMMA):
1987
+ targets = [expr]
1988
+ while self._match(TokenType.COMMA):
1989
+ next_expr = self._parse_expression()
1990
+ if next_expr.type == 'identifier':
1991
+ targets.append(next_expr)
1992
+ else:
1993
+ # Not a simple identifier list, this is something else
1994
+ # Restore and fall through to normal parsing
1995
+ break
1996
+
1997
+ # Check if followed by =
1998
+ if self._match(TokenType.EQUALS):
1999
+ value = self._parse_expression()
2000
+ self._match(TokenType.SEMICOLON)
2001
+ return ASTNode('tuple_assignment', value={'targets': targets, 'value': value})
2002
+
1816
2003
  # === BASIC INJECTION: <== (replace target with source) ===
1817
2004
  if self._match(TokenType.INJECT_LEFT):
1818
2005
  # Check if this is a createcmd injection with a code block
@@ -2000,6 +2187,11 @@ class CSSLParser:
2000
2187
  elif self._match(TokenType.COMPARE_GE):
2001
2188
  right = self._parse_term()
2002
2189
  left = ASTNode('binary', value={'op': '>=', 'left': left, 'right': right})
2190
+ elif self._check(TokenType.KEYWORD) and self._peek().value == 'in':
2191
+ # 'in' operator for containment: item in list
2192
+ self._advance() # consume 'in'
2193
+ right = self._parse_term()
2194
+ left = ASTNode('binary', value={'op': 'in', 'left': left, 'right': right})
2003
2195
  else:
2004
2196
  break
2005
2197
 
@@ -2335,17 +2527,76 @@ class CSSLParser:
2335
2527
  self._expect(TokenType.COMPARE_GT) # consume >
2336
2528
  return ASTNode('instance_ref', value=instance_name)
2337
2529
 
2338
- # Check for type generic instantiation: stack<string>, vector<int>, etc.
2530
+ # Check for type generic instantiation: stack<string>, vector<int>, map<string, int>, etc.
2339
2531
  # This creates a new instance of the type with the specified element type
2340
2532
  if name in TYPE_GENERICS and self._check(TokenType.COMPARE_LT):
2341
2533
  self._advance() # consume <
2342
2534
  element_type = 'dynamic'
2535
+ value_type = None # For map<K, V>
2536
+
2343
2537
  if self._check(TokenType.KEYWORD) or self._check(TokenType.IDENTIFIER):
2344
2538
  element_type = self._advance().value
2539
+
2540
+ # Check for second type parameter (map<K, V>)
2541
+ if name == 'map' and self._check(TokenType.COMMA):
2542
+ self._advance() # consume ,
2543
+ if self._check(TokenType.KEYWORD) or self._check(TokenType.IDENTIFIER):
2544
+ value_type = self._advance().value
2545
+ else:
2546
+ value_type = 'dynamic'
2547
+
2345
2548
  self._expect(TokenType.COMPARE_GT) # consume >
2549
+
2550
+ # Check for inline initialization: map<K,V>{"key": "value", ...}
2551
+ init_values = None
2552
+ if self._check(TokenType.BLOCK_START):
2553
+ self._advance() # consume {
2554
+ init_values = {}
2555
+
2556
+ while not self._check(TokenType.BLOCK_END) and not self._is_at_end():
2557
+ # Parse key
2558
+ if self._check(TokenType.STRING):
2559
+ key = self._advance().value
2560
+ elif self._check(TokenType.IDENTIFIER):
2561
+ key = self._advance().value
2562
+ else:
2563
+ key = str(self._parse_expression().value) if hasattr(self._parse_expression(), 'value') else 'key'
2564
+
2565
+ # Expect : or =
2566
+ if self._check(TokenType.COLON):
2567
+ self._advance()
2568
+ elif self._check(TokenType.EQUALS):
2569
+ self._advance()
2570
+
2571
+ # Parse value
2572
+ value = self._parse_expression()
2573
+ init_values[key] = value
2574
+
2575
+ # Optional comma
2576
+ if self._check(TokenType.COMMA):
2577
+ self._advance()
2578
+
2579
+ self._expect(TokenType.BLOCK_END) # consume }
2580
+
2581
+ # Check for array-style initialization: vector<int>[1, 2, 3], array<string>["a", "b"]
2582
+ elif self._check(TokenType.BRACKET_START):
2583
+ self._advance() # consume [
2584
+ init_values = []
2585
+
2586
+ while not self._check(TokenType.BRACKET_END) and not self._is_at_end():
2587
+ init_values.append(self._parse_expression())
2588
+
2589
+ # Optional comma
2590
+ if self._check(TokenType.COMMA):
2591
+ self._advance()
2592
+
2593
+ self._expect(TokenType.BRACKET_END) # consume ]
2594
+
2346
2595
  return ASTNode('type_instantiation', value={
2347
2596
  'type': name,
2348
- 'element_type': element_type
2597
+ 'element_type': element_type,
2598
+ 'value_type': value_type,
2599
+ 'init_values': init_values
2349
2600
  })
2350
2601
 
2351
2602
  # Check for type-parameterized function call: OpenFind<string>(0)