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.
@@ -216,6 +216,9 @@ class CSSLLexer:
216
216
  self.column = 1
217
217
  elif char in '"\'':
218
218
  self._read_string(char)
219
+ elif char == '`':
220
+ # Raw string (no escape processing) - useful for JSON
221
+ self._read_raw_string()
219
222
  elif char.isdigit() or (char == '-' and self._peek(1).isdigit()):
220
223
  self._read_number()
221
224
  elif char == 'r' and self._peek(1) == '@':
@@ -224,7 +227,7 @@ class CSSLLexer:
224
227
  elif char == 's' and self._peek(1) == '@':
225
228
  # s@<name> self-reference to global struct
226
229
  self._read_self_ref()
227
- elif char.isalpha() or char == '_' or char == '-':
230
+ elif char.isalpha() or char == '_':
228
231
  self._read_identifier()
229
232
  elif char == '@':
230
233
  self._add_token(TokenType.AT, '@')
@@ -346,13 +349,52 @@ class CSSLLexer:
346
349
  def _read_string(self, quote_char: str):
347
350
  self._advance()
348
351
  start = self.pos
352
+ result = []
349
353
  while self.pos < len(self.source) and self.source[self.pos] != quote_char:
350
- if self.source[self.pos] == '\\':
354
+ if self.source[self.pos] == '\\' and self.pos + 1 < len(self.source):
355
+ # Handle escape sequences
356
+ next_char = self.source[self.pos + 1]
357
+ if next_char == 'n':
358
+ result.append('\n')
359
+ elif next_char == 't':
360
+ result.append('\t')
361
+ elif next_char == 'r':
362
+ result.append('\r')
363
+ elif next_char == '\\':
364
+ result.append('\\')
365
+ elif next_char == quote_char:
366
+ result.append(quote_char)
367
+ elif next_char == '"':
368
+ result.append('"')
369
+ elif next_char == "'":
370
+ result.append("'")
371
+ else:
372
+ result.append(self.source[self.pos])
373
+ result.append(next_char)
374
+ self._advance()
375
+ self._advance()
376
+ else:
377
+ result.append(self.source[self.pos])
351
378
  self._advance()
379
+ value = ''.join(result)
380
+ self._add_token(TokenType.STRING, value)
381
+ self._advance()
382
+
383
+ def _read_raw_string(self):
384
+ """Read raw string with backticks - no escape processing.
385
+
386
+ Useful for JSON: `{"id": "2819e1", "name": "test"}`
387
+ """
388
+ self._advance() # Skip opening backtick
389
+ start = self.pos
390
+ while self.pos < len(self.source) and self.source[self.pos] != '`':
391
+ if self.source[self.pos] == '\n':
392
+ self.line += 1
393
+ self.column = 0
352
394
  self._advance()
353
395
  value = self.source[start:self.pos]
354
396
  self._add_token(TokenType.STRING, value)
355
- self._advance()
397
+ self._advance() # Skip closing backtick
356
398
 
357
399
  def _read_number(self):
358
400
  start = self.pos
@@ -368,7 +410,7 @@ class CSSLLexer:
368
410
 
369
411
  def _read_identifier(self):
370
412
  start = self.pos
371
- while self.pos < len(self.source) and (self.source[self.pos].isalnum() or self.source[self.pos] in '_-'):
413
+ while self.pos < len(self.source) and (self.source[self.pos].isalnum() or self.source[self.pos] == '_'):
372
414
  self._advance()
373
415
  value = self.source[start:self.pos]
374
416
 
@@ -588,6 +630,286 @@ class CSSLParser:
588
630
  self._match(TokenType.BLOCK_END)
589
631
  return root
590
632
 
