IncludeCPP 3.7.2__tar.gz → 3.7.6__tar.gz
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-3.7.2 → includecpp-3.7.6}/IncludeCPP.egg-info/PKG-INFO +1 -1
- {includecpp-3.7.2 → includecpp-3.7.6}/PKG-INFO +1 -1
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/__init__.py +1 -1
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/cli/commands.py +82 -63
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/core/cssl/CSSL_DOCUMENTATION.md +27 -8
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/core/cssl/cssl_parser.py +174 -11
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/core/cssl/cssl_runtime.py +183 -15
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/core/cssl_bridge.py +477 -48
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/vscode/cssl/language-configuration.json +1 -4
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +96 -11
- {includecpp-3.7.2 → includecpp-3.7.6}/pyproject.toml +1 -1
- {includecpp-3.7.2 → includecpp-3.7.6}/setup.py +1 -1
- {includecpp-3.7.2 → includecpp-3.7.6}/IncludeCPP.egg-info/SOURCES.txt +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/IncludeCPP.egg-info/dependency_links.txt +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/IncludeCPP.egg-info/entry_points.txt +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/IncludeCPP.egg-info/requires.txt +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/IncludeCPP.egg-info/top_level.txt +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/LICENSE +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/MANIFEST.in +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/README.md +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/__init__.pyi +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/__main__.py +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/cli/__init__.py +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/cli/config_parser.py +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/core/__init__.py +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/core/ai_integration.py +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/core/build_manager.py +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/core/cpp_api.py +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/core/cpp_api.pyi +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/core/cppy_converter.py +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/core/cssl/__init__.py +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/core/cssl/cssl_builtins.py +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/core/cssl/cssl_builtins.pyi +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/core/cssl/cssl_events.py +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/core/cssl/cssl_modules.py +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/core/cssl/cssl_syntax.py +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/core/cssl/cssl_types.py +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/core/cssl_bridge.pyi +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/core/error_catalog.py +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/core/error_formatter.py +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/core/exceptions.py +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/core/path_discovery.py +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/core/project_ui.py +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/core/settings_ui.py +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/generator/__init__.py +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/generator/parser.cpp +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/generator/parser.h +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/generator/type_resolver.cpp +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/generator/type_resolver.h +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/py.typed +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/templates/cpp.proj.template +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/vscode/__init__.py +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/vscode/cssl/__init__.py +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/vscode/cssl/package.json +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/includecpp/vscode/cssl/snippets/cssl.snippets.json +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/requirements.txt +0 -0
- {includecpp-3.7.2 → includecpp-3.7.6}/setup.cfg +0 -0
|
@@ -7480,13 +7480,12 @@ def cssl_exec(path, code):
|
|
|
7480
7480
|
# Execute
|
|
7481
7481
|
click.secho("--- Output ---", fg='green')
|
|
7482
7482
|
try:
|
|
7483
|
-
result = cssl_lang.
|
|
7483
|
+
result = cssl_lang.run(source)
|
|
7484
7484
|
|
|
7485
7485
|
# Output is already printed to stdout during execution via runtime.output()
|
|
7486
|
-
#
|
|
7487
|
-
|
|
7488
|
-
|
|
7489
|
-
click.echo(f"Result: {result}")
|
|
7486
|
+
# Don't print "Result:" automatically - users should use printl() for output
|
|
7487
|
+
# This prevents unwanted output for function calls like: Function();
|
|
7488
|
+
pass
|
|
7490
7489
|
|
|
7491
7490
|
except Exception as e:
|
|
7492
7491
|
click.secho(f"CSSL Error: {e}", fg='red')
|
|
@@ -7595,75 +7594,95 @@ def cssl_doc(search, list_sections):
|
|
|
7595
7594
|
click.secho("=" * 50, fg='cyan')
|
|
7596
7595
|
click.echo()
|
|
7597
7596
|
|
|
7598
|
-
# Split into
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
found_sections = []
|
|
7602
|
-
for section in sections:
|
|
7603
|
-
if search.lower() in section.lower():
|
|
7604
|
-
found_sections.append(section)
|
|
7605
|
-
|
|
7606
|
-
if found_sections:
|
|
7607
|
-
# Also find specific lines with the search term
|
|
7608
|
-
all_lines = content.split('\n')
|
|
7609
|
-
matching_lines = []
|
|
7610
|
-
for i, line in enumerate(all_lines):
|
|
7611
|
-
if search.lower() in line.lower():
|
|
7612
|
-
# Get context (2 lines before and after)
|
|
7613
|
-
start = max(0, i - 2)
|
|
7614
|
-
end = min(len(all_lines), i + 3)
|
|
7615
|
-
context = '\n'.join(all_lines[start:end])
|
|
7616
|
-
if context not in matching_lines:
|
|
7617
|
-
matching_lines.append((i + 1, context))
|
|
7618
|
-
|
|
7619
|
-
# Show summary
|
|
7620
|
-
click.secho(f"Found in {len(found_sections)} section(s):", fg='green')
|
|
7621
|
-
for section in found_sections:
|
|
7622
|
-
# Extract section title
|
|
7623
|
-
title_match = re.match(r'^##\s+(.+)$', section, re.MULTILINE)
|
|
7624
|
-
if title_match:
|
|
7625
|
-
click.echo(f" - {title_match.group(1)}")
|
|
7597
|
+
# Split into subsections (### headers) for focused results
|
|
7598
|
+
subsections = re.split(r'(?=^### )', content, flags=re.MULTILINE)
|
|
7626
7599
|
|
|
7627
|
-
|
|
7600
|
+
# Also split into main sections (## headers)
|
|
7601
|
+
main_sections = re.split(r'(?=^## )', content, flags=re.MULTILINE)
|
|
7628
7602
|
|
|
7629
|
-
|
|
7630
|
-
|
|
7631
|
-
|
|
7603
|
+
# Find matching subsections (### level) - most focused
|
|
7604
|
+
matching_subsections = []
|
|
7605
|
+
for subsection in subsections:
|
|
7606
|
+
if search.lower() in subsection.lower():
|
|
7607
|
+
# Extract title
|
|
7608
|
+
title_match = re.match(r'^###\s+(.+)$', subsection, re.MULTILINE)
|
|
7609
|
+
if title_match:
|
|
7610
|
+
# Trim subsection to just the content until next ### or ##
|
|
7611
|
+
lines = subsection.split('\n')
|
|
7612
|
+
trimmed_lines = []
|
|
7613
|
+
for line in lines:
|
|
7614
|
+
if line.startswith('## ') and not line.startswith('### '):
|
|
7615
|
+
break
|
|
7616
|
+
trimmed_lines.append(line)
|
|
7617
|
+
matching_subsections.append((title_match.group(1), '\n'.join(trimmed_lines)))
|
|
7618
|
+
|
|
7619
|
+
if matching_subsections:
|
|
7620
|
+
click.secho(f"Found {len(matching_subsections)} matching subsection(s):", fg='green')
|
|
7621
|
+
click.echo()
|
|
7632
7622
|
|
|
7633
|
-
|
|
7634
|
-
|
|
7635
|
-
|
|
7623
|
+
# Show focused subsections (limit output)
|
|
7624
|
+
for title, sub_content in matching_subsections[:5]:
|
|
7625
|
+
click.secho(f"### {title}", fg='yellow', bold=True)
|
|
7626
|
+
# Highlight search term in content
|
|
7636
7627
|
highlighted = re.sub(
|
|
7637
7628
|
f'({re.escape(search)})',
|
|
7638
7629
|
click.style(r'\1', fg='green', bold=True),
|
|
7639
|
-
|
|
7630
|
+
sub_content,
|
|
7640
7631
|
flags=re.IGNORECASE
|
|
7641
7632
|
)
|
|
7642
|
-
|
|
7643
|
-
|
|
7644
|
-
|
|
7645
|
-
|
|
7646
|
-
|
|
7647
|
-
|
|
7648
|
-
|
|
7649
|
-
|
|
7650
|
-
|
|
7651
|
-
click.echo("(Scroll or pipe to a file for full content)")
|
|
7652
|
-
click.echo()
|
|
7653
|
-
|
|
7654
|
-
for section in found_sections:
|
|
7655
|
-
click.echo(section)
|
|
7633
|
+
# Limit lines per subsection
|
|
7634
|
+
lines = highlighted.split('\n')
|
|
7635
|
+
if len(lines) > 30:
|
|
7636
|
+
click.echo('\n'.join(lines[:30]))
|
|
7637
|
+
click.secho(f" ... ({len(lines) - 30} more lines)", fg='cyan')
|
|
7638
|
+
else:
|
|
7639
|
+
click.echo(highlighted)
|
|
7640
|
+
click.echo()
|
|
7641
|
+
click.secho("-" * 40, fg='cyan')
|
|
7656
7642
|
click.echo()
|
|
7657
7643
|
|
|
7644
|
+
if len(matching_subsections) > 5:
|
|
7645
|
+
click.secho(f"... and {len(matching_subsections) - 5} more subsections", fg='cyan')
|
|
7646
|
+
click.echo("Use --list to see all sections")
|
|
7658
7647
|
else:
|
|
7659
|
-
|
|
7660
|
-
|
|
7661
|
-
|
|
7662
|
-
|
|
7663
|
-
|
|
7664
|
-
|
|
7665
|
-
|
|
7666
|
-
|
|
7648
|
+
# Fall back to main section search (## level)
|
|
7649
|
+
found_sections = []
|
|
7650
|
+
for section in main_sections:
|
|
7651
|
+
if search.lower() in section.lower():
|
|
7652
|
+
title_match = re.match(r'^##\s+(.+)$', section, re.MULTILINE)
|
|
7653
|
+
if title_match:
|
|
7654
|
+
found_sections.append((title_match.group(1), section))
|
|
7655
|
+
|
|
7656
|
+
if found_sections:
|
|
7657
|
+
click.secho(f"Found in {len(found_sections)} section(s):", fg='green')
|
|
7658
|
+
for title, _ in found_sections:
|
|
7659
|
+
click.echo(f" - {title}")
|
|
7660
|
+
click.echo()
|
|
7661
|
+
|
|
7662
|
+
# Show first matching section, trimmed
|
|
7663
|
+
title, section = found_sections[0]
|
|
7664
|
+
click.secho(f"## {title}", fg='yellow', bold=True)
|
|
7665
|
+
highlighted = re.sub(
|
|
7666
|
+
f'({re.escape(search)})',
|
|
7667
|
+
click.style(r'\1', fg='green', bold=True),
|
|
7668
|
+
section,
|
|
7669
|
+
flags=re.IGNORECASE
|
|
7670
|
+
)
|
|
7671
|
+
lines = highlighted.split('\n')
|
|
7672
|
+
if len(lines) > 40:
|
|
7673
|
+
click.echo('\n'.join(lines[:40]))
|
|
7674
|
+
click.secho(f"\n... ({len(lines) - 40} more lines in this section)", fg='cyan')
|
|
7675
|
+
else:
|
|
7676
|
+
click.echo(highlighted)
|
|
7677
|
+
else:
|
|
7678
|
+
click.secho(f"No matches found for '{search}'", fg='yellow')
|
|
7679
|
+
click.echo()
|
|
7680
|
+
click.echo("Try searching for:")
|
|
7681
|
+
click.echo(" - Keywords: class, function, define, open, global, shuffled")
|
|
7682
|
+
click.echo(" - Syntax: $, @, ::, this->, <<==, <==, #$")
|
|
7683
|
+
click.echo(" - Types: string, int, stack, vector, map, json")
|
|
7684
|
+
click.echo()
|
|
7685
|
+
click.echo("Or use: includecpp cssl doc --list")
|
|
7667
7686
|
else:
|
|
7668
7687
|
# Full documentation mode
|
|
7669
7688
|
click.echo_via_pager(content)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# CSSL - C-Style Scripting Language
|
|
2
2
|
|
|
3
|
-
> Version 3.7.
|
|
3
|
+
> Version 3.7.6 | A modern scripting language with C++-style syntax and unique features like CodeInfusion and BruteInjection.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -41,22 +41,25 @@
|
|
|
41
41
|
```python
|
|
42
42
|
from includecpp import CSSL
|
|
43
43
|
|
|
44
|
-
#
|
|
45
|
-
CSSL.
|
|
46
|
-
|
|
47
|
-
# Execute code
|
|
48
|
-
CSSL.exec("""
|
|
44
|
+
# Execute code (v3.7.6+: use run() instead of exec())
|
|
45
|
+
CSSL.run("""
|
|
49
46
|
printl("Hello CSSL!");
|
|
50
47
|
""")
|
|
51
48
|
|
|
52
49
|
# With parameters and return value
|
|
53
|
-
result = CSSL.
|
|
50
|
+
result = CSSL.run("""
|
|
54
51
|
string name = parameter.get(0);
|
|
55
52
|
printl("Hello " + name);
|
|
56
53
|
parameter.return(true);
|
|
57
54
|
""", "World")
|
|
58
55
|
|
|
59
56
|
print(result) # True
|
|
57
|
+
|
|
58
|
+
# Create typed scripts and modules (v3.7.6+)
|
|
59
|
+
main = CSSL.script("cssl", '''printl("Main");''')
|
|
60
|
+
payload = CSSL.script("cssl-pl", '''void helper() { printl("Helper!"); }''')
|
|
61
|
+
mod = CSSL.makemodule(main, payload, "mymod")
|
|
62
|
+
mod.helper() # Call function directly
|
|
60
63
|
```
|
|
61
64
|
|
|
62
65
|
### CLI Execution
|
|
@@ -701,12 +704,24 @@ super void forceRun() {
|
|
|
701
704
|
|
|
702
705
|
### shuffled
|
|
703
706
|
|
|
704
|
-
Allows multiple return values.
|
|
707
|
+
Allows multiple return values with tuple unpacking.
|
|
705
708
|
|
|
706
709
|
```cssl
|
|
707
710
|
shuffled string getNames() {
|
|
708
711
|
return "Alice", "Bob", "Charlie";
|
|
709
712
|
}
|
|
713
|
+
|
|
714
|
+
// Tuple unpacking (v3.7.6+)
|
|
715
|
+
a, b, c = getNames();
|
|
716
|
+
printl(a); // "Alice"
|
|
717
|
+
printl(b); // "Bob"
|
|
718
|
+
printl(c); // "Charlie"
|
|
719
|
+
|
|
720
|
+
// Works with any types
|
|
721
|
+
shuffled getValues() {
|
|
722
|
+
return "text", 42, true;
|
|
723
|
+
}
|
|
724
|
+
name, num, flag = getValues();
|
|
710
725
|
```
|
|
711
726
|
|
|
712
727
|
---
|
|
@@ -1143,6 +1158,10 @@ print(stats.total) # 50 - Persisted!
|
|
|
1143
1158
|
|
|
1144
1159
|
CodeInfusion enables modifying functions at runtime.
|
|
1145
1160
|
|
|
1161
|
+
> **Important**: Injection operators must be written **without spaces**:
|
|
1162
|
+
> - ✓ `func() <<==` / `func() +<<==` / `func() -<<==` (correct)
|
|
1163
|
+
> - ✗ `func() < <==` / `func() + <<==` / `func() - <<==` (wrong)
|
|
1164
|
+
|
|
1146
1165
|
### <<== (Replace)
|
|
1147
1166
|
|
|
1148
1167
|
Replaces function content.
|
|
@@ -108,6 +108,8 @@ class TokenType(Enum):
|
|
|
108
108
|
COMMENT = auto()
|
|
109
109
|
NEWLINE = auto()
|
|
110
110
|
EOF = auto()
|
|
111
|
+
# Super-functions for .cssl-pl payload files (v3.8.0)
|
|
112
|
+
SUPER_FUNC = auto() # #$run(), #$exec(), #$printl() - pre-execution hooks
|
|
111
113
|
|
|
112
114
|
|
|
113
115
|
KEYWORDS = {
|
|
@@ -212,9 +214,14 @@ class CSSLLexer:
|
|
|
212
214
|
|
|
213
215
|
char = self.source[self.pos]
|
|
214
216
|
|
|
215
|
-
# Comments
|
|
217
|
+
# Super-functions (#$) or Comments (# and // style)
|
|
216
218
|
if char == '#':
|
|
217
|
-
self.
|
|
219
|
+
if self._peek(1) == '$':
|
|
220
|
+
# Super-function: #$run(), #$exec(), #$printl()
|
|
221
|
+
self._read_super_function()
|
|
222
|
+
else:
|
|
223
|
+
# Regular comment
|
|
224
|
+
self._skip_comment()
|
|
218
225
|
elif char == '/' and self._peek(1) == '/':
|
|
219
226
|
# C-style // comment - NEW
|
|
220
227
|
self._skip_comment()
|
|
@@ -446,6 +453,31 @@ class CSSLLexer:
|
|
|
446
453
|
else:
|
|
447
454
|
self._add_token(TokenType.IDENTIFIER, value)
|
|
448
455
|
|
|
456
|
+
def _read_super_function(self):
|
|
457
|
+
"""Read #$<name>(...) super-function call for .cssl-pl payloads.
|
|
458
|
+
|
|
459
|
+
Super-functions are pre-execution hooks that run when a payload is loaded.
|
|
460
|
+
Valid super-functions: #$run(), #$exec(), #$printl()
|
|
461
|
+
|
|
462
|
+
Syntax:
|
|
463
|
+
#$run(initFunction); // Call a function at load time
|
|
464
|
+
#$exec(setup()); // Execute expression at load time
|
|
465
|
+
#$printl("Payload loaded"); // Print at load time
|
|
466
|
+
"""
|
|
467
|
+
start = self.pos
|
|
468
|
+
self._advance() # skip '#'
|
|
469
|
+
self._advance() # skip '$'
|
|
470
|
+
|
|
471
|
+
# Read the super-function name (run, exec, printl, etc.)
|
|
472
|
+
name_start = self.pos
|
|
473
|
+
while self.pos < len(self.source) and (self.source[self.pos].isalnum() or self.source[self.pos] == '_'):
|
|
474
|
+
self._advance()
|
|
475
|
+
func_name = self.source[name_start:self.pos]
|
|
476
|
+
|
|
477
|
+
# Store as #$<name> token value
|
|
478
|
+
value = f'#${func_name}'
|
|
479
|
+
self._add_token(TokenType.SUPER_FUNC, value)
|
|
480
|
+
|
|
449
481
|
def _read_self_ref(self):
|
|
450
482
|
"""Read s@<name> or s@<name>.<member>... self-reference"""
|
|
451
483
|
start = self.pos
|
|
@@ -1377,6 +1409,9 @@ class CSSLParser:
|
|
|
1377
1409
|
elif self._looks_like_function_declaration():
|
|
1378
1410
|
# Nested typed function (e.g., void Level2() { ... })
|
|
1379
1411
|
return self._parse_typed_function()
|
|
1412
|
+
elif self._check(TokenType.SUPER_FUNC):
|
|
1413
|
+
# Super-function for .cssl-pl payload files
|
|
1414
|
+
return self._parse_super_function()
|
|
1380
1415
|
elif (self._check(TokenType.IDENTIFIER) or self._check(TokenType.AT) or
|
|
1381
1416
|
self._check(TokenType.CAPTURED_REF) or self._check(TokenType.SHARED_REF) or
|
|
1382
1417
|
self._check(TokenType.GLOBAL_REF) or self._check(TokenType.SELF_REF) or
|
|
@@ -1594,23 +1629,42 @@ class CSSLParser:
|
|
|
1594
1629
|
return ASTNode('c_for_update', value={'var': var_name, 'op': 'none'})
|
|
1595
1630
|
|
|
1596
1631
|
def _parse_python_style_for(self) -> ASTNode:
|
|
1597
|
-
"""Parse Python-style for loop: for (i in range(...)) { }
|
|
1632
|
+
"""Parse Python-style for loop: for (i in range(...)) { } or for (item in collection) { }
|
|
1598
1633
|
|
|
1599
1634
|
Supports:
|
|
1600
1635
|
for (i in range(n)) { } - 0 to n-1
|
|
1601
1636
|
for (i in range(start, end)) { } - start to end-1
|
|
1602
1637
|
for (i in range(start, end, step)) { }
|
|
1638
|
+
for (item in collection) { } - iterate over list/vector
|
|
1639
|
+
for (item in @global_collection) { } - iterate over global
|
|
1603
1640
|
"""
|
|
1604
1641
|
var_name = self._advance().value
|
|
1605
1642
|
self._expect(TokenType.KEYWORD) # 'in'
|
|
1606
1643
|
|
|
1607
|
-
#
|
|
1644
|
+
# Check if this is range() or collection iteration
|
|
1645
|
+
is_range = False
|
|
1608
1646
|
if self._check(TokenType.KEYWORD) and self._peek().value == 'range':
|
|
1609
1647
|
self._advance() # consume 'range' keyword
|
|
1648
|
+
is_range = True
|
|
1610
1649
|
elif self._check(TokenType.IDENTIFIER) and self._peek().value == 'range':
|
|
1611
1650
|
self._advance() # consume 'range' identifier
|
|
1612
|
-
|
|
1613
|
-
|
|
1651
|
+
is_range = True
|
|
1652
|
+
|
|
1653
|
+
# If not range, parse as collection iteration
|
|
1654
|
+
if not is_range:
|
|
1655
|
+
iterable = self._parse_expression()
|
|
1656
|
+
self._expect(TokenType.PAREN_END)
|
|
1657
|
+
|
|
1658
|
+
node = ASTNode('foreach', value={'var': var_name, 'iterable': iterable}, children=[])
|
|
1659
|
+
self._expect(TokenType.BLOCK_START)
|
|
1660
|
+
|
|
1661
|
+
while not self._check(TokenType.BLOCK_END) and not self._is_at_end():
|
|
1662
|
+
stmt = self._parse_statement()
|
|
1663
|
+
if stmt:
|
|
1664
|
+
node.children.append(stmt)
|
|
1665
|
+
|
|
1666
|
+
self._expect(TokenType.BLOCK_END)
|
|
1667
|
+
return node
|
|
1614
1668
|
|
|
1615
1669
|
self._expect(TokenType.PAREN_START)
|
|
1616
1670
|
first_arg = self._parse_expression()
|
|
@@ -1722,11 +1776,56 @@ class CSSLParser:
|
|
|
1722
1776
|
return node
|
|
1723
1777
|
|
|
1724
1778
|
def _parse_return(self) -> ASTNode:
|
|
1725
|
-
|
|
1779
|
+
"""Parse return statement, supporting multiple values for shuffled functions.
|
|
1780
|
+
|
|
1781
|
+
Syntax:
|
|
1782
|
+
return; // Return None
|
|
1783
|
+
return value; // Return single value
|
|
1784
|
+
return a, b, c; // Return multiple values (for shuffled)
|
|
1785
|
+
"""
|
|
1786
|
+
values = []
|
|
1726
1787
|
if not self._check(TokenType.SEMICOLON) and not self._check(TokenType.BLOCK_END):
|
|
1727
|
-
|
|
1788
|
+
values.append(self._parse_expression())
|
|
1789
|
+
|
|
1790
|
+
# Check for comma-separated return values (shuffled return)
|
|
1791
|
+
while self._check(TokenType.COMMA):
|
|
1792
|
+
self._advance() # consume comma
|
|
1793
|
+
values.append(self._parse_expression())
|
|
1794
|
+
|
|
1795
|
+
self._match(TokenType.SEMICOLON)
|
|
1796
|
+
|
|
1797
|
+
if len(values) == 0:
|
|
1798
|
+
return ASTNode('return', value=None)
|
|
1799
|
+
elif len(values) == 1:
|
|
1800
|
+
return ASTNode('return', value=values[0])
|
|
1801
|
+
else:
|
|
1802
|
+
# Multiple return values - create tuple return
|
|
1803
|
+
return ASTNode('return', value={'multiple': True, 'values': values})
|
|
1804
|
+
|
|
1805
|
+
def _parse_super_function(self) -> ASTNode:
|
|
1806
|
+
"""Parse super-function for .cssl-pl payload files.
|
|
1807
|
+
|
|
1808
|
+
Syntax:
|
|
1809
|
+
#$run(initFunction); // Call function at load time
|
|
1810
|
+
#$exec(setup()); // Execute expression at load time
|
|
1811
|
+
#$printl("Payload loaded"); // Print at load time
|
|
1812
|
+
|
|
1813
|
+
These are pre-execution hooks that run when payload() loads the file.
|
|
1814
|
+
"""
|
|
1815
|
+
token = self._advance() # Get the SUPER_FUNC token
|
|
1816
|
+
super_name = token.value # e.g., "#$run", "#$exec", "#$printl"
|
|
1817
|
+
|
|
1818
|
+
# Parse the arguments
|
|
1819
|
+
self._expect(TokenType.PAREN_START)
|
|
1820
|
+
args = []
|
|
1821
|
+
if not self._check(TokenType.PAREN_END):
|
|
1822
|
+
args.append(self._parse_expression())
|
|
1823
|
+
while self._match(TokenType.COMMA):
|
|
1824
|
+
args.append(self._parse_expression())
|
|
1825
|
+
self._expect(TokenType.PAREN_END)
|
|
1728
1826
|
self._match(TokenType.SEMICOLON)
|
|
1729
|
-
|
|
1827
|
+
|
|
1828
|
+
return ASTNode('super_func', value={'name': super_name, 'args': args})
|
|
1730
1829
|
|
|
1731
1830
|
def _parse_try(self) -> ASTNode:
|
|
1732
1831
|
node = ASTNode('try', children=[])
|
|
@@ -1813,6 +1912,25 @@ class CSSLParser:
|
|
|
1813
1912
|
def _parse_expression_statement(self) -> Optional[ASTNode]:
|
|
1814
1913
|
expr = self._parse_expression()
|
|
1815
1914
|
|
|
1915
|
+
# === TUPLE UNPACKING: a, b, c = shuffled_func() ===
|
|
1916
|
+
# Check if we have comma-separated identifiers before =
|
|
1917
|
+
if expr.type == 'identifier' and self._check(TokenType.COMMA):
|
|
1918
|
+
targets = [expr]
|
|
1919
|
+
while self._match(TokenType.COMMA):
|
|
1920
|
+
next_expr = self._parse_expression()
|
|
1921
|
+
if next_expr.type == 'identifier':
|
|
1922
|
+
targets.append(next_expr)
|
|
1923
|
+
else:
|
|
1924
|
+
# Not a simple identifier list, this is something else
|
|
1925
|
+
# Restore and fall through to normal parsing
|
|
1926
|
+
break
|
|
1927
|
+
|
|
1928
|
+
# Check if followed by =
|
|
1929
|
+
if self._match(TokenType.EQUALS):
|
|
1930
|
+
value = self._parse_expression()
|
|
1931
|
+
self._match(TokenType.SEMICOLON)
|
|
1932
|
+
return ASTNode('tuple_assignment', value={'targets': targets, 'value': value})
|
|
1933
|
+
|
|
1816
1934
|
# === BASIC INJECTION: <== (replace target with source) ===
|
|
1817
1935
|
if self._match(TokenType.INJECT_LEFT):
|
|
1818
1936
|
# Check if this is a createcmd injection with a code block
|
|
@@ -2335,17 +2453,62 @@ class CSSLParser:
|
|
|
2335
2453
|
self._expect(TokenType.COMPARE_GT) # consume >
|
|
2336
2454
|
return ASTNode('instance_ref', value=instance_name)
|
|
2337
2455
|
|
|
2338
|
-
# Check for type generic instantiation: stack<string>, vector<int>, etc.
|
|
2456
|
+
# Check for type generic instantiation: stack<string>, vector<int>, map<string, int>, etc.
|
|
2339
2457
|
# This creates a new instance of the type with the specified element type
|
|
2340
2458
|
if name in TYPE_GENERICS and self._check(TokenType.COMPARE_LT):
|
|
2341
2459
|
self._advance() # consume <
|
|
2342
2460
|
element_type = 'dynamic'
|
|
2461
|
+
value_type = None # For map<K, V>
|
|
2462
|
+
|
|
2343
2463
|
if self._check(TokenType.KEYWORD) or self._check(TokenType.IDENTIFIER):
|
|
2344
2464
|
element_type = self._advance().value
|
|
2465
|
+
|
|
2466
|
+
# Check for second type parameter (map<K, V>)
|
|
2467
|
+
if name == 'map' and self._check(TokenType.COMMA):
|
|
2468
|
+
self._advance() # consume ,
|
|
2469
|
+
if self._check(TokenType.KEYWORD) or self._check(TokenType.IDENTIFIER):
|
|
2470
|
+
value_type = self._advance().value
|
|
2471
|
+
else:
|
|
2472
|
+
value_type = 'dynamic'
|
|
2473
|
+
|
|
2345
2474
|
self._expect(TokenType.COMPARE_GT) # consume >
|
|
2475
|
+
|
|
2476
|
+
# Check for inline initialization: map<K,V>{"key": "value", ...}
|
|
2477
|
+
init_values = None
|
|
2478
|
+
if self._check(TokenType.BLOCK_START):
|
|
2479
|
+
self._advance() # consume {
|
|
2480
|
+
init_values = {}
|
|
2481
|
+
|
|
2482
|
+
while not self._check(TokenType.BLOCK_END) and not self._is_at_end():
|
|
2483
|
+
# Parse key
|
|
2484
|
+
if self._check(TokenType.STRING):
|
|
2485
|
+
key = self._advance().value
|
|
2486
|
+
elif self._check(TokenType.IDENTIFIER):
|
|
2487
|
+
key = self._advance().value
|
|
2488
|
+
else:
|
|
2489
|
+
key = str(self._parse_expression().value) if hasattr(self._parse_expression(), 'value') else 'key'
|
|
2490
|
+
|
|
2491
|
+
# Expect : or =
|
|
2492
|
+
if self._check(TokenType.COLON):
|
|
2493
|
+
self._advance()
|
|
2494
|
+
elif self._check(TokenType.EQUALS):
|
|
2495
|
+
self._advance()
|
|
2496
|
+
|
|
2497
|
+
# Parse value
|
|
2498
|
+
value = self._parse_expression()
|
|
2499
|
+
init_values[key] = value
|
|
2500
|
+
|
|
2501
|
+
# Optional comma
|
|
2502
|
+
if self._check(TokenType.COMMA):
|
|
2503
|
+
self._advance()
|
|
2504
|
+
|
|
2505
|
+
self._expect(TokenType.BLOCK_END) # consume }
|
|
2506
|
+
|
|
2346
2507
|
return ASTNode('type_instantiation', value={
|
|
2347
2508
|
'type': name,
|
|
2348
|
-
'element_type': element_type
|
|
2509
|
+
'element_type': element_type,
|
|
2510
|
+
'value_type': value_type,
|
|
2511
|
+
'init_values': init_values
|
|
2349
2512
|
})
|
|
2350
2513
|
|
|
2351
2514
|
# Check for type-parameterized function call: OpenFind<string>(0)
|