IncludeCPP 3.3.20__py3-none-any.whl → 3.4.8__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 +59 -58
- includecpp/cli/commands.py +400 -21
- includecpp/core/cppy_converter.py +143 -18
- includecpp/core/cssl/__init__.py +40 -0
- includecpp/core/cssl/cssl_builtins.py +1693 -0
- includecpp/core/cssl/cssl_events.py +621 -0
- includecpp/core/cssl/cssl_modules.py +2803 -0
- includecpp/core/cssl/cssl_parser.py +1791 -0
- includecpp/core/cssl/cssl_runtime.py +1587 -0
- includecpp/core/cssl/cssl_syntax.py +488 -0
- includecpp/core/cssl/cssl_types.py +438 -0
- includecpp/core/cssl_bridge.py +409 -0
- includecpp/core/cssl_bridge.pyi +311 -0
- includecpp/core/project_ui.py +684 -34
- includecpp/generator/parser.cpp +81 -0
- {includecpp-3.3.20.dist-info → includecpp-3.4.8.dist-info}/METADATA +48 -4
- includecpp-3.4.8.dist-info/RECORD +41 -0
- includecpp-3.3.20.dist-info/RECORD +0 -31
- {includecpp-3.3.20.dist-info → includecpp-3.4.8.dist-info}/WHEEL +0 -0
- {includecpp-3.3.20.dist-info → includecpp-3.4.8.dist-info}/entry_points.txt +0 -0
- {includecpp-3.3.20.dist-info → includecpp-3.4.8.dist-info}/licenses/LICENSE +0 -0
- {includecpp-3.3.20.dist-info → includecpp-3.4.8.dist-info}/top_level.txt +0 -0
includecpp/__init__.py
CHANGED
|
@@ -1,58 +1,59 @@
|
|
|
1
|
-
from .core.cpp_api import CppApi
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
f"
|
|
37
|
-
f"
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
f"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
1
|
+
from .core.cpp_api import CppApi
|
|
2
|
+
from .core import cssl_bridge as CSSL
|
|
3
|
+
import warnings
|
|
4
|
+
|
|
5
|
+
__version__ = "3.4.8"
|
|
6
|
+
__all__ = ["CppApi", "CSSL"]
|
|
7
|
+
|
|
8
|
+
# Module-level cache for C++ modules
|
|
9
|
+
_api_instance = None
|
|
10
|
+
_loaded_modules = {}
|
|
11
|
+
|
|
12
|
+
def _get_api():
|
|
13
|
+
"""Get or create singleton CppApi instance."""
|
|
14
|
+
global _api_instance
|
|
15
|
+
if _api_instance is None:
|
|
16
|
+
_api_instance = CppApi()
|
|
17
|
+
return _api_instance
|
|
18
|
+
|
|
19
|
+
def __getattr__(name: str):
|
|
20
|
+
"""Enable: from includecpp import fast_list
|
|
21
|
+
|
|
22
|
+
This hook is called when Python cannot find an attribute in this module.
|
|
23
|
+
It allows dynamic C++ module loading via the import system.
|
|
24
|
+
"""
|
|
25
|
+
if name.startswith('_'):
|
|
26
|
+
raise AttributeError(f"module 'includecpp' has no attribute '{name}'")
|
|
27
|
+
|
|
28
|
+
if name in _loaded_modules:
|
|
29
|
+
return _loaded_modules[name]
|
|
30
|
+
|
|
31
|
+
api = _get_api()
|
|
32
|
+
|
|
33
|
+
if name not in api.registry:
|
|
34
|
+
available = list(api.registry.keys())
|
|
35
|
+
raise AttributeError(
|
|
36
|
+
f"Module '{name}' not found. "
|
|
37
|
+
f"Available: {available}. "
|
|
38
|
+
f"Run 'includecpp rebuild' first."
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
if api.need_update(name):
|
|
42
|
+
warnings.warn(
|
|
43
|
+
f"Module '{name}' source files changed. "
|
|
44
|
+
f"Run 'includecpp rebuild' to update.",
|
|
45
|
+
UserWarning
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
module = api.include(name)
|
|
49
|
+
_loaded_modules[name] = module
|
|
50
|
+
return module
|
|
51
|
+
|
|
52
|
+
def __dir__():
|
|
53
|
+
"""List available attributes including C++ modules."""
|
|
54
|
+
base = ['CppApi', 'CSSL', '__version__']
|
|
55
|
+
try:
|
|
56
|
+
api = _get_api()
|
|
57
|
+
return sorted(set(base + list(api.registry.keys())))
|
|
58
|
+
except Exception:
|
|
59
|
+
return base
|
includecpp/cli/commands.py
CHANGED
|
@@ -65,7 +65,7 @@ def _safe_echo(text, **kwargs):
|
|
|
65
65
|
('╔', '+'), ('╗', '+'), ('╚', '+'), ('╝', '+'),
|
|
66
66
|
('┌', '+'), ('┐', '+'), ('└', '+'), ('┘', '+'),
|
|
67
67
|
('═', '-'), ('─', '-'), ('║', '|'), ('│', '|'),
|
|
68
|
-
('✗', '[X]'), ('•', '*'),
|
|
68
|
+
('✗', '[X]'), ('✓', '[OK]'), ('❌', '[X]'), ('•', '*'),
|
|
69
69
|
('→', '->'), ('▶', '>'), ('◆', '*'),
|
|
70
70
|
('\u2011', '-'), ('\u2010', '-'),
|
|
71
71
|
('\u2013', '-'), ('\u2014', '--'),
|
|
@@ -149,13 +149,13 @@ def _render_readme_with_colors(readme_text):
|
|
|
149
149
|
|
|
150
150
|
def _show_changelog():
|
|
151
151
|
"""Extract and display changelog from README."""
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
152
|
+
_safe_echo("=" * 70)
|
|
153
|
+
_safe_echo("IncludeCPP Changelog", fg='cyan', bold=True)
|
|
154
|
+
_safe_echo("=" * 70)
|
|
155
|
+
_safe_echo("")
|
|
156
156
|
|
|
157
157
|
try:
|
|
158
|
-
|
|
158
|
+
_safe_echo(" Fetching changelog from PyPI...", nl=False)
|
|
159
159
|
req = urllib.request.Request(
|
|
160
160
|
"https://pypi.org/pypi/IncludeCPP/json",
|
|
161
161
|
headers={"User-Agent": "IncludeCPP-CLI"}
|
|
@@ -166,12 +166,12 @@ def _show_changelog():
|
|
|
166
166
|
data = json.loads(raw_data)
|
|
167
167
|
description = data.get('info', {}).get('description', '')
|
|
168
168
|
version = data.get('info', {}).get('version', 'unknown')
|
|
169
|
-
|
|
170
|
-
|
|
169
|
+
_safe_echo(" OK", fg='green')
|
|
170
|
+
_safe_echo("")
|
|
171
171
|
|
|
172
172
|
if description:
|
|
173
|
-
|
|
174
|
-
|
|
173
|
+
_safe_echo(f"Current Version: {version}", fg='green', bold=True)
|
|
174
|
+
_safe_echo("")
|
|
175
175
|
|
|
176
176
|
lines = description.split('\n')
|
|
177
177
|
in_changelog = False
|
|
@@ -190,23 +190,23 @@ def _show_changelog():
|
|
|
190
190
|
for line in changelog_lines:
|
|
191
191
|
stripped = line.strip()
|
|
192
192
|
if stripped.startswith('## '):
|
|
193
|
-
|
|
193
|
+
_safe_echo(stripped[3:], fg='yellow', bold=True)
|
|
194
194
|
elif stripped.startswith('- '):
|
|
195
|
-
|
|
195
|
+
_safe_echo(" " + stripped)
|
|
196
196
|
elif stripped:
|
|
197
|
-
|
|
197
|
+
_safe_echo(" " + stripped)
|
|
198
198
|
else:
|
|
199
|
-
|
|
199
|
+
_safe_echo("No changelog found in README.", fg='yellow')
|
|
200
200
|
else:
|
|
201
|
-
|
|
201
|
+
_safe_echo("No documentation available.", fg='yellow')
|
|
202
202
|
|
|
203
203
|
except Exception as e:
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
204
|
+
_safe_echo(" FAILED", fg='red')
|
|
205
|
+
_safe_echo("")
|
|
206
|
+
_safe_echo("Could not fetch changelog: " + str(e), fg='red', err=True)
|
|
207
207
|
|
|
208
|
-
|
|
209
|
-
|
|
208
|
+
_safe_echo("")
|
|
209
|
+
_safe_echo("=" * 70)
|
|
210
210
|
|
|
211
211
|
|
|
212
212
|
@click.group(invoke_without_command=True)
|
|
@@ -4436,8 +4436,10 @@ def fix(module_name, all_modules, exclude, undo, auto_fix, verbose, use_ai):
|
|
|
4436
4436
|
if var_decl:
|
|
4437
4437
|
var_name = var_decl.group(1)
|
|
4438
4438
|
# Check if variable appears again in rest of content
|
|
4439
|
+
# v3.4.1: Use word boundaries to avoid false positives from substring matches
|
|
4439
4440
|
rest_content = '\n'.join(lines[i:])
|
|
4440
|
-
|
|
4441
|
+
uses = len(re.findall(rf'\b{re.escape(var_name)}\b', rest_content))
|
|
4442
|
+
if uses <= 1:
|
|
4441
4443
|
add_issue('info', 'Mistake', file_path, i, 'C003',
|
|
4442
4444
|
f"Variable '{var_name}' may be unused",
|
|
4443
4445
|
"Remove unused variable or mark as [[maybe_unused]]")
|
|
@@ -7133,6 +7135,383 @@ def cppy_types():
|
|
|
7133
7135
|
click.echo("=" * 60)
|
|
7134
7136
|
|
|
7135
7137
|
|
|
7138
|
+
# ============================================================================
|
|
7139
|
+
# EXEC - Interactive Code Execution
|
|
7140
|
+
# ============================================================================
|
|
7141
|
+
|
|
7142
|
+
@cli.command()
|
|
7143
|
+
@click.argument('lang', type=click.Choice(['py', 'cpp', 'python', 'c++']))
|
|
7144
|
+
@click.argument('path', required=False, type=click.Path())
|
|
7145
|
+
@click.option('--all', 'import_all', is_flag=True, help='Import all available modules')
|
|
7146
|
+
def exec(lang, path, import_all):
|
|
7147
|
+
"""Execute code interactively for quick testing.
|
|
7148
|
+
|
|
7149
|
+
Run Python or C++ code snippets without creating files.
|
|
7150
|
+
Perfect for testing your IncludeCPP modules quickly.
|
|
7151
|
+
|
|
7152
|
+
\b
|
|
7153
|
+
Usage:
|
|
7154
|
+
includecpp exec py # Interactive Python
|
|
7155
|
+
includecpp exec cpp # Interactive C++
|
|
7156
|
+
includecpp exec py mymodule # Auto-import mymodule
|
|
7157
|
+
includecpp exec py plugins/x.cp # Auto-import from plugin
|
|
7158
|
+
includecpp exec py --all # Import all modules
|
|
7159
|
+
|
|
7160
|
+
\b
|
|
7161
|
+
Controls:
|
|
7162
|
+
ENTER = Add new line
|
|
7163
|
+
Empty line = Execute code (press ENTER twice)
|
|
7164
|
+
CTRL+C = Cancel
|
|
7165
|
+
|
|
7166
|
+
\b
|
|
7167
|
+
Examples:
|
|
7168
|
+
$ includecpp exec py fast_math
|
|
7169
|
+
>>> x = fast_math.add(1, 2)
|
|
7170
|
+
>>> print(x)
|
|
7171
|
+
>>>
|
|
7172
|
+
3
|
|
7173
|
+
"""
|
|
7174
|
+
import sys
|
|
7175
|
+
import subprocess
|
|
7176
|
+
import tempfile
|
|
7177
|
+
from pathlib import Path as PathLib
|
|
7178
|
+
|
|
7179
|
+
# Normalize language
|
|
7180
|
+
is_python = lang in ('py', 'python')
|
|
7181
|
+
lang_name = 'Python' if is_python else 'C++'
|
|
7182
|
+
|
|
7183
|
+
# Build imports/includes
|
|
7184
|
+
imports = []
|
|
7185
|
+
includes = []
|
|
7186
|
+
|
|
7187
|
+
if import_all:
|
|
7188
|
+
# Import all available modules
|
|
7189
|
+
try:
|
|
7190
|
+
from ..core.cpp_api import CppApi
|
|
7191
|
+
api = CppApi()
|
|
7192
|
+
modules = list(api.registry.keys())
|
|
7193
|
+
if is_python:
|
|
7194
|
+
for mod in modules:
|
|
7195
|
+
imports.append(f'from includecpp import {mod}')
|
|
7196
|
+
if modules:
|
|
7197
|
+
click.secho(f"Auto-importing {len(modules)} modules: {', '.join(modules)}", fg='cyan')
|
|
7198
|
+
else:
|
|
7199
|
+
for mod in modules:
|
|
7200
|
+
includes.append(f'#include "{mod}.h"')
|
|
7201
|
+
if modules:
|
|
7202
|
+
click.secho(f"Auto-including {len(modules)} headers", fg='cyan')
|
|
7203
|
+
except Exception:
|
|
7204
|
+
click.secho("Warning: Could not load module registry", fg='yellow')
|
|
7205
|
+
|
|
7206
|
+
elif path:
|
|
7207
|
+
path_obj = PathLib(path)
|
|
7208
|
+
module_name = None
|
|
7209
|
+
|
|
7210
|
+
# Check if it's a .cp plugin file
|
|
7211
|
+
if path.endswith('.cp') or '/plugins/' in path or '\\plugins\\' in path:
|
|
7212
|
+
# Extract module name from plugin path
|
|
7213
|
+
module_name = path_obj.stem
|
|
7214
|
+
elif path_obj.exists():
|
|
7215
|
+
# It's a file path
|
|
7216
|
+
module_name = path_obj.stem
|
|
7217
|
+
else:
|
|
7218
|
+
# Assume it's a module name directly
|
|
7219
|
+
module_name = path
|
|
7220
|
+
|
|
7221
|
+
if module_name:
|
|
7222
|
+
if is_python:
|
|
7223
|
+
imports.append(f'from includecpp import {module_name}')
|
|
7224
|
+
click.secho(f"Auto-importing: {module_name}", fg='cyan')
|
|
7225
|
+
else:
|
|
7226
|
+
includes.append(f'#include "{module_name}.h"')
|
|
7227
|
+
click.secho(f"Auto-including: {module_name}.h", fg='cyan')
|
|
7228
|
+
|
|
7229
|
+
# Show header
|
|
7230
|
+
click.echo()
|
|
7231
|
+
click.secho(f"=== IncludeCPP {lang_name} REPL ===", fg='cyan', bold=True)
|
|
7232
|
+
click.echo("Enter code line by line. Press ENTER on empty line to execute.")
|
|
7233
|
+
click.echo("Press CTRL+C to cancel.")
|
|
7234
|
+
click.echo()
|
|
7235
|
+
|
|
7236
|
+
# Show pre-loaded imports
|
|
7237
|
+
if imports:
|
|
7238
|
+
click.secho("Pre-loaded:", fg='green')
|
|
7239
|
+
for imp in imports:
|
|
7240
|
+
click.echo(f" {imp}")
|
|
7241
|
+
click.echo()
|
|
7242
|
+
|
|
7243
|
+
if includes:
|
|
7244
|
+
click.secho("Pre-loaded:", fg='green')
|
|
7245
|
+
for inc in includes:
|
|
7246
|
+
click.echo(f" {inc}")
|
|
7247
|
+
click.echo()
|
|
7248
|
+
|
|
7249
|
+
# Collect code lines
|
|
7250
|
+
lines = []
|
|
7251
|
+
prompt = '>>> ' if is_python else 'cpp> '
|
|
7252
|
+
continuation = '... ' if is_python else ' > '
|
|
7253
|
+
|
|
7254
|
+
try:
|
|
7255
|
+
while True:
|
|
7256
|
+
try:
|
|
7257
|
+
# Determine prompt
|
|
7258
|
+
current_prompt = prompt if not lines else continuation
|
|
7259
|
+
line = input(current_prompt)
|
|
7260
|
+
|
|
7261
|
+
# Empty line = execute
|
|
7262
|
+
if not line.strip():
|
|
7263
|
+
if lines:
|
|
7264
|
+
break
|
|
7265
|
+
continue
|
|
7266
|
+
|
|
7267
|
+
lines.append(line)
|
|
7268
|
+
|
|
7269
|
+
except EOFError:
|
|
7270
|
+
break
|
|
7271
|
+
|
|
7272
|
+
except KeyboardInterrupt:
|
|
7273
|
+
click.echo()
|
|
7274
|
+
click.secho("Cancelled.", fg='yellow')
|
|
7275
|
+
return
|
|
7276
|
+
|
|
7277
|
+
if not lines:
|
|
7278
|
+
click.secho("No code entered.", fg='yellow')
|
|
7279
|
+
return
|
|
7280
|
+
|
|
7281
|
+
# Build full code
|
|
7282
|
+
code_lines = imports + [''] + lines if imports else lines
|
|
7283
|
+
|
|
7284
|
+
click.echo()
|
|
7285
|
+
click.secho("--- Output ---", fg='green')
|
|
7286
|
+
|
|
7287
|
+
if is_python:
|
|
7288
|
+
# Execute Python code
|
|
7289
|
+
full_code = '\n'.join(code_lines)
|
|
7290
|
+
try:
|
|
7291
|
+
# Use exec with captured output
|
|
7292
|
+
import io
|
|
7293
|
+
from contextlib import redirect_stdout, redirect_stderr
|
|
7294
|
+
|
|
7295
|
+
stdout_capture = io.StringIO()
|
|
7296
|
+
stderr_capture = io.StringIO()
|
|
7297
|
+
|
|
7298
|
+
# Create execution context
|
|
7299
|
+
exec_globals = {'__name__': '__main__'}
|
|
7300
|
+
|
|
7301
|
+
with redirect_stdout(stdout_capture), redirect_stderr(stderr_capture):
|
|
7302
|
+
exec(full_code, exec_globals)
|
|
7303
|
+
|
|
7304
|
+
stdout_val = stdout_capture.getvalue()
|
|
7305
|
+
stderr_val = stderr_capture.getvalue()
|
|
7306
|
+
|
|
7307
|
+
if stdout_val:
|
|
7308
|
+
click.echo(stdout_val, nl=False)
|
|
7309
|
+
if stderr_val:
|
|
7310
|
+
click.secho(stderr_val, fg='red', nl=False)
|
|
7311
|
+
|
|
7312
|
+
if not stdout_val and not stderr_val:
|
|
7313
|
+
click.secho("(no output)", fg='bright_black')
|
|
7314
|
+
|
|
7315
|
+
except Exception as e:
|
|
7316
|
+
click.secho(f"Error: {e}", fg='red')
|
|
7317
|
+
|
|
7318
|
+
else:
|
|
7319
|
+
# Execute C++ code
|
|
7320
|
+
# Build a complete C++ program
|
|
7321
|
+
cpp_code_lines = [
|
|
7322
|
+
'#include <iostream>',
|
|
7323
|
+
'#include <vector>',
|
|
7324
|
+
'#include <string>',
|
|
7325
|
+
'#include <algorithm>',
|
|
7326
|
+
'#include <cmath>',
|
|
7327
|
+
'using namespace std;',
|
|
7328
|
+
''
|
|
7329
|
+
]
|
|
7330
|
+
cpp_code_lines.extend(includes)
|
|
7331
|
+
cpp_code_lines.append('')
|
|
7332
|
+
cpp_code_lines.append('int main() {')
|
|
7333
|
+
|
|
7334
|
+
# Indent user code
|
|
7335
|
+
for line in lines:
|
|
7336
|
+
cpp_code_lines.append(' ' + line)
|
|
7337
|
+
|
|
7338
|
+
cpp_code_lines.append(' return 0;')
|
|
7339
|
+
cpp_code_lines.append('}')
|
|
7340
|
+
|
|
7341
|
+
full_code = '\n'.join(cpp_code_lines)
|
|
7342
|
+
|
|
7343
|
+
# Write to temp file and compile
|
|
7344
|
+
with tempfile.NamedTemporaryFile(mode='w', suffix='.cpp', delete=False, encoding='utf-8') as f:
|
|
7345
|
+
f.write(full_code)
|
|
7346
|
+
cpp_file = f.name
|
|
7347
|
+
|
|
7348
|
+
exe_file = cpp_file.replace('.cpp', '.exe' if sys.platform == 'win32' else '')
|
|
7349
|
+
|
|
7350
|
+
try:
|
|
7351
|
+
# Compile
|
|
7352
|
+
compile_cmd = ['g++', '-std=c++17', '-o', exe_file, cpp_file]
|
|
7353
|
+
result = subprocess.run(compile_cmd, capture_output=True, text=True)
|
|
7354
|
+
|
|
7355
|
+
if result.returncode != 0:
|
|
7356
|
+
click.secho("Compilation Error:", fg='red')
|
|
7357
|
+
click.echo(result.stderr)
|
|
7358
|
+
else:
|
|
7359
|
+
# Run
|
|
7360
|
+
run_result = subprocess.run([exe_file], capture_output=True, text=True, timeout=10)
|
|
7361
|
+
if run_result.stdout:
|
|
7362
|
+
click.echo(run_result.stdout, nl=False)
|
|
7363
|
+
if run_result.stderr:
|
|
7364
|
+
click.secho(run_result.stderr, fg='red', nl=False)
|
|
7365
|
+
if not run_result.stdout and not run_result.stderr:
|
|
7366
|
+
click.secho("(no output)", fg='bright_black')
|
|
7367
|
+
|
|
7368
|
+
except subprocess.TimeoutExpired:
|
|
7369
|
+
click.secho("Execution timed out (10s limit)", fg='red')
|
|
7370
|
+
except FileNotFoundError:
|
|
7371
|
+
click.secho("Error: g++ not found. Install a C++ compiler.", fg='red')
|
|
7372
|
+
except Exception as e:
|
|
7373
|
+
click.secho(f"Error: {e}", fg='red')
|
|
7374
|
+
finally:
|
|
7375
|
+
# Cleanup temp files
|
|
7376
|
+
import os
|
|
7377
|
+
try:
|
|
7378
|
+
os.unlink(cpp_file)
|
|
7379
|
+
if os.path.exists(exe_file):
|
|
7380
|
+
os.unlink(exe_file)
|
|
7381
|
+
except Exception:
|
|
7382
|
+
pass
|
|
7383
|
+
|
|
7384
|
+
click.echo()
|
|
7385
|
+
click.secho("--------------", fg='green')
|
|
7386
|
+
|
|
7387
|
+
|
|
7388
|
+
# ============================================================================
|
|
7389
|
+
# CSSL - Hidden Command Group
|
|
7390
|
+
# ============================================================================
|
|
7391
|
+
|
|
7392
|
+
@click.group(hidden=True)
|
|
7393
|
+
def cssl():
|
|
7394
|
+
"""CSSL scripting commands."""
|
|
7395
|
+
pass
|
|
7396
|
+
|
|
7397
|
+
|
|
7398
|
+
@cssl.command(name='exec')
|
|
7399
|
+
@click.argument('path', required=False, type=click.Path())
|
|
7400
|
+
@click.option('--code', '-c', type=str, help='Execute code directly')
|
|
7401
|
+
def cssl_exec(path, code):
|
|
7402
|
+
"""Execute CSSL code or file."""
|
|
7403
|
+
from pathlib import Path as PathLib
|
|
7404
|
+
|
|
7405
|
+
try:
|
|
7406
|
+
from ..core.cssl_bridge import CsslLang
|
|
7407
|
+
except ImportError as e:
|
|
7408
|
+
click.secho(f"CSSL runtime not available: {e}", fg='red')
|
|
7409
|
+
return
|
|
7410
|
+
|
|
7411
|
+
cssl_lang = CsslLang()
|
|
7412
|
+
|
|
7413
|
+
# Determine source
|
|
7414
|
+
if code:
|
|
7415
|
+
source = code
|
|
7416
|
+
elif path:
|
|
7417
|
+
path_obj = PathLib(path)
|
|
7418
|
+
if not path_obj.exists():
|
|
7419
|
+
click.secho(f"File not found: {path}", fg='red')
|
|
7420
|
+
return
|
|
7421
|
+
source = path_obj.read_text(encoding='utf-8')
|
|
7422
|
+
else:
|
|
7423
|
+
# Interactive mode
|
|
7424
|
+
click.secho("=== CSSL REPL ===", fg='magenta', bold=True)
|
|
7425
|
+
click.echo("Enter CSSL code. Empty line to execute. CTRL+C to cancel.")
|
|
7426
|
+
click.echo()
|
|
7427
|
+
|
|
7428
|
+
lines = []
|
|
7429
|
+
prompt = 'cssl> '
|
|
7430
|
+
|
|
7431
|
+
try:
|
|
7432
|
+
while True:
|
|
7433
|
+
try:
|
|
7434
|
+
line = input(prompt)
|
|
7435
|
+
if not line.strip():
|
|
7436
|
+
if lines:
|
|
7437
|
+
break
|
|
7438
|
+
continue
|
|
7439
|
+
lines.append(line)
|
|
7440
|
+
except EOFError:
|
|
7441
|
+
break
|
|
7442
|
+
except KeyboardInterrupt:
|
|
7443
|
+
click.echo()
|
|
7444
|
+
click.secho("Cancelled.", fg='yellow')
|
|
7445
|
+
return
|
|
7446
|
+
|
|
7447
|
+
if not lines:
|
|
7448
|
+
click.secho("No code entered.", fg='yellow')
|
|
7449
|
+
return
|
|
7450
|
+
|
|
7451
|
+
source = '\n'.join(lines)
|
|
7452
|
+
|
|
7453
|
+
# Execute
|
|
7454
|
+
click.secho("--- Output ---", fg='green')
|
|
7455
|
+
try:
|
|
7456
|
+
result = cssl_lang.exec(source)
|
|
7457
|
+
|
|
7458
|
+
# Print output buffer
|
|
7459
|
+
for line in cssl_lang.get_output():
|
|
7460
|
+
click.echo(line)
|
|
7461
|
+
|
|
7462
|
+
if result is not None:
|
|
7463
|
+
click.echo(f"Result: {result}")
|
|
7464
|
+
|
|
7465
|
+
except Exception as e:
|
|
7466
|
+
click.secho(f"CSSL Error: {e}", fg='red')
|
|
7467
|
+
|
|
7468
|
+
click.secho("--------------", fg='green')
|
|
7469
|
+
|
|
7470
|
+
|
|
7471
|
+
@cssl.command(name='makemodule')
|
|
7472
|
+
@click.argument('path', type=click.Path(exists=True))
|
|
7473
|
+
@click.option('--output', '-o', type=click.Path(), help='Output path for .cssl-mod')
|
|
7474
|
+
def cssl_makemodule(path, output):
|
|
7475
|
+
"""Create a .cssl-mod module from Python/C++ file."""
|
|
7476
|
+
from pathlib import Path as PathLib
|
|
7477
|
+
import pickle
|
|
7478
|
+
import base64
|
|
7479
|
+
|
|
7480
|
+
path_obj = PathLib(path)
|
|
7481
|
+
suffix = path_obj.suffix.lower()
|
|
7482
|
+
|
|
7483
|
+
if suffix not in ('.py', '.cpp', '.cp', '.h'):
|
|
7484
|
+
click.secho(f"Unsupported file type: {suffix}", fg='red')
|
|
7485
|
+
click.echo("Supported: .py, .cpp, .cp, .h")
|
|
7486
|
+
return
|
|
7487
|
+
|
|
7488
|
+
# Read source
|
|
7489
|
+
source = path_obj.read_text(encoding='utf-8')
|
|
7490
|
+
|
|
7491
|
+
# Create module data
|
|
7492
|
+
module_data = {
|
|
7493
|
+
'name': path_obj.stem,
|
|
7494
|
+
'type': 'python' if suffix == '.py' else 'cpp',
|
|
7495
|
+
'source': source,
|
|
7496
|
+
'version': '1.0',
|
|
7497
|
+
}
|
|
7498
|
+
|
|
7499
|
+
# Encode as base64 pickle
|
|
7500
|
+
encoded = base64.b64encode(pickle.dumps(module_data)).decode('utf-8')
|
|
7501
|
+
|
|
7502
|
+
# Write .cssl-mod file
|
|
7503
|
+
out_path = PathLib(output) if output else path_obj.with_suffix('.cssl-mod')
|
|
7504
|
+
out_path.write_text(f"CSSLMOD1\n{encoded}", encoding='utf-8')
|
|
7505
|
+
|
|
7506
|
+
click.secho(f"Created: {out_path}", fg='green')
|
|
7507
|
+
click.echo(f" Name: {module_data['name']}")
|
|
7508
|
+
click.echo(f" Type: {module_data['type']}")
|
|
7509
|
+
|
|
7510
|
+
|
|
7511
|
+
# Register hidden cssl command group
|
|
7512
|
+
cli.add_command(cssl)
|
|
7513
|
+
|
|
7514
|
+
|
|
7136
7515
|
# ============================================================================
|
|
7137
7516
|
# Conditional Registration of Experimental Commands
|
|
7138
7517
|
# ============================================================================
|