633
+ def _is_function_modifier(self, value: str) -> bool:
634
+ """Check if a keyword is a function modifier"""
635
+ return value in ('undefined', 'open', 'meta', 'super', 'closed', 'private', 'virtual', 'sqlbased')
636
+
637
+ def _is_type_keyword(self, value: str) -> bool:
638
+ """Check if a keyword is a type declaration"""
639
+ return value in ('int', 'string', 'float', 'bool', 'void', 'json', 'array', 'vector', 'stack',
640
+ 'dynamic', 'datastruct', 'dataspace', 'shuffled', 'iterator', 'combo', 'structure')
641
+
642
+ def _looks_like_function_declaration(self) -> bool:
643
+ """Check if current position looks like a C-style function declaration.
644
+
645
+ Patterns:
646
+ - int funcName(...)
647
+ - undefined int funcName(...)
648
+ - vector<string> funcName(...)
649
+ - undefined void funcName(...)
650
+ """
651
+ saved_pos = self.pos
652
+
653
+ # Skip modifiers (undefined, open, meta, super, closed, private, virtual)
654
+ while self._check(TokenType.KEYWORD) and self._is_function_modifier(self._current().value):
655
+ self._advance()
656
+
657
+ # Check for type keyword
658
+ if self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value):
659
+ self._advance()
660
+
661
+ # Skip generic type parameters <T>
662
+ if self._check(TokenType.COMPARE_LT):
663
+ depth = 1
664
+ self._advance()
665
+ while depth > 0 and not self._is_at_end():
666
+ if self._check(TokenType.COMPARE_LT):
667
+ depth += 1
668
+ elif self._check(TokenType.COMPARE_GT):
669
+ depth -= 1
670
+ self._advance()
671
+
672
+ # Check for identifier followed by (
673
+ if self._check(TokenType.IDENTIFIER):
674
+ self._advance()
675
+ is_func = self._check(TokenType.PAREN_START)
676
+ self.pos = saved_pos
677
+ return is_func
678
+
679
+ self.pos = saved_pos
680
+ return False
681
+
682
+ def _looks_like_typed_variable(self) -> bool:
683
+ """Check if current position looks like a typed variable declaration.
684
+
685
+ Patterns:
686
+ - int x;
687
+ - stack<string> myStack;
688
+ - vector<int> nums = [1,2,3];
689
+
690
+ Distinguishes from function declarations by checking for '(' after identifier.
691
+ """
692
+ saved_pos = self.pos
693
+
694
+ # Check for type keyword
695
+ if self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value):
696
+ self._advance()
697
+
698
+ # Skip generic type parameters <T>
699
+ if self._check(TokenType.COMPARE_LT):
700
+ depth = 1
701
+ self._advance()
702
+ while depth > 0 and not self._is_at_end():
703
+ if self._check(TokenType.COMPARE_LT):
704
+ depth += 1
705
+ elif self._check(TokenType.COMPARE_GT):
706
+ depth -= 1
707
+ self._advance()
708
+
709
+ # Check for identifier NOT followed by ( (that would be a function)
710
+ if self._check(TokenType.IDENTIFIER):
711
+ self._advance()
712
+ # If followed by '(' it's a function, not a variable
713
+ is_var = not self._check(TokenType.PAREN_START)
714
+ self.pos = saved_pos
715
+ return is_var
716
+
717
+ self.pos = saved_pos
718
+ return False
719
+
720
+ def _parse_typed_function(self) -> ASTNode:
721
+ """Parse C-style typed function declaration.
722
+
723
+ Patterns:
724
+ - int Add(int a, int b) { }
725
+ - undefined int Func() { }
726
+ - open void Handler(open Params) { }
727
+ - vector<string> GetNames() { }
728
+ """
729
+ modifiers = []
730
+ return_type = None
731
+ generic_type = None
732
+
733
+ # Collect modifiers (undefined, open, meta, super, closed, private, virtual)
734
+ while self._check(TokenType.KEYWORD) and self._is_function_modifier(self._current().value):
735
+ modifiers.append(self._advance().value)
736
+
737
+ # Get return type
738
+ if self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value):
739
+ return_type = self._advance().value
740
+
741
+ # Check for generic type <T>
742
+ if self._check(TokenType.COMPARE_LT):
743
+ self._advance() # skip <
744
+ generic_parts = []
745
+ depth = 1
746
+ while depth > 0 and not self._is_at_end():
747
+ if self._check(TokenType.COMPARE_LT):
748
+ depth += 1
749
+ generic_parts.append('<')
750
+ elif self._check(TokenType.COMPARE_GT):
751
+ depth -= 1
752
+ if depth > 0:
753
+ generic_parts.append('>')
754
+ elif self._check(TokenType.COMMA):
755
+ generic_parts.append(',')
756
+ else:
757
+ generic_parts.append(self._current().value)
758
+ self._advance()
759
+ generic_type = ''.join(generic_parts)
760
+
761
+ # Get function name
762
+ name = self._advance().value
763
+
764
+ # Parse parameters
765
+ params = []
766
+ self._expect(TokenType.PAREN_START)
767
+
768
+ while not self._check(TokenType.PAREN_END) and not self._is_at_end():
769
+ param_info = {}
770
+
771
+ # Handle 'open' keyword for open parameters
772
+ if self._match_keyword('open'):
773
+ param_info['open'] = True
774
+
775
+ # Handle type annotations
776
+ if self._check(TokenType.KEYWORD) and self._is_type_keyword(self._current().value):
777
+ param_info['type'] = self._advance().value
778
+
779
+ # Check for generic type parameter <T>
780
+ if self._check(TokenType.COMPARE_LT):
781
+ self._advance()
782
+ generic_parts = []
783
+ depth = 1
784
+ while depth > 0 and not self._is_at_end():
785
+ if self._check(TokenType.COMPARE_LT):
786
+ depth += 1
787
+ generic_parts.append('<')
788
+ elif self._check(TokenType.COMPARE_GT):
789
+ depth -= 1
790
+ if depth > 0:
791
+ generic_parts.append('>')
792
+ elif self._check(TokenType.COMMA):
793
+ generic_parts.append(',')
794
+ else:
795
+ generic_parts.append(self._current().value)
796
+ self._advance()
797
+ param_info['generic'] = ''.join(generic_parts)
798
+
799
+ # Handle reference operator &
800
+ if self._match(TokenType.AMPERSAND):
801
+ param_info['ref'] = True
802
+
803
+ # Get parameter name
804
+ if self._check(TokenType.IDENTIFIER):
805
+ param_name = self._advance().value
806
+ if param_info:
807
+ params.append({'name': param_name, **param_info})
808
+ else:
809
+ params.append(param_name)
810
+ elif self._check(TokenType.KEYWORD):
811
+ # Parameter name could be a keyword
812
+ param_name = self._advance().value
813
+ if param_info:
814
+ params.append({'name': param_name, **param_info})
815
+ else:
816
+ params.append(param_name)
817
+
818
+ self._match(TokenType.COMMA)
819
+
820
+ self._expect(TokenType.PAREN_END)
821
+
822
+ # Parse function body
823
+ node = ASTNode('function', value={
824
+ 'name': name,
825
+ 'params': params,
826
+ 'return_type': return_type,
827
+ 'generic_type': generic_type,
828
+ 'modifiers': modifiers
829
+ }, children=[])
830
+
831
+ self._expect(TokenType.BLOCK_START)
832
+
833
+ while not self._check(TokenType.BLOCK_END) and not self._is_at_end():
834
+ stmt = self._parse_statement()
835
+ if stmt:
836
+ node.children.append(stmt)
837
+
838
+ self._expect(TokenType.BLOCK_END)
839
+ return node
840
+
841
+ def _looks_like_typed_variable(self) -> bool:
842
+ """Check if current position looks like a typed variable declaration:
843
+ type_name varName; or type_name<T> varName; or type_name varName = value;
844
+ """
845
+ # Save position
846
+ saved_pos = self.pos
847
+
848
+ # Must start with a type keyword (int, string, stack, vector, etc.)
849
+ if not self._check(TokenType.KEYWORD):
850
+ return False
851
+
852
+ type_name = self._current().value
853
+
854
+ # Skip known type keywords
855
+ type_keywords = {'int', 'string', 'float', 'bool', 'dynamic', 'void',
856
+ 'stack', 'vector', 'datastruct', 'dataspace', 'shuffled',
857
+ 'iterator', 'combo', 'array', 'openquote', 'json'}
858
+ if type_name not in type_keywords:
859
+ return False
860
+
861
+ self._advance()
862
+
863
+ # Check for optional generic <T>
864
+ if self._match(TokenType.COMPARE_LT):
865
+ # Skip until >
866
+ depth = 1
867
+ while depth > 0 and not self._is_at_end():
868
+ if self._check(TokenType.COMPARE_LT):
869
+ depth += 1
870
+ elif self._check(TokenType.COMPARE_GT):
871
+ depth -= 1
872
+ self._advance()
873
+
874
+ # Next should be an identifier (variable name), not '(' (function) or ';'
875
+ result = self._check(TokenType.IDENTIFIER)
876
+
877
+ # Restore position
878
+ self.pos = saved_pos
879
+ return result
880
+
881
+ def _parse_typed_variable(self) -> Optional[ASTNode]:
882
+ """Parse a typed variable declaration: type varName; or type<T> varName = value;"""
883
+ # Get type name
884
+ type_name = self._advance().value # Consume type keyword
885
+
886
+ # Check for generic type <T>
887
+ element_type = None
888
+ if self._match(TokenType.COMPARE_LT):
889
+ # Get element type
890
+ if self._check(TokenType.KEYWORD) or self._check(TokenType.IDENTIFIER):
891
+ element_type = self._advance().value
892
+ self._expect(TokenType.COMPARE_GT)
893
+
894
+ # Get variable name
895
+ if not self._check(TokenType.IDENTIFIER):
896
+ return None
897
+ var_name = self._advance().value
898
+
899
+ # Check for assignment or just declaration
900
+ value = None
901
+ if self._match(TokenType.EQUALS):
902
+ value = self._parse_expression()
903
+
904
+ self._match(TokenType.SEMICOLON)
905
+
906
+ return ASTNode('typed_declaration', value={
907
+ 'type': type_name,
908
+ 'element_type': element_type,
909
+ 'name': var_name,
910
+ 'value': value
911
+ })
912
+
591
913
  def parse_program(self) -> ASTNode:
