IncludeCPP 3.6.0__py3-none-any.whl → 3.7.1__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.
@@ -101,6 +101,7 @@ class TokenType(Enum):
101
101
  SELF_REF = auto() # s@<name> self-reference to global struct
102
102
  SHARED_REF = auto() # $<name> shared object reference
103
103
  CAPTURED_REF = auto() # %<name> captured reference (for infusion)
104
+ THIS_REF = auto() # this-><name> class member reference
104
105
  PACKAGE = auto()
105
106
  PACKAGE_INCLUDES = auto()
106
107
  AS = auto()
@@ -111,7 +112,7 @@ class TokenType(Enum):
111
112
 
112
113
  KEYWORDS = {
113
114
  # Service structure
114
- 'service-init', 'service-run', 'service-include', 'struct', 'define', 'main',
115
+ 'service-init', 'service-run', 'service-include', 'struct', 'define', 'main', 'class', 'new', 'this',
115
116
  # Control flow
116
117
  'if', 'else', 'elif', 'while', 'for', 'foreach', 'in', 'range',
117
118
  'switch', 'case', 'default', 'break', 'continue', 'return',
@@ -126,7 +127,7 @@ KEYWORDS = {
126
127
  'package', 'package-includes', 'exec', 'as', 'global',
127
128
  # CSSL Type Keywords
128
129
  'int', 'string', 'float', 'bool', 'void', 'json', 'array', 'vector', 'stack',
129
- 'list', 'dictionary', 'dict', # Python-like types
130
+ 'list', 'dictionary', 'dict', 'instance', 'map', # Python-like types
130
131
  'dynamic', # No type declaration (slow but flexible)
131
132
  'undefined', # Function errors ignored
132
133
  'open', # Accept any parameter type
@@ -154,7 +155,7 @@ TYPE_LITERALS = {'list', 'dict'}
154
155
  # Generic type keywords that use <T> syntax
155
156
  TYPE_GENERICS = {
156
157
  'datastruct', 'dataspace', 'shuffled', 'iterator', 'combo',
157
- 'vector', 'stack', 'array', 'openquote', 'list', 'dictionary'
158
+ 'vector', 'stack', 'array', 'openquote', 'list', 'dictionary', 'map'
158
159
  }
159
160
 
160
161
  # Functions that accept type parameters: FuncName<type>(args)
@@ -679,7 +680,7 @@ class CSSLParser:
679
680
  def _is_type_keyword(self, value: str) -> bool:
680
681
  """Check if a keyword is a type declaration"""
681
682
  return value in ('int', 'string', 'float', 'bool', 'void', 'json', 'array', 'vector', 'stack',
682
- 'list', 'dictionary', 'dict',
683
+ 'list', 'dictionary', 'dict', 'instance', 'map',
683
684
  'dynamic', 'datastruct', 'dataspace', 'shuffled', 'iterator', 'combo', 'structure')
684
685
 
685
686
  def _looks_like_function_declaration(self) -> bool:
@@ -898,7 +899,7 @@ class CSSLParser:
898
899
  type_keywords = {'int', 'string', 'float', 'bool', 'dynamic', 'void',
899
900
  'stack', 'vector', 'datastruct', 'dataspace', 'shuffled',
900
901
  'iterator', 'combo', 'array', 'openquote', 'json',
901
- 'list', 'dictionary', 'dict'}
902
+ 'list', 'dictionary', 'dict', 'instance', 'map'}
902
903
  if type_name not in type_keywords:
903
904
  return False
904
905
 
@@ -927,11 +928,13 @@ class CSSLParser:
927
928
  # Get type name
928
929
  type_name = self._advance().value # Consume type keyword
929
930
 
930
- # Check for generic type <T>
931
+ # Check for generic type <T> or instance<"name">
931
932
  element_type = None
932
933
  if self._match(TokenType.COMPARE_LT):
933
- # Get element type
934
- if self._check(TokenType.KEYWORD) or self._check(TokenType.IDENTIFIER):
934
+ # For instance<"name">, element_type can be a string literal
935
+ if type_name == 'instance' and self._check(TokenType.STRING):
936
+ element_type = self._advance().value
937
+ elif self._check(TokenType.KEYWORD) or self._check(TokenType.IDENTIFIER):
935
938
  element_type = self._advance().value
936
939
  self._expect(TokenType.COMPARE_GT)
937
940
 
@@ -947,6 +950,14 @@ class CSSLParser:
947
950
 
948
951
  self._match(TokenType.SEMICOLON)
949
952
 
953
+ # For instance<"name">, create a special node type
954
+ if type_name == 'instance':
955
+ return ASTNode('instance_declaration', value={
956
+ 'instance_name': element_type,
957
+ 'name': var_name,
958
+ 'value': value
959
+ })
960
+
950
961
  return ASTNode('typed_declaration', value={
951
962
  'type': type_name,
952
963
  'element_type': element_type,
@@ -961,6 +972,8 @@ class CSSLParser:
961
972
  while not self._is_at_end():
962
973
  if self._match_keyword('struct'):
963
974
  root.children.append(self._parse_struct())
975
+ elif self._match_keyword('class'):
976
+ root.children.append(self._parse_class())
964
977
  elif self._match_keyword('define'):
965
978
  root.children.append(self._parse_define())
966
979
  # Check for C-style typed function declarations
@@ -1233,6 +1246,58 @@ class CSSLParser:
1233
1246
  self._expect(TokenType.BLOCK_END)
1234
1247
  return node
1235
1248
 
1249
+ def _parse_class(self) -> ASTNode:
1250
+ """Parse class declaration with members and methods.
1251
+
1252
+ Syntax:
1253
+ class ClassName {
1254
+ string name;
1255
+ int age;
1256
+
1257
+ void ClassName(string n) { this->name = n; }
1258
+
1259
+ void sayHello() {
1260
+ printl("Hello " + this->name);
1261
+ }
1262
+ }
1263
+ """
1264
+ class_name = self._advance().value
1265
+
1266
+ node = ASTNode('class', value={'name': class_name}, children=[])
1267
+ self._expect(TokenType.BLOCK_START)
1268
+
1269
+ while not self._check(TokenType.BLOCK_END) and not self._is_at_end():
1270
+ # Check for typed function (method) declaration
1271
+ if self._looks_like_function_declaration():
1272
+ method = self._parse_typed_function()
1273
+ method_info = method.value
1274
+ method_name = method_info.get('name')
1275
+
1276
+ # Mark constructor (same name as class or __init__)
1277
+ if method_name == class_name or method_name == '__init__':
1278
+ method.value['is_constructor'] = True
1279
+
1280
+ node.children.append(method)
1281
+
1282
+ # Check for typed member variable declaration
1283
+ elif self._looks_like_typed_variable():
1284
+ member = self._parse_typed_variable()
1285
+ if member:
1286
+ # Mark as class member
1287
+ member.value['is_member'] = True
1288
+ node.children.append(member)
1289
+
1290
+ # Check for define-style method
1291
+ elif self._match_keyword('define'):
1292
+ method = self._parse_define()
1293
+ node.children.append(method)
1294
+
1295
+ else:
1296
+ self._advance()
1297
+
1298
+ self._expect(TokenType.BLOCK_END)
1299
+ return node
1300
+
1236
1301
  def _parse_define(self) -> ASTNode:
1237
1302
  name = self._advance().value
1238
1303
  params = []
@@ -1314,7 +1379,8 @@ class CSSLParser:
1314
1379
  return self._parse_typed_function()
1315
1380
  elif (self._check(TokenType.IDENTIFIER) or self._check(TokenType.AT) or
1316
1381
  self._check(TokenType.CAPTURED_REF) or self._check(TokenType.SHARED_REF) or
1317
- self._check(TokenType.GLOBAL_REF) or self._check(TokenType.SELF_REF)):
1382
+ self._check(TokenType.GLOBAL_REF) or self._check(TokenType.SELF_REF) or
1383
+ (self._check(TokenType.KEYWORD) and self._current().value in ('this', 'new'))):
1318
1384
  return self._parse_expression_statement()
1319
1385
  else:
1320
1386
  self._advance()
@@ -1782,14 +1848,14 @@ class CSSLParser:
1782
1848
  if self._check(TokenType.BRACKET_START):
1783
1849
  # Peek ahead to see if this is an index [n] or a filter [type::helper=...]
1784
1850
  # Only consume if it's a simple number index
1785
- saved_pos = self._current
1851
+ saved_pos = self.pos
1786
1852
  self._advance() # consume [
1787
1853
  if self._check(TokenType.NUMBER):
1788
1854
  remove_index = int(self._advance().value)
1789
1855
  self._expect(TokenType.BRACKET_END)
1790
1856
  else:
1791
1857
  # Not a number - restore position for filter parsing
1792
- self._current = saved_pos
1858
+ self.pos = saved_pos
1793
1859
 
1794
1860
  filter_info = self._parse_injection_filter()
1795
1861
  source = self._parse_expression()
@@ -1824,14 +1890,14 @@ class CSSLParser:
1824
1890
  remove_index = None
1825
1891
  if self._check(TokenType.BRACKET_START):
1826
1892
  # Peek ahead to see if this is an index [n] or something else
1827
- saved_pos = self._current
1893
+ saved_pos = self.pos
1828
1894
  self._advance() # consume [
1829
1895
  if self._check(TokenType.NUMBER):
1830
1896
  remove_index = int(self._advance().value)
1831
1897
  self._expect(TokenType.BRACKET_END)
1832
1898
  else:
1833
1899
  # Not a number - restore position
1834
- self._current = saved_pos
1900
+ self.pos = saved_pos
1835
1901
 
1836
1902
  if self._check(TokenType.BLOCK_START):
1837
1903
  code_block = self._parse_action_block()
@@ -1987,19 +2053,75 @@ class CSSLParser:
1987
2053
  return self._parse_primary()
1988
2054
 
1989
2055
  def _parse_primary(self) -> ASTNode:
2056
+ # Handle 'this->' member access
2057
+ if self._check(TokenType.KEYWORD) and self._current().value == 'this':
2058
+ self._advance() # consume 'this'
2059
+ if self._match(TokenType.FLOW_RIGHT): # ->
2060
+ member = self._advance().value
2061
+ node = ASTNode('this_access', value={'member': member})
2062
+ # Continue to check for calls, member access, indexing
2063
+ while True:
2064
+ if self._match(TokenType.PAREN_START):
2065
+ # Method call: this->method()
2066
+ args, kwargs = self._parse_call_arguments()
2067
+ self._expect(TokenType.PAREN_END)
2068
+ node = ASTNode('call', value={'callee': node, 'args': args, 'kwargs': kwargs})
2069
+ elif self._match(TokenType.DOT):
2070
+ # Chained access: this->obj.method
2071
+ member = self._advance().value
2072
+ node = ASTNode('member_access', value={'object': node, 'member': member})
2073
+ elif self._match(TokenType.BRACKET_START):
2074
+ # Index access: this->arr[0]
2075
+ index = self._parse_expression()
2076
+ self._expect(TokenType.BRACKET_END)
2077
+ node = ASTNode('index_access', value={'object': node, 'index': index})
2078
+ elif self._match(TokenType.FLOW_RIGHT):
2079
+ # Chained this->a->b style access
2080
+ member = self._advance().value
2081
+ node = ASTNode('this_access', value={'member': member, 'object': node})
2082
+ else:
2083
+ break
2084
+ return node
2085
+ else:
2086
+ # Just 'this' keyword alone - return as identifier for now
2087
+ return ASTNode('identifier', value='this')
2088
+
2089
+ # Handle 'new ClassName(args)' instantiation
2090
+ if self._check(TokenType.KEYWORD) and self._current().value == 'new':
2091
+ self._advance() # consume 'new'
2092
+ class_name = self._advance().value # get class name
2093
+ args = []
2094
+ kwargs = {}
2095
+ if self._match(TokenType.PAREN_START):
2096
+ args, kwargs = self._parse_call_arguments()
2097
+ self._expect(TokenType.PAREN_END)
2098
+ node = ASTNode('new', value={'class': class_name, 'args': args, 'kwargs': kwargs})
2099
+ # Continue to check for member access, calls on the new object
2100
+ while True:
2101
+ if self._match(TokenType.DOT):
2102
+ member = self._advance().value
2103
+ node = ASTNode('member_access', value={'object': node, 'member': member})
2104
+ if self._match(TokenType.PAREN_START):
2105
+ args, kwargs = self._parse_call_arguments()
2106
+ self._expect(TokenType.PAREN_END)
2107
+ node = ASTNode('call', value={'callee': node, 'args': args, 'kwargs': kwargs})
2108
+ elif self._match(TokenType.BRACKET_START):
2109
+ index = self._parse_expression()
2110
+ self._expect(TokenType.BRACKET_END)
2111
+ node = ASTNode('index_access', value={'object': node, 'index': index})
2112
+ else:
2113
+ break
2114
+ return node
2115
+
1990
2116
  if self._match(TokenType.AT):
1991
2117
  node = self._parse_module_reference()
1992
2118
  # Continue to check for calls, indexing, member access on module refs
1993
2119
  while True:
1994
2120
  if self._match(TokenType.PAREN_START):
1995
- # Function call on module ref: @Module.method()
1996
- args = []
1997
- while not self._check(TokenType.PAREN_END) and not self._is_at_end():
1998
- args.append(self._parse_expression())
1999
- if not self._check(TokenType.PAREN_END):
2000
- self._expect(TokenType.COMMA)
2121
+ # Function call on module ref: @Module.method() - with kwargs support
2122
+ args, kwargs = self._parse_call_arguments()
2001
2123
  self._expect(TokenType.PAREN_END)
2002
- node = ASTNode('call', value={'callee': node, 'args': args})
2124
+ node = ASTNode('call', value={'callee': node, 'args': args, 'kwargs': kwargs})
2003
2125
  elif self._match(TokenType.DOT):
2004
2126
  # Member access: @Module.property
2005
2127
  member = self._advance().value
@@ -2017,31 +2139,23 @@ class CSSLParser:
2017
2139
  # s@<name> self-reference to global struct
2018
2140
  token = self._advance()
2019
2141
  node = ASTNode('self_ref', value=token.value, line=token.line, column=token.column)
2020
- # Check for function call: s@Backend.Loop.Start()
2142
+ # Check for function call: s@Backend.Loop.Start() - with kwargs support
2021
2143
  if self._match(TokenType.PAREN_START):
2022
- args = []
2023
- while not self._check(TokenType.PAREN_END):
2024
- args.append(self._parse_expression())
2025
- if not self._check(TokenType.PAREN_END):
2026
- self._expect(TokenType.COMMA)
2144
+ args, kwargs = self._parse_call_arguments()
2027
2145
  self._expect(TokenType.PAREN_END)
2028
- node = ASTNode('call', value={'callee': node, 'args': args})
2146
+ node = ASTNode('call', value={'callee': node, 'args': args, 'kwargs': kwargs})
2029
2147
  return node
2030
2148
 
2031
2149
  if self._check(TokenType.GLOBAL_REF):
2032
2150
  # r@<name> global variable reference/declaration
2033
2151
  token = self._advance()
2034
2152
  node = ASTNode('global_ref', value=token.value, line=token.line, column=token.column)
2035
- # Check for member access, calls, indexing
2153
+ # Check for member access, calls, indexing - with kwargs support
2036
2154
  while True:
2037
2155
  if self._match(TokenType.PAREN_START):
2038
- args = []
2039
- while not self._check(TokenType.PAREN_END):
2040
- args.append(self._parse_expression())
2041
- if not self._check(TokenType.PAREN_END):
2042
- self._expect(TokenType.COMMA)
2156
+ args, kwargs = self._parse_call_arguments()
2043
2157
  self._expect(TokenType.PAREN_END)
2044
- node = ASTNode('call', value={'callee': node, 'args': args})
2158
+ node = ASTNode('call', value={'callee': node, 'args': args, 'kwargs': kwargs})
2045
2159
  elif self._match(TokenType.DOT):
2046
2160
  member = self._advance().value
2047
2161
  node = ASTNode('member_access', value={'object': node, 'member': member})
@@ -2057,16 +2171,12 @@ class CSSLParser:
2057
2171
  # $<name> shared object reference
2058
2172
  token = self._advance()
2059
2173
  node = ASTNode('shared_ref', value=token.value, line=token.line, column=token.column)
2060
- # Check for member access, calls, indexing
2174
+ # Check for member access, calls, indexing - with kwargs support
2061
2175
  while True:
2062
2176
  if self._match(TokenType.PAREN_START):
2063
- args = []
2064
- while not self._check(TokenType.PAREN_END):
2065
- args.append(self._parse_expression())
2066
- if not self._check(TokenType.PAREN_END):
2067
- self._expect(TokenType.COMMA)
2177
+ args, kwargs = self._parse_call_arguments()
2068
2178
  self._expect(TokenType.PAREN_END)
2069
- node = ASTNode('call', value={'callee': node, 'args': args})
2179
+ node = ASTNode('call', value={'callee': node, 'args': args, 'kwargs': kwargs})
2070
2180
  elif self._match(TokenType.DOT):
2071
2181
  member = self._advance().value
2072
2182
  node = ASTNode('member_access', value={'object': node, 'member': member})
@@ -2082,16 +2192,12 @@ class CSSLParser:
2082
2192
  # %<name> captured reference (captures value at infusion registration time)
2083
2193
  token = self._advance()
2084
2194
  node = ASTNode('captured_ref', value=token.value, line=token.line, column=token.column)
2085
- # Check for member access, calls, indexing
2195
+ # Check for member access, calls, indexing - with kwargs support
2086
2196
  while True:
2087
2197
  if self._match(TokenType.PAREN_START):
2088
- args = []
2089
- while not self._check(TokenType.PAREN_END):
2090
- args.append(self._parse_expression())
2091
- if not self._check(TokenType.PAREN_END):
2092
- self._expect(TokenType.COMMA)
2198
+ args, kwargs = self._parse_call_arguments()
2093
2199
  self._expect(TokenType.PAREN_END)
2094
- node = ASTNode('call', value={'callee': node, 'args': args})
2200
+ node = ASTNode('call', value={'callee': node, 'args': args, 'kwargs': kwargs})
2095
2201
  elif self._match(TokenType.DOT):
2096
2202
  member = self._advance().value
2097
2203
  node = ASTNode('member_access', value={'object': node, 'member': member})
@@ -2160,14 +2266,10 @@ class CSSLParser:
2160
2266
  member = self._advance().value
2161
2267
  node = ASTNode('member_access', value={'object': node, 'member': member})
2162
2268
  elif self._match(TokenType.PAREN_START):
2163
- # Function call
2164
- args = []
2165
- while not self._check(TokenType.PAREN_END):
2166
- args.append(self._parse_expression())
2167
- if not self._check(TokenType.PAREN_END):
2168
- self._expect(TokenType.COMMA)
2269
+ # Function call - use _parse_call_arguments for kwargs support
2270
+ args, kwargs = self._parse_call_arguments()
2169
2271
  self._expect(TokenType.PAREN_END)
2170
- node = ASTNode('call', value={'callee': node, 'args': args})
2272
+ node = ASTNode('call', value={'callee': node, 'args': args, 'kwargs': kwargs})
2171
2273
  elif self._match(TokenType.BRACKET_START):
2172
2274
  # Index access
2173
2275
  index = self._parse_expression()
@@ -2191,7 +2293,7 @@ class CSSLParser:
2191
2293
  while not self._check(TokenType.PAREN_END) and not self._is_at_end():
2192
2294
  # Check for named argument: identifier = expression
2193
2295
  if self._check(TokenType.IDENTIFIER):
2194
- saved_pos = self._current
2296
+ saved_pos = self.pos # Save token position
2195
2297
  name_token = self._advance()
2196
2298
 
2197
2299
  if self._check(TokenType.EQUALS):
@@ -2201,7 +2303,7 @@ class CSSLParser:
2201
2303
  kwargs[name_token.value] = value
2202
2304
  else:
2203
2305
  # Not named, restore and parse as expression
2204
- self._current = saved_pos
2306
+ self.pos = saved_pos # Restore token position
2205
2307
  args.append(self._parse_expression())
2206
2308
  else:
2207
2309
  args.append(self._parse_expression())
@@ -2220,6 +2322,19 @@ class CSSLParser:
2220
2322
  namespace_member = self._advance().value
2221
2323
  name = f"{name}::{namespace_member}"
2222
2324
 
2325
+ # Check for instance<"name"> syntax - gets/creates shared instance
2326
+ if name == 'instance' and self._check(TokenType.COMPARE_LT):
2327
+ self._advance() # consume <
2328
+ # Expect string literal for instance name
2329
+ if self._check(TokenType.STRING):
2330
+ instance_name = self._advance().value
2331
+ elif self._check(TokenType.IDENTIFIER):
2332
+ instance_name = self._advance().value
2333
+ else:
2334
+ raise CSSLParserError("Expected instance name (string or identifier)", self._current_line())
2335
+ self._expect(TokenType.COMPARE_GT) # consume >
2336
+ return ASTNode('instance_ref', value=instance_name)
2337
+
2223
2338
  # Check for type generic instantiation: stack<string>, vector<int>, etc.
2224
2339
  # This creates a new instance of the type with the specified element type
2225
2340
  if name in TYPE_GENERICS and self._check(TokenType.COMPARE_LT):
@@ -2288,7 +2403,7 @@ class CSSLParser:
2288
2403
  return False
2289
2404
 
2290
2405
  # Save position for lookahead
2291
- saved_pos = self._current
2406
+ saved_pos = self.pos
2292
2407
 
2293
2408
  # Check if it looks like key = value pattern
2294
2409
  is_object = False
@@ -2299,7 +2414,7 @@ class CSSLParser:
2299
2414
  is_object = True
2300
2415
 
2301
2416
  # Restore position
2302
- self._current = saved_pos
2417
+ self.pos = saved_pos
2303
2418
  return is_object
2304
2419
 
2305
2420
  def _parse_action_block_expression(self) -> ASTNode: