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.
- includecpp/__init__.py +1 -1
- includecpp/cli/commands.py +418 -0
- includecpp/core/cssl/CSSL_DOCUMENTATION.md +275 -13
- includecpp/core/cssl/cssl_builtins.py +114 -0
- includecpp/core/cssl/cssl_builtins.pyi +1393 -0
- includecpp/core/cssl/cssl_parser.py +174 -59
- includecpp/core/cssl/cssl_runtime.py +273 -1
- includecpp/core/cssl/cssl_types.py +224 -2
- includecpp/vscode/cssl/package.json +24 -4
- includecpp/vscode/cssl/snippets/cssl.snippets.json +1080 -0
- includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +127 -7
- {includecpp-3.6.0.dist-info → includecpp-3.7.1.dist-info}/METADATA +1 -1
- {includecpp-3.6.0.dist-info → includecpp-3.7.1.dist-info}/RECORD +17 -15
- {includecpp-3.6.0.dist-info → includecpp-3.7.1.dist-info}/WHEEL +0 -0
- {includecpp-3.6.0.dist-info → includecpp-3.7.1.dist-info}/entry_points.txt +0 -0
- {includecpp-3.6.0.dist-info → includecpp-3.7.1.dist-info}/licenses/LICENSE +0 -0
- {includecpp-3.6.0.dist-info → includecpp-3.7.1.dist-info}/top_level.txt +0 -0
|
@@ -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
|
-
#
|
|
934
|
-
if
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
2417
|
+
self.pos = saved_pos
|
|
2303
2418
|
return is_object
|
|
2304
2419
|
|
|
2305
2420
|
def _parse_action_block_expression(self) -> ASTNode:
|