592
914
  """Parse a standalone program (no service wrapper)"""
593
915
  root = ASTNode('program', children=[])
@@ -597,6 +919,39 @@ class CSSLParser:
597
919
  root.children.append(self._parse_struct())
598
920
  elif self._match_keyword('define'):
599
921
  root.children.append(self._parse_define())
922
+ # Check for C-style typed function declarations
923
+ elif self._looks_like_function_declaration():
924
+ root.children.append(self._parse_typed_function())
925
+ # Check for typed variable declarations (int x;, stack<string> s;)
926
+ elif self._looks_like_typed_variable():
927
+ decl = self._parse_typed_variable()
928
+ if decl:
929
+ root.children.append(decl)
930
+ # Handle service blocks
931
+ elif self._match_keyword('service-init'):
932
+ root.children.append(self._parse_service_init())
933
+ elif self._match_keyword('service-include'):
934
+ root.children.append(self._parse_service_include())
935
+ elif self._match_keyword('service-run'):
936
+ root.children.append(self._parse_service_run())
937
+ elif self._match_keyword('package'):
938
+ root.children.append(self._parse_package())
939
+ elif self._match_keyword('package-includes'):
940
+ root.children.append(self._parse_package_includes())
941
+ # Handle global declarations
942
+ elif self._match_keyword('global'):
943
+ stmt = self._parse_expression_statement()
944
+ if stmt:
945
+ # Wrap in global_assignment to mark as global variable
946
+ global_stmt = ASTNode('global_assignment', value=stmt)
947
+ root.children.append(global_stmt)
948
+ elif self._check(TokenType.GLOBAL_REF):
949
+ stmt = self._parse_expression_statement()
950
+ if stmt:
951
+ # Wrap in global_assignment to mark as global variable (same as 'global' keyword)
952
+ global_stmt = ASTNode('global_assignment', value=stmt)
953
+ root.children.append(global_stmt)
954
+ # Handle statements
600
955
  elif self._check(TokenType.IDENTIFIER) or self._check(TokenType.AT) or self._check(TokenType.SELF_REF):
