IncludeCPP 3.4.10__py3-none-any.whl → 3.4.21__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.
@@ -99,6 +99,7 @@ class TokenType(Enum):
99
99
  AT = auto()
100
100
  GLOBAL_REF = auto() # r@<name> global variable declaration
101
101
  SELF_REF = auto() # s@<name> self-reference to global struct
102
+ SHARED_REF = auto() # $<name> shared object reference
102
103
  PACKAGE = auto()
103
104
  PACKAGE_INCLUDES = auto()
104
105
  AS = auto()
@@ -154,6 +155,11 @@ TYPE_GENERICS = {
154
155
  'vector', 'stack', 'array', 'openquote'
155
156
  }
156
157
 
158
+ # Functions that accept type parameters: FuncName<type>(args)
159
+ TYPE_PARAM_FUNCTIONS = {
160
+ 'OpenFind' # OpenFind<string>(0)
161
+ }
162
+
157
163
  # Injection helper prefixes (type::helper=value)
158
164
  INJECTION_HELPERS = {
159
165
  'string', 'integer', 'json', 'array', 'vector', 'combo', 'dynamic', 'sql'
@@ -232,6 +238,9 @@ class CSSLLexer:
232
238
  elif char == '@':
233
239
  self._add_token(TokenType.AT, '@')
234
240
  self._advance()
241
+ elif char == '$':
242
+ # $<name> shared object reference
243
+ self._read_shared_ref()
235
244
  elif char == '&':
236
245
  # & for references
237
246
  if self._peek(1) == '&':
@@ -470,6 +479,20 @@ class CSSLLexer:
470
479
  value = self.source[name_start:self.pos]
471
480
  self._add_token(TokenType.GLOBAL_REF, value)
472
481
 
482
+ def _read_shared_ref(self):
483
+ """Read $<name> shared object reference"""
484
+ self._advance() # skip '$'
485
+
486
+ # Read the identifier (shared object name)
487
+ name_start = self.pos
488
+ while self.pos < len(self.source) and (self.source[self.pos].isalnum() or self.source[self.pos] == '_'):
489
+ self._advance()
490
+
491
+ value = self.source[name_start:self.pos]
492
+ if not value:
493
+ self.error("Expected identifier after '$'")
494
+ self._add_token(TokenType.SHARED_REF, value)
495
+
473
496
  def _read_less_than(self):
474
497
  # Check for <<== (code infusion left)
475
498
  if self._peek(1) == '<' and self._peek(2) == '=' and self._peek(3) == '=':
@@ -952,7 +975,7 @@ class CSSLParser:
952
975
  global_stmt = ASTNode('global_assignment', value=stmt)
953
976
  root.children.append(global_stmt)
954
977
  # Handle statements
955
- elif self._check(TokenType.IDENTIFIER) or self._check(TokenType.AT) or self._check(TokenType.SELF_REF):
978
+ elif self._check(TokenType.IDENTIFIER) or self._check(TokenType.AT) or self._check(TokenType.SELF_REF) or self._check(TokenType.SHARED_REF):
956
979
  stmt = self._parse_expression_statement()
957
980
  if stmt:
958
981
  root.children.append(stmt)
@@ -1275,6 +1298,7 @@ class CSSLParser:
1275
1298
  return None
1276
1299
 
1277
1300
  def _parse_if(self) -> ASTNode:
1301
+ """Parse if statement with support for else if AND elif syntax."""
1278
1302
  self._expect(TokenType.PAREN_START)
1279
1303
  condition = self._parse_expression()
1280
1304
  self._expect(TokenType.PAREN_END)
@@ -1290,7 +1314,13 @@ class CSSLParser:
1290
1314
  self._expect(TokenType.BLOCK_END)
1291
1315
  node.children.append(then_block)
1292
1316
 
1293
- if self._match_keyword('else'):
1317
+ # Support both 'else if' AND 'elif' syntax
1318
+ if self._match_keyword('elif'):
1319
+ # elif is shorthand for else if
1320
+ else_block = ASTNode('else', children=[])
1321
+ else_block.children.append(self._parse_if())
1322
+ node.children.append(else_block)
1323
+ elif self._match_keyword('else'):
1294
1324
  else_block = ASTNode('else', children=[])
1295
1325
  if self._match_keyword('if'):
1296
1326
  else_block.children.append(self._parse_if())
@@ -1322,18 +1352,186 @@ class CSSLParser:
1322
1352
  return node
1323
1353
 
1324
1354
  def _parse_for(self) -> ASTNode:
1355
+ """Parse for loop - supports both syntaxes:
1356
+
1357
+ Python-style: for (i in range(0, n)) { }
1358
+ C-style: for (int i = 0; i < n; i = i + 1) { }
1359
+ for (i = 0; i < n; i++) { }
1360
+ """
1325
1361
  self._expect(TokenType.PAREN_START)
1362
+
1363
+ # Detect C-style by checking for semicolons in the for header
1364
+ # Look ahead without consuming tokens
1365
+ is_c_style = self._detect_c_style_for()
1366
+
1367
+ if is_c_style:
1368
+ # C-style: for (init; condition; update) { }
1369
+ return self._parse_c_style_for()
1370
+ else:
1371
+ # Python-style: for (var in range(start, end)) { }
1372
+ return self._parse_python_style_for()
1373
+
1374
+ def _detect_c_style_for(self) -> bool:
1375
+ """Detect if this is a C-style for loop by looking for semicolons."""
1376
+ # Scan the tokens list directly without modifying self.pos
1377
+ pos = self.pos
1378
+ paren_depth = 1
1379
+
1380
+ while pos < len(self.tokens) and paren_depth > 0:
1381
+ token = self.tokens[pos]
1382
+ if token.type == TokenType.PAREN_START:
1383
+ paren_depth += 1
1384
+ elif token.type == TokenType.PAREN_END:
1385
+ paren_depth -= 1
1386
+ elif token.type == TokenType.SEMICOLON and paren_depth == 1:
1387
+ # Found semicolon at top level - C-style
1388
+ return True
1389
+ elif token.type == TokenType.KEYWORD and token.value == 'in':
1390
+ # Found 'in' keyword - Python-style
1391
+ return False
1392
+ pos += 1
1393
+
1394
+ return False # Default to Python-style
1395
+
1396
+ def _parse_c_style_for(self) -> ASTNode:
1397
+ """Parse C-style for loop: for (init; condition; update) { }"""
1398
+ # Parse init statement
1399
+ init = None
1400
+ if not self._check(TokenType.SEMICOLON):
1401
+ # Check if it's a typed declaration: int i = 0
1402
+ if self._check(TokenType.KEYWORD) and self._peek().value in ('int', 'float', 'string', 'bool', 'dynamic'):
1403
+ type_name = self._advance().value
1404
+ var_name = self._advance().value
1405
+ self._expect(TokenType.EQUALS)
1406
+ value = self._parse_expression()
1407
+ init = ASTNode('c_for_init', value={
1408
+ 'type': type_name,
1409
+ 'var': var_name,
1410
+ 'value': value
1411
+ })
1412
+ else:
1413
+ # Simple assignment: i = 0
1414
+ var_name = self._advance().value
1415
+ self._expect(TokenType.EQUALS)
1416
+ value = self._parse_expression()
1417
+ init = ASTNode('c_for_init', value={
1418
+ 'type': None,
1419
+ 'var': var_name,
1420
+ 'value': value
1421
+ })
1422
+
1423
+ self._expect(TokenType.SEMICOLON)
1424
+
1425
+ # Parse condition
1426
+ condition = None
1427
+ if not self._check(TokenType.SEMICOLON):
1428
+ condition = self._parse_expression()
1429
+
1430
+ self._expect(TokenType.SEMICOLON)
1431
+
1432
+ # Parse update statement
1433
+ update = None
1434
+ if not self._check(TokenType.PAREN_END):
1435
+ # Could be: i = i + 1, i++, ++i, i += 1
1436
+ update = self._parse_c_for_update()
1437
+
1438
+ self._expect(TokenType.PAREN_END)
1439
+
1440
+ node = ASTNode('c_for', value={
1441
+ 'init': init,
1442
+ 'condition': condition,
1443
+ 'update': update
1444
+ }, children=[])
1445
+
1446
+ self._expect(TokenType.BLOCK_START)
1447
+
1448
+ while not self._check(TokenType.BLOCK_END) and not self._is_at_end():
1449
+ stmt = self._parse_statement()
1450
+ if stmt:
1451
+ node.children.append(stmt)
1452
+
1453
+ self._expect(TokenType.BLOCK_END)
1454
+ return node
1455
+
1456
+ def _parse_c_for_update(self) -> ASTNode:
1457
+ """Parse the update part of a C-style for loop.
1458
+
1459
+ Supports: i = i + 1, i++, ++i, i += 1, i -= 1
1460
+ """
1461
+ # Check for prefix increment/decrement: ++i or --i
1462
+ if self._check(TokenType.PLUS) or self._check(TokenType.MINUS):
1463
+ op_token = self._advance()
1464
+ # Check for double operator (++ or --)
1465
+ if self._check(op_token.type):
1466
+ self._advance()
1467
+ var_name = self._advance().value
1468
+ op = 'increment' if op_token.type == TokenType.PLUS else 'decrement'
1469
+ return ASTNode('c_for_update', value={'var': var_name, 'op': op})
1470
+
1471
+ # Regular variable assignment or postfix
1472
+ var_name = self._advance().value
1473
+
1474
+ # Check for postfix increment/decrement: i++ or i--
1475
+ if self._check(TokenType.PLUS):
1476
+ self._advance()
1477
+ if self._check(TokenType.PLUS):
1478
+ self._advance()
1479
+ return ASTNode('c_for_update', value={'var': var_name, 'op': 'increment'})
1480
+ else:
1481
+ # i += value
1482
+ if self._check(TokenType.EQUALS):
1483
+ self._advance()
1484
+ value = self._parse_expression()
1485
+ return ASTNode('c_for_update', value={'var': var_name, 'op': 'add', 'value': value})
1486
+ elif self._check(TokenType.MINUS):
1487
+ self._advance()
1488
+ if self._check(TokenType.MINUS):
1489
+ self._advance()
1490
+ return ASTNode('c_for_update', value={'var': var_name, 'op': 'decrement'})
1491
+ else:
1492
+ # i -= value
1493
+ if self._check(TokenType.EQUALS):
1494
+ self._advance()
1495
+ value = self._parse_expression()
1496
+ return ASTNode('c_for_update', value={'var': var_name, 'op': 'subtract', 'value': value})
1497
+
1498
+ # Regular assignment: i = expression
1499
+ if self._check(TokenType.EQUALS):
1500
+ self._advance()
1501
+ value = self._parse_expression()
1502
+ return ASTNode('c_for_update', value={'var': var_name, 'op': 'assign', 'value': value})
1503
+
1504
+ # Just the variable (shouldn't happen but handle it)
1505
+ return ASTNode('c_for_update', value={'var': var_name, 'op': 'none'})
1506
+
1507
+ def _parse_python_style_for(self) -> ASTNode:
1508
+ """Parse Python-style for loop: for (i in range(start, end)) { }"""
1326
1509
  var_name = self._advance().value
1327
- self._expect(TokenType.KEYWORD)
1328
- self._expect(TokenType.KEYWORD)
1510
+ self._expect(TokenType.KEYWORD) # 'in'
1511
+
1512
+ # 'range' can be keyword or identifier
1513
+ if self._check(TokenType.KEYWORD) and self._peek().value == 'range':
1514
+ self._advance() # consume 'range' keyword
1515
+ elif self._check(TokenType.IDENTIFIER) and self._peek().value == 'range':
1516
+ self._advance() # consume 'range' identifier
1517
+ else:
1518
+ self.error(f"Expected 'range', got {self._peek().value}")
1519
+
1329
1520
  self._expect(TokenType.PAREN_START)
1330
1521
  start = self._parse_expression()
1331
1522
  self._expect(TokenType.COMMA)
1332
1523
  end = self._parse_expression()
1524
+
1525
+ # Optional step parameter: range(start, end, step)
1526
+ step = None
1527
+ if self._check(TokenType.COMMA):
1528
+ self._advance() # consume comma
1529
+ step = self._parse_expression()
1530
+
1333
1531
  self._expect(TokenType.PAREN_END)
1334
1532
  self._expect(TokenType.PAREN_END)
1335
1533
 
1336
- node = ASTNode('for', value={'var': var_name, 'start': start, 'end': end}, children=[])
1534
+ node = ASTNode('for', value={'var': var_name, 'start': start, 'end': end, 'step': step}, children=[])
1337
1535
  self._expect(TokenType.BLOCK_START)
1338
1536
 
1339
1537
  while not self._check(TokenType.BLOCK_END) and not self._is_at_end():
@@ -1787,6 +1985,31 @@ class CSSLParser:
1787
1985
  break
1788
1986
  return node
1789
1987
 
1988
+ if self._check(TokenType.SHARED_REF):
1989
+ # $<name> shared object reference
1990
+ token = self._advance()
1991
+ node = ASTNode('shared_ref', value=token.value, line=token.line, column=token.column)
1992
+ # Check for member access, calls, indexing
1993
+ while True:
1994
+ if self._match(TokenType.PAREN_START):
1995
+ args = []
1996
+ while not self._check(TokenType.PAREN_END):
1997
+ args.append(self._parse_expression())
1998
+ if not self._check(TokenType.PAREN_END):
1999
+ self._expect(TokenType.COMMA)
2000
+ self._expect(TokenType.PAREN_END)
2001
+ node = ASTNode('call', value={'callee': node, 'args': args})
2002
+ elif self._match(TokenType.DOT):
2003
+ member = self._advance().value
2004
+ node = ASTNode('member_access', value={'object': node, 'member': member})
2005
+ elif self._match(TokenType.BRACKET_START):
2006
+ index = self._parse_expression()
2007
+ self._expect(TokenType.BRACKET_END)
2008
+ node = ASTNode('index_access', value={'object': node, 'index': index})
2009
+ else:
2010
+ break
2011
+ return node
2012
+
1790
2013
  if self._check(TokenType.NUMBER):
1791
2014
  return ASTNode('literal', value=self._advance().value)
1792
2015
 
@@ -1822,16 +2045,81 @@ class CSSLParser:
1822
2045
  return ASTNode('literal', value=None)
1823
2046
 
1824
2047
  def _parse_module_reference(self) -> ASTNode:
1825
- parts = []
1826
- parts.append(self._advance().value)
2048
+ """Parse @name, handling method calls and property access.
1827
2049
 
1828
- while self._match(TokenType.DOT):
1829
- parts.append(self._advance().value)
2050
+ @name alone -> module_ref
2051
+ @name.method() -> call with member_access
2052
+ @name.property -> member_access
2053
+ """
2054
+ # Get base name
2055
+ name = self._advance().value
2056
+ node = ASTNode('module_ref', value=name)
1830
2057
 
1831
- return ASTNode('module_ref', value='.'.join(parts))
2058
+ # Continue to handle member access, calls, and indexing
2059
+ while True:
2060
+ if self._match(TokenType.DOT):
2061
+ member = self._advance().value
2062
+ node = ASTNode('member_access', value={'object': node, 'member': member})
2063
+ elif self._match(TokenType.PAREN_START):
2064
+ # Function call
2065
+ args = []
2066
+ while not self._check(TokenType.PAREN_END):
2067
+ args.append(self._parse_expression())
2068
+ if not self._check(TokenType.PAREN_END):
2069
+ self._expect(TokenType.COMMA)
2070
+ self._expect(TokenType.PAREN_END)
2071
+ node = ASTNode('call', value={'callee': node, 'args': args})
2072
+ elif self._match(TokenType.BRACKET_START):
2073
+ # Index access
2074
+ index = self._parse_expression()
2075
+ self._expect(TokenType.BRACKET_END)
2076
+ node = ASTNode('index_access', value={'object': node, 'index': index})
2077
+ else:
2078
+ break
2079
+
2080
+ return node
1832
2081
 
1833
2082
  def _parse_identifier_or_call(self) -> ASTNode:
1834
2083
  name = self._advance().value
2084
+
2085
+ # Check for type generic instantiation: stack<string>, vector<int>, etc.
2086
+ # This creates a new instance of the type with the specified element type
2087
+ if name in TYPE_GENERICS and self._check(TokenType.COMPARE_LT):
2088
+ self._advance() # consume <
2089
+ element_type = 'dynamic'
2090
+ if self._check(TokenType.KEYWORD) or self._check(TokenType.IDENTIFIER):
2091
+ element_type = self._advance().value
2092
+ self._expect(TokenType.COMPARE_GT) # consume >
2093
+ return ASTNode('type_instantiation', value={
2094
+ 'type': name,
2095
+ 'element_type': element_type
2096
+ })
2097
+
2098
+ # Check for type-parameterized function call: OpenFind<string>(0)
2099
+ if name in TYPE_PARAM_FUNCTIONS and self._check(TokenType.COMPARE_LT):
2100
+ self._advance() # consume <
2101
+ type_param = 'dynamic'
2102
+ if self._check(TokenType.KEYWORD) or self._check(TokenType.IDENTIFIER):
2103
+ type_param = self._advance().value
2104
+ self._expect(TokenType.COMPARE_GT) # consume >
2105
+
2106
+ # Must be followed by ()
2107
+ if self._check(TokenType.PAREN_START):
2108
+ self._advance() # consume (
2109
+ args = []
2110
+ while not self._check(TokenType.PAREN_END):
2111
+ args.append(self._parse_expression())
2112
+ if not self._check(TokenType.PAREN_END):
2113
+ self._expect(TokenType.COMMA)
2114
+ self._expect(TokenType.PAREN_END)
2115
+
2116
+ # Return as typed function call
2117
+ return ASTNode('typed_call', value={
2118
+ 'name': name,
2119
+ 'type_param': type_param,
2120
+ 'args': args
2121
+ })
2122
+
1835
2123
  node = ASTNode('identifier', value=name)
1836
2124
 
1837
2125
  while True: