IncludeCPP 4.0.3__py3-none-any.whl → 4.1.0__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.
- includecpp/__init__.py +1 -1
- includecpp/__init__.pyi +3 -1
- includecpp/cli/commands.py +3 -3
- includecpp/core/ai_integration.py +46 -13
- includecpp/core/cpp_api_extensions.pyi +622 -0
- includecpp/core/cssl/CSSL_DOCUMENTATION.md +186 -5
- includecpp/core/cssl/cssl_builtins.py +87 -2
- includecpp/core/cssl/cssl_languages.py +836 -0
- includecpp/core/cssl/cssl_parser.py +138 -38
- includecpp/core/cssl/cssl_runtime.py +178 -11
- includecpp/core/cssl/cssl_syntax.py +88 -4
- includecpp/core/cssl/cssl_types.py +31 -2
- {includecpp-4.0.3.dist-info → includecpp-4.1.0.dist-info}/METADATA +101 -1
- {includecpp-4.0.3.dist-info → includecpp-4.1.0.dist-info}/RECORD +18 -16
- {includecpp-4.0.3.dist-info → includecpp-4.1.0.dist-info}/WHEEL +0 -0
- {includecpp-4.0.3.dist-info → includecpp-4.1.0.dist-info}/entry_points.txt +0 -0
- {includecpp-4.0.3.dist-info → includecpp-4.1.0.dist-info}/licenses/LICENSE +0 -0
- {includecpp-4.0.3.dist-info → includecpp-4.1.0.dist-info}/top_level.txt +0 -0
|
@@ -113,6 +113,8 @@ class TokenType(Enum):
|
|
|
113
113
|
# Append operator for constructor/function extension
|
|
114
114
|
PLUS_PLUS = auto() # ++ for constructor/function append (keeps old + adds new)
|
|
115
115
|
MINUS_MINUS = auto() # -- for potential future use
|
|
116
|
+
# Multi-language support (v4.1.0)
|
|
117
|
+
LANG_INSTANCE_REF = auto() # cpp$InstanceName, py$Object - cross-language instance access
|
|
116
118
|
|
|
117
119
|
|
|
118
120
|
KEYWORDS = {
|
|
@@ -155,6 +157,8 @@ KEYWORDS = {
|
|
|
155
157
|
'static', # Static method/function
|
|
156
158
|
# CSSL Include Keywords
|
|
157
159
|
'include', 'get',
|
|
160
|
+
# Multi-language support (v4.1.0)
|
|
161
|
+
'supports', 'libinclude',
|
|
158
162
|
}
|
|
159
163
|
|
|
160
164
|
# Function modifiers that can appear in any order before function name
|
|
@@ -182,6 +186,12 @@ INJECTION_HELPERS = {
|
|
|
182
186
|
'string', 'integer', 'json', 'array', 'vector', 'combo', 'dynamic', 'sql'
|
|
183
187
|
}
|
|
184
188
|
|
|
189
|
+
# Language identifiers for multi-language support (v4.1.0)
|
|
190
|
+
# Used in lang$instance patterns like cpp$MyClass, py$Object
|
|
191
|
+
LANGUAGE_IDS = {
|
|
192
|
+
'cpp', 'py', 'python', 'java', 'csharp', 'js', 'javascript'
|
|
193
|
+
}
|
|
194
|
+
|
|
185
195
|
|
|
186
196
|
@dataclass
|
|
187
197
|
class Token:
|
|
@@ -457,6 +467,25 @@ class CSSLLexer:
|
|
|
457
467
|
self._advance()
|
|
458
468
|
value = self.source[start:self.pos]
|
|
459
469
|
|
|
470
|
+
# Check for language$instance pattern (v4.1.0)
|
|
471
|
+
# e.g., cpp$MyClass, py$Object, java$Service
|
|
472
|
+
if value.lower() in LANGUAGE_IDS and self.pos < len(self.source) and self.source[self.pos] == '$':
|
|
473
|
+
lang_id = value
|
|
474
|
+
self._advance() # skip '$'
|
|
475
|
+
# Read instance name
|
|
476
|
+
instance_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
|
+
instance_name = self.source[instance_start:self.pos]
|
|
480
|
+
if instance_name:
|
|
481
|
+
self._add_token(TokenType.LANG_INSTANCE_REF, {'lang': lang_id, 'instance': instance_name})
|
|
482
|
+
return
|
|
483
|
+
# If no instance name, revert and treat as normal identifier
|
|
484
|
+
self.pos = start
|
|
485
|
+
while self.pos < len(self.source) and (self.source[self.pos].isalnum() or self.source[self.pos] == '_'):
|
|
486
|
+
self._advance()
|
|
487
|
+
value = self.source[start:self.pos]
|
|
488
|
+
|
|
460
489
|
if value in ('True', 'true'):
|
|
461
490
|
self._add_token(TokenType.BOOLEAN, True)
|
|
462
491
|
elif value in ('False', 'false'):
|
|
@@ -1350,13 +1379,7 @@ class CSSLParser:
|
|
|
1350
1379
|
# Wrap in global_assignment to mark as global variable (same as 'global' keyword)
|
|
1351
1380
|
global_stmt = ASTNode('global_assignment', value=stmt)
|
|
1352
1381
|
root.children.append(global_stmt)
|
|
1353
|
-
#
|
|
1354
|
-
elif (self._check(TokenType.IDENTIFIER) or self._check(TokenType.AT) or
|
|
1355
|
-
self._check(TokenType.SELF_REF) or self._check(TokenType.SHARED_REF) or
|
|
1356
|
-
self._check(TokenType.KEYWORD)):
|
|
1357
|
-
stmt = self._parse_expression_statement()
|
|
1358
|
-
if stmt:
|
|
1359
|
-
root.children.append(stmt)
|
|
1382
|
+
# Control flow keywords must be checked BEFORE generic KEYWORD handling
|
|
1360
1383
|
elif self._match_keyword('if'):
|
|
1361
1384
|
root.children.append(self._parse_if())
|
|
1362
1385
|
elif self._match_keyword('while'):
|
|
@@ -1365,6 +1388,13 @@ class CSSLParser:
|
|
|
1365
1388
|
root.children.append(self._parse_for())
|
|
1366
1389
|
elif self._match_keyword('foreach'):
|
|
1367
1390
|
root.children.append(self._parse_foreach())
|
|
1391
|
+
# Handle statements - keywords like 'instance', 'list', 'map' can be variable names
|
|
1392
|
+
elif (self._check(TokenType.IDENTIFIER) or self._check(TokenType.AT) or
|
|
1393
|
+
self._check(TokenType.SELF_REF) or self._check(TokenType.SHARED_REF) or
|
|
1394
|
+
self._check(TokenType.KEYWORD)):
|
|
1395
|
+
stmt = self._parse_expression_statement()
|
|
1396
|
+
if stmt:
|
|
1397
|
+
root.children.append(stmt)
|
|
1368
1398
|
# Skip comments and newlines
|
|
1369
1399
|
elif self._check(TokenType.COMMENT) or self._check(TokenType.NEWLINE):
|
|
1370
1400
|
self._advance()
|
|
@@ -1627,15 +1657,22 @@ class CSSLParser:
|
|
|
1627
1657
|
# class Child : extends Parent (param1, param2) { ... } <- constructor args for parent
|
|
1628
1658
|
extends_class = None
|
|
1629
1659
|
extends_is_python = False
|
|
1660
|
+
extends_lang_ref = None # v4.1.0: Cross-language inheritance (cpp$ClassName)
|
|
1630
1661
|
extends_args = []
|
|
1631
1662
|
overwrites_class = None
|
|
1632
1663
|
overwrites_is_python = False
|
|
1664
|
+
supports_language = None # v4.1.0: Multi-language syntax support
|
|
1633
1665
|
|
|
1634
1666
|
if self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.COLON):
|
|
1635
1667
|
# Parse extends and/or overwrites (can be chained with : or ::)
|
|
1636
1668
|
while True:
|
|
1637
1669
|
if self._match_keyword('extends'):
|
|
1638
|
-
|
|
1670
|
+
# v4.1.0: Check for cross-language inheritance: extends cpp$ClassName
|
|
1671
|
+
if self._check(TokenType.LANG_INSTANCE_REF):
|
|
1672
|
+
ref = self._advance().value
|
|
1673
|
+
extends_lang_ref = ref # {'lang': 'cpp', 'instance': 'ClassName'}
|
|
1674
|
+
extends_class = ref['instance']
|
|
1675
|
+
elif self._check(TokenType.IDENTIFIER):
|
|
1639
1676
|
extends_class = self._advance().value
|
|
1640
1677
|
elif self._check(TokenType.SHARED_REF):
|
|
1641
1678
|
extends_class = self._advance().value
|
|
@@ -1660,8 +1697,20 @@ class CSSLParser:
|
|
|
1660
1697
|
# Skip optional () after class name
|
|
1661
1698
|
if self._match(TokenType.PAREN_START):
|
|
1662
1699
|
self._expect(TokenType.PAREN_END)
|
|
1700
|
+
# v4.1.0: Parse 'supports' keyword for multi-language syntax
|
|
1701
|
+
elif self._match_keyword('supports'):
|
|
1702
|
+
if self._check(TokenType.AT):
|
|
1703
|
+
self._advance() # consume @
|
|
1704
|
+
if self._check(TokenType.IDENTIFIER):
|
|
1705
|
+
supports_language = '@' + self._advance().value
|
|
1706
|
+
else:
|
|
1707
|
+
raise CSSLSyntaxError("Expected language identifier after '@' in 'supports'")
|
|
1708
|
+
elif self._check(TokenType.IDENTIFIER):
|
|
1709
|
+
supports_language = self._advance().value
|
|
1710
|
+
else:
|
|
1711
|
+
raise CSSLSyntaxError("Expected language identifier after 'supports'")
|
|
1663
1712
|
else:
|
|
1664
|
-
raise CSSLSyntaxError("Expected 'extends' or '
|
|
1713
|
+
raise CSSLSyntaxError("Expected 'extends', 'overwrites', or 'supports' after ':' or '::' in class declaration")
|
|
1665
1714
|
# Check for another : or :: for chaining
|
|
1666
1715
|
if not (self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.COLON)):
|
|
1667
1716
|
break
|
|
@@ -1673,9 +1722,11 @@ class CSSLParser:
|
|
|
1673
1722
|
'class_params': class_params,
|
|
1674
1723
|
'extends': extends_class,
|
|
1675
1724
|
'extends_is_python': extends_is_python,
|
|
1725
|
+
'extends_lang_ref': extends_lang_ref, # v4.1.0
|
|
1676
1726
|
'extends_args': extends_args,
|
|
1677
1727
|
'overwrites': overwrites_class,
|
|
1678
|
-
'overwrites_is_python': overwrites_is_python
|
|
1728
|
+
'overwrites_is_python': overwrites_is_python,
|
|
1729
|
+
'supports_language': supports_language # v4.1.0
|
|
1679
1730
|
}, children=[])
|
|
1680
1731
|
self._expect(TokenType.BLOCK_START)
|
|
1681
1732
|
|
|
@@ -1945,6 +1996,7 @@ class CSSLParser:
|
|
|
1945
1996
|
extends_method_ref = None
|
|
1946
1997
|
overwrites_class_ref = None
|
|
1947
1998
|
overwrites_method_ref = None
|
|
1999
|
+
supports_language = None # v4.1.0: Multi-language syntax support
|
|
1948
2000
|
|
|
1949
2001
|
if self._match(TokenType.DOUBLE_COLON) or self._match(TokenType.COLON):
|
|
1950
2002
|
# Parse extends and/or overwrites (supports :: method-level syntax)
|
|
@@ -2005,6 +2057,18 @@ class CSSLParser:
|
|
|
2005
2057
|
# Skip optional () after function/method name
|
|
2006
2058
|
if self._match(TokenType.PAREN_START):
|
|
2007
2059
|
self._expect(TokenType.PAREN_END)
|
|
2060
|
+
# v4.1.0: Parse 'supports' keyword for multi-language syntax
|
|
2061
|
+
elif self._match_keyword('supports'):
|
|
2062
|
+
if self._check(TokenType.AT):
|
|
2063
|
+
self._advance() # consume @
|
|
2064
|
+
if self._check(TokenType.IDENTIFIER):
|
|
2065
|
+
supports_language = '@' + self._advance().value
|
|
2066
|
+
else:
|
|
2067
|
+
raise CSSLSyntaxError("Expected language identifier after '@' in 'supports'")
|
|
2068
|
+
elif self._check(TokenType.IDENTIFIER):
|
|
2069
|
+
supports_language = self._advance().value
|
|
2070
|
+
else:
|
|
2071
|
+
raise CSSLSyntaxError("Expected language identifier after 'supports'")
|
|
2008
2072
|
else:
|
|
2009
2073
|
break
|
|
2010
2074
|
# Check for another :: or : for chaining extends/overwrites
|
|
@@ -2092,7 +2156,9 @@ class CSSLParser:
|
|
|
2092
2156
|
# New append mode fields
|
|
2093
2157
|
'append_mode': append_mode,
|
|
2094
2158
|
'append_ref_class': append_ref_class,
|
|
2095
|
-
'append_ref_member': append_ref_member
|
|
2159
|
+
'append_ref_member': append_ref_member,
|
|
2160
|
+
# v4.1.0: Multi-language support
|
|
2161
|
+
'supports_language': supports_language
|
|
2096
2162
|
}, children=[])
|
|
2097
2163
|
self._expect(TokenType.BLOCK_START)
|
|
2098
2164
|
|
|
@@ -2352,42 +2418,40 @@ class CSSLParser:
|
|
|
2352
2418
|
|
|
2353
2419
|
Supports: i = i + 1, i++, ++i, i += 1, i -= 1
|
|
2354
2420
|
"""
|
|
2355
|
-
# Check for prefix increment/decrement: ++i or --i
|
|
2356
|
-
if self._check(TokenType.
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2421
|
+
# Check for prefix increment/decrement: ++i or --i (as single PLUS_PLUS/MINUS_MINUS token)
|
|
2422
|
+
if self._check(TokenType.PLUS_PLUS):
|
|
2423
|
+
self._advance()
|
|
2424
|
+
var_name = self._advance().value
|
|
2425
|
+
return ASTNode('c_for_update', value={'var': var_name, 'op': 'increment'})
|
|
2426
|
+
elif self._check(TokenType.MINUS_MINUS):
|
|
2427
|
+
self._advance()
|
|
2428
|
+
var_name = self._advance().value
|
|
2429
|
+
return ASTNode('c_for_update', value={'var': var_name, 'op': 'decrement'})
|
|
2364
2430
|
|
|
2365
2431
|
# Regular variable assignment or postfix
|
|
2366
2432
|
var_name = self._advance().value
|
|
2367
2433
|
|
|
2368
|
-
# Check for postfix increment/decrement: i++ or i--
|
|
2369
|
-
if self._check(TokenType.
|
|
2434
|
+
# Check for postfix increment/decrement: i++ or i-- (as single PLUS_PLUS/MINUS_MINUS token)
|
|
2435
|
+
if self._check(TokenType.PLUS_PLUS):
|
|
2436
|
+
self._advance()
|
|
2437
|
+
return ASTNode('c_for_update', value={'var': var_name, 'op': 'increment'})
|
|
2438
|
+
elif self._check(TokenType.MINUS_MINUS):
|
|
2439
|
+
self._advance()
|
|
2440
|
+
return ASTNode('c_for_update', value={'var': var_name, 'op': 'decrement'})
|
|
2441
|
+
# i += value
|
|
2442
|
+
elif self._check(TokenType.PLUS):
|
|
2370
2443
|
self._advance()
|
|
2371
|
-
if self._check(TokenType.
|
|
2444
|
+
if self._check(TokenType.EQUALS):
|
|
2372
2445
|
self._advance()
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
if self._check(TokenType.EQUALS):
|
|
2377
|
-
self._advance()
|
|
2378
|
-
value = self._parse_expression()
|
|
2379
|
-
return ASTNode('c_for_update', value={'var': var_name, 'op': 'add', 'value': value})
|
|
2446
|
+
value = self._parse_expression()
|
|
2447
|
+
return ASTNode('c_for_update', value={'var': var_name, 'op': 'add', 'value': value})
|
|
2448
|
+
# i -= value
|
|
2380
2449
|
elif self._check(TokenType.MINUS):
|
|
2381
2450
|
self._advance()
|
|
2382
|
-
if self._check(TokenType.
|
|
2451
|
+
if self._check(TokenType.EQUALS):
|
|
2383
2452
|
self._advance()
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
# i -= value
|
|
2387
|
-
if self._check(TokenType.EQUALS):
|
|
2388
|
-
self._advance()
|
|
2389
|
-
value = self._parse_expression()
|
|
2390
|
-
return ASTNode('c_for_update', value={'var': var_name, 'op': 'subtract', 'value': value})
|
|
2453
|
+
value = self._parse_expression()
|
|
2454
|
+
return ASTNode('c_for_update', value={'var': var_name, 'op': 'subtract', 'value': value})
|
|
2391
2455
|
|
|
2392
2456
|
# Regular assignment: i = expression
|
|
2393
2457
|
if self._check(TokenType.EQUALS):
|
|
@@ -2948,6 +3012,14 @@ class CSSLParser:
|
|
|
2948
3012
|
if self._match(TokenType.MINUS):
|
|
2949
3013
|
operand = self._parse_unary()
|
|
2950
3014
|
return ASTNode('unary', value={'op': '-', 'operand': operand})
|
|
3015
|
+
# Prefix increment: ++i
|
|
3016
|
+
if self._match(TokenType.PLUS_PLUS):
|
|
3017
|
+
operand = self._parse_unary()
|
|
3018
|
+
return ASTNode('increment', value={'op': 'prefix', 'operand': operand})
|
|
3019
|
+
# Prefix decrement: --i
|
|
3020
|
+
if self._match(TokenType.MINUS_MINUS):
|
|
3021
|
+
operand = self._parse_unary()
|
|
3022
|
+
return ASTNode('decrement', value={'op': 'prefix', 'operand': operand})
|
|
2951
3023
|
if self._match(TokenType.AMPERSAND):
|
|
2952
3024
|
# Reference operator: &variable or &@module
|
|
2953
3025
|
operand = self._parse_unary()
|
|
@@ -3148,6 +3220,28 @@ class CSSLParser:
|
|
|
3148
3220
|
break
|
|
3149
3221
|
return node
|
|
3150
3222
|
|
|
3223
|
+
# v4.1.0: Cross-language instance reference: cpp$ClassName, py$Object
|
|
3224
|
+
if self._check(TokenType.LANG_INSTANCE_REF):
|
|
3225
|
+
token = self._advance()
|
|
3226
|
+
ref = token.value # {'lang': 'cpp', 'instance': 'ClassName'}
|
|
3227
|
+
node = ASTNode('lang_instance_ref', value=ref, line=token.line, column=token.column)
|
|
3228
|
+
# Check for member access, calls, indexing
|
|
3229
|
+
while True:
|
|
3230
|
+
if self._match(TokenType.PAREN_START):
|
|
3231
|
+
args, kwargs = self._parse_call_arguments()
|
|
3232
|
+
self._expect(TokenType.PAREN_END)
|
|
3233
|
+
node = ASTNode('call', value={'callee': node, 'args': args, 'kwargs': kwargs})
|
|
3234
|
+
elif self._match(TokenType.DOT):
|
|
3235
|
+
member = self._advance().value
|
|
3236
|
+
node = ASTNode('member_access', value={'object': node, 'member': member})
|
|
3237
|
+
elif self._match(TokenType.BRACKET_START):
|
|
3238
|
+
index = self._parse_expression()
|
|
3239
|
+
self._expect(TokenType.BRACKET_END)
|
|
3240
|
+
node = ASTNode('index_access', value={'object': node, 'index': index})
|
|
3241
|
+
else:
|
|
3242
|
+
break
|
|
3243
|
+
return node
|
|
3244
|
+
|
|
3151
3245
|
if self._check(TokenType.NUMBER):
|
|
3152
3246
|
return ASTNode('literal', value=self._advance().value)
|
|
3153
3247
|
|
|
@@ -3398,6 +3492,12 @@ class CSSLParser:
|
|
|
3398
3492
|
index = self._parse_expression()
|
|
3399
3493
|
self._expect(TokenType.BRACKET_END)
|
|
3400
3494
|
node = ASTNode('index_access', value={'object': node, 'index': index})
|
|
3495
|
+
# Postfix increment: i++
|
|
3496
|
+
elif self._match(TokenType.PLUS_PLUS):
|
|
3497
|
+
node = ASTNode('increment', value={'op': 'postfix', 'operand': node})
|
|
3498
|
+
# Postfix decrement: i--
|
|
3499
|
+
elif self._match(TokenType.MINUS_MINUS):
|
|
3500
|
+
node = ASTNode('decrement', value={'op': 'postfix', 'operand': node})
|
|
3401
3501
|
else:
|
|
3402
3502
|
break
|
|
3403
3503
|
|
|
@@ -2549,24 +2549,60 @@ class CSSLRuntime:
|
|
|
2549
2549
|
if filter_info:
|
|
2550
2550
|
source = self._apply_injection_filter(source, filter_info)
|
|
2551
2551
|
|
|
2552
|
-
# Get current target value for add/move modes
|
|
2552
|
+
# Get current target value for add/move/replace modes (needed for UniversalInstance handling)
|
|
2553
2553
|
current_value = None
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
current_value = None
|
|
2554
|
+
try:
|
|
2555
|
+
current_value = self._evaluate(target)
|
|
2556
|
+
except Exception:
|
|
2557
|
+
# Target might not exist yet, that's okay for add mode
|
|
2558
|
+
current_value = None
|
|
2560
2559
|
|
|
2561
2560
|
# Determine final value based on mode
|
|
2562
2561
|
if mode == 'replace':
|
|
2563
|
-
|
|
2562
|
+
from .cssl_types import CSSLInstance, UniversalInstance, CSSLClass
|
|
2563
|
+
# Special handling for UniversalInstance targets - inject instead of replace
|
|
2564
|
+
if isinstance(current_value, UniversalInstance):
|
|
2565
|
+
if isinstance(source, CSSLClass):
|
|
2566
|
+
current_value.set_member(source.name, source)
|
|
2567
|
+
final_value = current_value
|
|
2568
|
+
elif isinstance(source, ASTNode) and source.type == 'function':
|
|
2569
|
+
func_info = source.value
|
|
2570
|
+
func_name = func_info.get('name') if isinstance(func_info, dict) else None
|
|
2571
|
+
if func_name:
|
|
2572
|
+
current_value.set_method(func_name, source, self)
|
|
2573
|
+
final_value = current_value
|
|
2574
|
+
elif isinstance(source, CSSLInstance):
|
|
2575
|
+
current_value.set_member(source._class.name, source)
|
|
2576
|
+
final_value = current_value
|
|
2577
|
+
else:
|
|
2578
|
+
# For other types, store as member with source type name
|
|
2579
|
+
final_value = source
|
|
2580
|
+
else:
|
|
2581
|
+
final_value = source
|
|
2564
2582
|
elif mode == 'add':
|
|
2565
2583
|
# Copy & add - preserve target and add source
|
|
2566
|
-
from .cssl_types import CSSLInstance
|
|
2584
|
+
from .cssl_types import CSSLInstance, UniversalInstance, CSSLClass
|
|
2567
2585
|
|
|
2586
|
+
# Special handling for UniversalInstance + CSSLClass
|
|
2587
|
+
if isinstance(current_value, UniversalInstance) and isinstance(source, CSSLClass):
|
|
2588
|
+
# Inject class definition into universal instance
|
|
2589
|
+
current_value.set_member(source.name, source)
|
|
2590
|
+
final_value = current_value
|
|
2591
|
+
# Special handling for UniversalInstance + Function (AST node)
|
|
2592
|
+
elif isinstance(current_value, UniversalInstance) and isinstance(source, ASTNode) and source.type == 'function':
|
|
2593
|
+
# Inject function as a method into universal instance
|
|
2594
|
+
func_info = source.value
|
|
2595
|
+
func_name = func_info.get('name') if isinstance(func_info, dict) else None
|
|
2596
|
+
if func_name:
|
|
2597
|
+
current_value.set_method(func_name, source, self)
|
|
2598
|
+
final_value = current_value
|
|
2599
|
+
# Special handling for UniversalInstance + CSSLInstance
|
|
2600
|
+
elif isinstance(current_value, UniversalInstance) and isinstance(source, CSSLInstance):
|
|
2601
|
+
class_name = source._class.name
|
|
2602
|
+
current_value.set_member(class_name, source)
|
|
2603
|
+
final_value = current_value
|
|
2568
2604
|
# Special handling for CSSLInstance - merge classes
|
|
2569
|
-
|
|
2605
|
+
elif isinstance(current_value, CSSLInstance) and isinstance(source, CSSLInstance):
|
|
2570
2606
|
# Add the new class instance as a member with class name as key
|
|
2571
2607
|
class_name = source._class.name
|
|
2572
2608
|
current_value._members[class_name] = source
|
|
@@ -2873,7 +2909,7 @@ class CSSLRuntime:
|
|
|
2873
2909
|
func_info = child.value
|
|
2874
2910
|
func_name = func_info.get('name') if isinstance(func_info, dict) else None
|
|
2875
2911
|
if func_name:
|
|
2876
|
-
instance.set_method(func_name, child)
|
|
2912
|
+
instance.set_method(func_name, child, self)
|
|
2877
2913
|
elif child.type == 'var_declaration':
|
|
2878
2914
|
# Extract variable and value
|
|
2879
2915
|
var_info = child.value
|
|
@@ -3214,6 +3250,45 @@ class CSSLRuntime:
|
|
|
3214
3250
|
# Return None if instance doesn't exist (can be created via ==>)
|
|
3215
3251
|
return None
|
|
3216
3252
|
|
|
3253
|
+
# v4.1.0: Cross-language instance reference: cpp$ClassName, py$Object
|
|
3254
|
+
if node.type == 'lang_instance_ref':
|
|
3255
|
+
ref = node.value # {'lang': 'cpp', 'instance': 'ClassName'}
|
|
3256
|
+
lang_id = ref['lang']
|
|
3257
|
+
instance_name = ref['instance']
|
|
3258
|
+
|
|
3259
|
+
# First, try to get the language support object from scope
|
|
3260
|
+
lang_support = self.scope.get(lang_id)
|
|
3261
|
+
if lang_support is None:
|
|
3262
|
+
lang_support = self.global_scope.get(lang_id)
|
|
3263
|
+
|
|
3264
|
+
# If not found in scope, try to get from modules
|
|
3265
|
+
if lang_support is None:
|
|
3266
|
+
lang_support = self._modules.get(lang_id)
|
|
3267
|
+
|
|
3268
|
+
# If still not found, try getting default language support
|
|
3269
|
+
if lang_support is None:
|
|
3270
|
+
from .cssl_languages import get_language
|
|
3271
|
+
lang_support = get_language(lang_id)
|
|
3272
|
+
|
|
3273
|
+
if lang_support is not None:
|
|
3274
|
+
# Check if it's a LanguageSupport object with get_instance method
|
|
3275
|
+
if hasattr(lang_support, 'get_instance'):
|
|
3276
|
+
instance = lang_support.get_instance(instance_name)
|
|
3277
|
+
if instance is not None:
|
|
3278
|
+
return instance
|
|
3279
|
+
# Check _instances dict directly
|
|
3280
|
+
if hasattr(lang_support, '_instances'):
|
|
3281
|
+
if instance_name in lang_support._instances:
|
|
3282
|
+
return lang_support._instances[instance_name]
|
|
3283
|
+
|
|
3284
|
+
# Build helpful error message
|
|
3285
|
+
hint = f"Use '{lang_id}.share(\"{instance_name}\", instance)' to register the instance first."
|
|
3286
|
+
raise self._format_error(
|
|
3287
|
+
node.line if hasattr(node, 'line') else 0,
|
|
3288
|
+
f"Cross-language instance '{lang_id}${instance_name}' not found",
|
|
3289
|
+
hint
|
|
3290
|
+
)
|
|
3291
|
+
|
|
3217
3292
|
if node.type == 'new':
|
|
3218
3293
|
# Create new instance of a class: new ClassName(args)
|
|
3219
3294
|
return self._eval_new(node)
|
|
@@ -3287,6 +3362,14 @@ class CSSLRuntime:
|
|
|
3287
3362
|
if node.type == 'unary':
|
|
3288
3363
|
return self._eval_unary(node)
|
|
3289
3364
|
|
|
3365
|
+
# Increment: ++i or i++
|
|
3366
|
+
if node.type == 'increment':
|
|
3367
|
+
return self._eval_increment(node)
|
|
3368
|
+
|
|
3369
|
+
# Decrement: --i or i--
|
|
3370
|
+
if node.type == 'decrement':
|
|
3371
|
+
return self._eval_decrement(node)
|
|
3372
|
+
|
|
3290
3373
|
if node.type == 'non_null_assert':
|
|
3291
3374
|
# *$var, *@module, *identifier - assert value is not null/None
|
|
3292
3375
|
operand = node.value.get('operand')
|
|
@@ -3572,6 +3655,74 @@ class CSSLRuntime:
|
|
|
3572
3655
|
|
|
3573
3656
|
return None
|
|
3574
3657
|
|
|
3658
|
+
def _eval_increment(self, node: ASTNode) -> Any:
|
|
3659
|
+
"""Evaluate increment operation (++i or i++)"""
|
|
3660
|
+
op_type = node.value.get('op') # 'prefix' or 'postfix'
|
|
3661
|
+
operand = node.value.get('operand')
|
|
3662
|
+
|
|
3663
|
+
# Get variable name
|
|
3664
|
+
var_name = None
|
|
3665
|
+
if isinstance(operand, ASTNode):
|
|
3666
|
+
if operand.type == 'identifier':
|
|
3667
|
+
var_name = operand.value
|
|
3668
|
+
elif operand.type == 'shared_ref':
|
|
3669
|
+
# Handle $var++
|
|
3670
|
+
var_name = operand.value
|
|
3671
|
+
current = self.shared_vars.get(var_name, 0)
|
|
3672
|
+
if op_type == 'prefix':
|
|
3673
|
+
self.shared_vars[var_name] = current + 1
|
|
3674
|
+
return current + 1
|
|
3675
|
+
else: # postfix
|
|
3676
|
+
self.shared_vars[var_name] = current + 1
|
|
3677
|
+
return current
|
|
3678
|
+
|
|
3679
|
+
if var_name:
|
|
3680
|
+
current = self.scope.get(var_name, 0)
|
|
3681
|
+
if op_type == 'prefix':
|
|
3682
|
+
# ++i: increment then return
|
|
3683
|
+
self.scope.set(var_name, current + 1)
|
|
3684
|
+
return current + 1
|
|
3685
|
+
else:
|
|
3686
|
+
# i++: return then increment
|
|
3687
|
+
self.scope.set(var_name, current + 1)
|
|
3688
|
+
return current
|
|
3689
|
+
|
|
3690
|
+
return None
|
|
3691
|
+
|
|
3692
|
+
def _eval_decrement(self, node: ASTNode) -> Any:
|
|
3693
|
+
"""Evaluate decrement operation (--i or i--)"""
|
|
3694
|
+
op_type = node.value.get('op') # 'prefix' or 'postfix'
|
|
3695
|
+
operand = node.value.get('operand')
|
|
3696
|
+
|
|
3697
|
+
# Get variable name
|
|
3698
|
+
var_name = None
|
|
3699
|
+
if isinstance(operand, ASTNode):
|
|
3700
|
+
if operand.type == 'identifier':
|
|
3701
|
+
var_name = operand.value
|
|
3702
|
+
elif operand.type == 'shared_ref':
|
|
3703
|
+
# Handle $var--
|
|
3704
|
+
var_name = operand.value
|
|
3705
|
+
current = self.shared_vars.get(var_name, 0)
|
|
3706
|
+
if op_type == 'prefix':
|
|
3707
|
+
self.shared_vars[var_name] = current - 1
|
|
3708
|
+
return current - 1
|
|
3709
|
+
else: # postfix
|
|
3710
|
+
self.shared_vars[var_name] = current - 1
|
|
3711
|
+
return current
|
|
3712
|
+
|
|
3713
|
+
if var_name:
|
|
3714
|
+
current = self.scope.get(var_name, 0)
|
|
3715
|
+
if op_type == 'prefix':
|
|
3716
|
+
# --i: decrement then return
|
|
3717
|
+
self.scope.set(var_name, current - 1)
|
|
3718
|
+
return current - 1
|
|
3719
|
+
else:
|
|
3720
|
+
# i--: return then decrement
|
|
3721
|
+
self.scope.set(var_name, current - 1)
|
|
3722
|
+
return current
|
|
3723
|
+
|
|
3724
|
+
return None
|
|
3725
|
+
|
|
3575
3726
|
def _eval_call(self, node: ASTNode) -> Any:
|
|
3576
3727
|
"""Evaluate function call with optional named arguments"""
|
|
3577
3728
|
callee_node = node.value.get('callee')
|
|
@@ -3783,6 +3934,22 @@ class CSSLRuntime:
|
|
|
3783
3934
|
hint
|
|
3784
3935
|
)
|
|
3785
3936
|
|
|
3937
|
+
# If we got a variable that holds a class reference, use that class
|
|
3938
|
+
if not isinstance(class_def, CSSLClass):
|
|
3939
|
+
# Check if it's a variable holding a class (dynamic class instantiation)
|
|
3940
|
+
if hasattr(class_def, '__class__') and isinstance(class_def, CSSLClass):
|
|
3941
|
+
pass # Already a CSSLClass, continue
|
|
3942
|
+
elif isinstance(class_def, dict) and 'class_def' in class_def:
|
|
3943
|
+
# Injected class reference from +<== operator
|
|
3944
|
+
class_def = class_def['class_def']
|
|
3945
|
+
else:
|
|
3946
|
+
# Not a class - show error
|
|
3947
|
+
raise CSSLRuntimeError(
|
|
3948
|
+
f"'{class_name}' is not a class",
|
|
3949
|
+
node.line,
|
|
3950
|
+
hint=f"'{class_name}' is of type {type(class_def).__name__}"
|
|
3951
|
+
)
|
|
3952
|
+
|
|
3786
3953
|
if not isinstance(class_def, CSSLClass):
|
|
3787
3954
|
raise CSSLRuntimeError(
|
|
3788
3955
|
f"'{class_name}' is not a class",
|