601
956
  stmt = self._parse_expression_statement()
602
957
  if stmt:
@@ -609,6 +964,9 @@ class CSSLParser:
609
964
  root.children.append(self._parse_for())
610
965
  elif self._match_keyword('foreach'):
611
966
  root.children.append(self._parse_foreach())
967
+ # Skip comments and newlines
968
+ elif self._check(TokenType.COMMENT) or self._check(TokenType.NEWLINE):
969
+ self._advance()
612
970
  else:
613
971
  self._advance()
614
972
 
@@ -837,8 +1195,31 @@ class CSSLParser:
837
1195
 
838
1196
  if self._match(TokenType.PAREN_START):
839
1197
  while not self._check(TokenType.PAREN_END):
1198
+ param_info = {}
1199
+ # Handle 'open' keyword for open parameters
1200
+ if self._match_keyword('open'):
1201
+ param_info['open'] = True
1202
+ # Handle type annotations (e.g., string, int, dynamic, etc.)
1203
+ if self._check(TokenType.KEYWORD):
1204
+ param_info['type'] = self._advance().value
1205
+ # Handle reference operator &
1206
+ if self._match(TokenType.AMPERSAND):
1207
+ param_info['ref'] = True
1208
+ # Get parameter name
840
1209
  if self._check(TokenType.IDENTIFIER):
841
- params.append(self._advance().value)
1210
+ param_name = self._advance().value
1211
+ if param_info:
1212
+ params.append({'name': param_name, **param_info})
1213
+ else:
1214
+ params.append(param_name)
1215
+ self._match(TokenType.COMMA)
1216
+ elif self._check(TokenType.KEYWORD):
1217
+ # Parameter name could be a keyword like 'Params'
1218
+ param_name = self._advance().value
1219
+ if param_info:
1220
+ params.append({'name': param_name, **param_info})
1221
+ else:
1222
+ params.append(param_name)
842
1223
  self._match(TokenType.COMMA)
843
1224
  else:
844
1225
  break
@@ -878,6 +1259,15 @@ class CSSLParser:
878
1259
  return self._parse_try()
879
1260
  elif self._match_keyword('await'):
880
1261
  return self._parse_await()
1262
+ elif self._match_keyword('define'):
1263
+ # Nested define function
1264
+ return self._parse_define()
1265
+ elif self._looks_like_typed_variable():
1266
+ # Typed variable declaration (e.g., stack<string> myStack;)
1267
+ return self._parse_typed_variable()
1268
+ elif self._looks_like_function_declaration():
1269
+ # Nested typed function (e.g., void Level2() { ... })
1270
+ return self._parse_typed_function()
881
1271
  elif self._check(TokenType.IDENTIFIER) or self._check(TokenType.AT):
882
1272
  return self._parse_expression_statement()
883
1273
  else:
@@ -1077,6 +1467,9 @@ class CSSLParser:
1077
1467
  # Check for define statements inside action block
1078
1468
  if self._match_keyword('define'):
1079
1469
  node.children.append(self._parse_define())
1470
+ # Check for typed function definitions (nested functions)
1471
+ elif self._looks_like_function_declaration():
1472
+ node.children.append(self._parse_typed_function())
1080
1473
  else:
1081
1474
  stmt = self._parse_statement()
1082
1475
  if stmt:
@@ -1320,12 +1713,39 @@ class CSSLParser:
1320
1713
  if self._match(TokenType.MINUS):
1321
1714
  operand = self._parse_unary()
1322
1715
  return ASTNode('unary', value={'op': '-', 'operand': operand})
1716
+ if self._match(TokenType.AMPERSAND):
1717
+ # Reference operator: &variable or &@module
1718
+ operand = self._parse_unary()
1719
+ return ASTNode('reference', value=operand)
1323
1720
 
1324
1721
  return self._parse_primary()
1325
1722
 
1326
1723
  def _parse_primary(self) -> ASTNode:
1327
1724
  if self._match(TokenType.AT):
1328
- return self._parse_module_reference()
1725
+ node = self._parse_module_reference()
1726
+ # Continue to check for calls, indexing, member access on module refs
1727
+ while True:
1728
+ if self._match(TokenType.PAREN_START):
1729
+ # Function call on module ref: @Module.method()
1730
+ args = []
1731
+ while not self._check(TokenType.PAREN_END) and not self._is_at_end():
1732
+ args.append(self._parse_expression())
1733
+ if not self._check(TokenType.PAREN_END):
1734
+ self._expect(TokenType.COMMA)
1735
+ self._expect(TokenType.PAREN_END)
1736
+ node = ASTNode('call', value={'callee': node, 'args': args})
1737
+ elif self._match(TokenType.DOT):
1738
+ # Member access: @Module.property
1739
+ member = self._advance().value
1740
+ node = ASTNode('member_access', value={'object': node, 'member': member})
1741
+ elif self._match(TokenType.BRACKET_START):
1742
+ # Index access: @Module[index]
1743
+ index = self._parse_expression()
1744
+ self._expect(TokenType.BRACKET_END)
1745
+ node = ASTNode('index_access', value={'object': node, 'index': index})
1746
+ else:
1747
+ break
1748
+ return node
1329
1749
 
1330
1750
  if self._check(TokenType.SELF_REF):
1331
1751
  # s@<name> self-reference to global struct
@@ -1342,6 +1762,31 @@ class CSSLParser:
1342
1762
  node = ASTNode('call', value={'callee': node, 'args': args})
1343
1763
  return node
1344
1764
 
1765
+ if self._check(TokenType.GLOBAL_REF):
1766
+ # r@<name> global variable reference/declaration
1767
+ token = self._advance()
1768
+ node = ASTNode('global_ref', value=token.value, line=token.line, column=token.column)
1769
+ # Check for member access, calls, indexing
1770
+ while True:
1771
+ if self._match(TokenType.PAREN_START):
1772
+ args = []
1773
+ while not self._check(TokenType.PAREN_END):
1774
+ args.append(self._parse_expression())
1775
+ if not self._check(TokenType.PAREN_END):
1776
+ self._expect(TokenType.COMMA)
1777
+ self._expect(TokenType.PAREN_END)
1778
+ node = ASTNode('call', value={'callee': node, 'args': args})
1779
+ elif self._match(TokenType.DOT):
1780
+ member = self._advance().value
1781
+ node = ASTNode('member_access', value={'object': node, 'member': member})
1782
+ elif self._match(TokenType.BRACKET_START):
1783
+ index = self._parse_expression()
1784
+ self._expect(TokenType.BRACKET_END)
1785
+ node = ASTNode('index_access', value={'object': node, 'index': index})
1786
+ else:
1787
+ break
1788
+ return node
1789
+
1345
1790
  if self._check(TokenType.NUMBER):
1346
1791
  return ASTNode('literal', value=self._advance().value)
1347
1792