Add files via upload

这个提交包含在:
2026-04-06 17:15:32 +08:00
提交者 GitHub
父节点 423c0898ad
当前提交 0fd67de6f2
修改 4 个文件,包含 3502 行新增0 行删除
+653
查看文件
@@ -0,0 +1,653 @@
#!/usr/bin/env python3
import os
import sys
import subprocess
import platform
from pathlib import Path
# 定义颜色类
class Colors:
RESET = '\033[0m'
RED = '\033[31m'
GREEN = '\033[32m'
YELLOW = '\033[33m'
BLUE = '\033[34m'
MAGENTA = '\033[35m'
CYAN = '\033[36m'
WHITE = '\033[37m'
BOLD = '\033[1m'
BOLD_GREEN = '\033[1;32m'
BOLD_YELLOW = '\033[1;33m'
BOLD_CYAN = '\033[1;36m'
BOLD_RED = '\033[1;31m'
# 确保Windows终端支持ANSI颜色
def enable_windows_ansi_support():
if platform.system() == 'Windows':
try:
import ctypes
kernel32 = ctypes.windll.kernel32
kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7)
except:
pass
# 打印带颜色的文本
def print_color(text, color=Colors.RESET):
print(f"{color}{text}{Colors.RESET}")
# 运行命令并返回结果
def run_command(cmd, cwd=None, shell=True, check=False):
try:
result = subprocess.run(cmd, cwd=cwd, shell=shell, check=check,
capture_output=True, text=True)
return result
except subprocess.CalledProcessError as e:
return e
# 构建Windows EXE
def build_exe():
print_color("\n========================================", Colors.BOLD_CYAN)
print_color("Building Windows EXE", Colors.BOLD_YELLOW)
print_color("========================================", Colors.BOLD_CYAN)
print()
print_color("Checking PyInstaller...", Colors.CYAN)
result = run_command("pip show pyinstaller", check=False)
if result.returncode != 0:
print_color("PyInstaller not found, installing...", Colors.YELLOW)
result = run_command("pip install pyinstaller", check=True)
if result.returncode != 0:
print_color("Failed to install PyInstaller", Colors.BOLD_RED)
input("Press Enter to continue...")
return False
print_color("Building scl.py...", Colors.CYAN)
result = run_command(
"pyinstaller --onefile --name scl --distpath dist\\exe --workpath build\\exe --specpath build\\exe scl.py",
check=True
)
if result.returncode != 0:
print_color("Failed to build scl.py", Colors.BOLD_RED)
input("Press Enter to continue...")
return False
print()
print_color("EXE build completed!", Colors.BOLD_GREEN)
print_color("Output directory: dist\\exe", Colors.GREEN)
print()
print_color("Copying plugins directory...", Colors.CYAN)
os.makedirs("dist\\exe\\plugins", exist_ok=True)
result = run_command("xcopy /E /I /Y plugins dist\\exe\\plugins", check=False)
print()
input("Press Enter to continue...")
return True
# 构建Windows EXE - 愚人节版本
def build_exe_april_fools():
print_color("\n========================================", Colors.BOLD_CYAN)
print_color("Building Windows EXE - April Fools Edition", Colors.BOLD_YELLOW)
print_color("========================================", Colors.BOLD_CYAN)
print()
print_color("Checking PyInstaller...", Colors.CYAN)
result = run_command("pip show pyinstaller", check=False)
if result.returncode != 0:
print_color("PyInstaller not found, installing...", Colors.YELLOW)
result = run_command("pip install pyinstaller", check=True)
if result.returncode != 0:
print_color("Failed to install PyInstaller", Colors.BOLD_RED)
input("Press Enter to continue...")
return False
if not os.path.exists("sdp_yrj.py"):
print_color("Error: sdp_yrj.py not found", Colors.BOLD_RED)
input("Press Enter to continue...")
return False
print_color("Building sdp_yrj.py...", Colors.CYAN)
result = run_command(
"pyinstaller --onefile --name sdp_yrj --distpath dist\\exe --workpath build\\exe --specpath build\\exe sdp_yrj.py",
check=False
)
if result.returncode != 0:
print_color("Failed to build sdp_yrj.py", Colors.BOLD_RED)
else:
print_color("Successfully built sdp_yrj.exe", Colors.BOLD_GREEN)
print()
print_color("April Fools EXE build completed!", Colors.BOLD_GREEN)
print_color("Output directory: dist\\exe", Colors.GREEN)
print()
print_color("Copying plugins directory...", Colors.CYAN)
os.makedirs("dist\\exe\\plugins", exist_ok=True)
result = run_command("xcopy /E /I /Y plugins dist\\exe\\plugins", check=False)
print()
input("Press Enter to continue...")
return True
# 构建Linux DEB - SCL Full Package (via WSL)
def build_deb():
print_color("\n========================================", Colors.BOLD_CYAN)
print_color("Building Linux DEB via WSL", Colors.BOLD_YELLOW)
print_color("========================================", Colors.BOLD_CYAN)
print()
print_color("Checking WSL...", Colors.CYAN)
result = run_command("wsl echo 'WSL OK'", check=False)
if result.returncode != 0:
print_color("WSL is not installed or not available", Colors.BOLD_RED)
print_color("Please install WSL first:", Colors.YELLOW)
print_color(" wsl --install", Colors.GREEN)
input("Press Enter to continue...")
return False
print_color("WSL found. Preparing build environment...", Colors.GREEN)
# 获取当前目录的WSL路径
result = run_command("wsl wslpath '%cd%'", check=True)
wsl_path = result.stdout.strip()
print_color(f"WSL path: {wsl_path}", Colors.BLUE)
print_color("Creating dist directory...", Colors.CYAN)
os.makedirs("dist", exist_ok=True)
print_color("Copying build script to WSL...", Colors.CYAN)
result = run_command(f"wsl cp '{wsl_path}/build_deb_wsl.sh' /tmp/build_deb_wsl.sh", check=True)
result = run_command("wsl chmod +x /tmp/build_deb_wsl.sh", check=True)
print_color("Building DEB package in WSL...", Colors.CYAN)
result = run_command(f"wsl /tmp/build_deb_wsl.sh '{wsl_path}'", check=True)
if result.returncode != 0:
print()
print_color("Failed to build DEB package", Colors.BOLD_RED)
print_color("Make sure dpkg-deb is available in WSL", Colors.YELLOW)
print_color("Run: wsl sudo apt update ^&^& wsl sudo apt install dpkg-dev", Colors.GREEN)
input("Press Enter to continue...")
return False
print()
print_color("DEB build completed!", Colors.BOLD_GREEN)
print_color("Output file: dist\\scl-1.0.0.deb", Colors.GREEN)
print()
input("Press Enter to continue...")
return True
# 构建Linux DEB - SDP Only (via WSL)
def build_sdp_deb():
print_color("\n========================================", Colors.BOLD_CYAN)
print_color("Building Linux DEB - SDP Only (via WSL)", Colors.BOLD_YELLOW)
print_color("========================================", Colors.BOLD_CYAN)
print()
print_color("Checking WSL...", Colors.CYAN)
result = run_command("wsl echo 'WSL OK'", check=False)
if result.returncode != 0:
print_color("WSL is not installed or not available", Colors.BOLD_RED)
print_color("Please install WSL first:", Colors.YELLOW)
print_color(" wsl --install", Colors.GREEN)
input("Press Enter to continue...")
return False
print_color("WSL found. Preparing build environment...", Colors.GREEN)
# 获取当前目录的WSL路径
result = run_command("wsl wslpath '%cd%'", check=True)
wsl_path = result.stdout.strip()
print_color(f"WSL path: {wsl_path}", Colors.BLUE)
print_color("Creating dist directory...", Colors.CYAN)
os.makedirs("dist", exist_ok=True)
print_color("Copying build script to WSL...", Colors.CYAN)
result = run_command(f"wsl cp '{wsl_path}/build_sdp_deb.sh' /tmp/build_sdp_deb.sh", check=True)
print_color("Building SDP DEB package in WSL...", Colors.CYAN)
result = run_command(f"wsl /tmp/build_sdp_deb.sh '{wsl_path}'", check=True)
if result.returncode != 0:
print()
print_color("Failed to build SDP DEB package", Colors.BOLD_RED)
print_color("Make sure dpkg-deb is available in WSL", Colors.YELLOW)
print_color("Run: wsl sudo apt update ^&^& wsl sudo apt install dpkg-dev", Colors.GREEN)
input("Press Enter to continue...")
return False
print()
print_color("SDP DEB build completed!", Colors.BOLD_GREEN)
print_color("Output file: dist\\scl-sdp-1.0.0.deb", Colors.GREEN)
print()
input("Press Enter to continue...")
return True
# 构建Linux DEB - SDP April Fools Edition (via WSL)
def build_sdp_deb_april_fools():
print_color("\n========================================", Colors.BOLD_CYAN)
print_color("Building Linux DEB - SDP April Fools Edition (via WSL)", Colors.BOLD_YELLOW)
print_color("========================================", Colors.BOLD_CYAN)
print()
if not os.path.exists("sdp_yrj.py"):
print_color("Error: sdp_yrj.py not found", Colors.BOLD_RED)
input("Press Enter to continue...")
return False
print_color("Checking WSL...", Colors.CYAN)
result = run_command("wsl echo 'WSL OK'", check=False)
if result.returncode != 0:
print_color("WSL is not installed or not available", Colors.BOLD_RED)
print_color("Please install WSL first:", Colors.YELLOW)
print_color(" wsl --install", Colors.GREEN)
input("Press Enter to continue...")
return False
print_color("WSL found. Preparing build environment...", Colors.GREEN)
# 获取当前目录的WSL路径
result = run_command("wsl wslpath '%cd%'", check=True)
wsl_path = result.stdout.strip()
print_color(f"WSL path: {wsl_path}", Colors.BLUE)
print_color("Creating dist directory...", Colors.CYAN)
os.makedirs("dist", exist_ok=True)
# 创建愚人节版本的构建脚本
print_color("Creating April Fools build script...", Colors.CYAN)
sdp_yrj_deb_script = '''#!/bin/bash
set -e
WSL_PATH="$1"
VERSION="1.0.0"
cd "$WSL_PATH"
# 创建临时目录
mkdir -p deb_temp/usr/local/bin
mkdir -p deb_temp/DEBIAN
# 复制sdp_yrj.py
echo "Copying sdp_yrj.py..."
cp sdp_yrj.py deb_temp/usr/local/bin/sdp_yrj
chmod +x deb_temp/usr/local/bin/sdp_yrj
# 复制插件目录
echo "Copying plugins directory..."
mkdir -p deb_temp/usr/local/lib/scl/plugins
cp -r plugins/* deb_temp/usr/local/lib/scl/plugins/
# 创建DEBIAN控制文件
echo "Creating DEBIAN control file..."
cat > deb_temp/DEBIAN/control << 'EOF'
Package: scl-sdp-yrj
Version: 1.0.0
Section: utils
Priority: optional
Architecture: all
Depends: python3
Maintainer: SCL Team
Description: SCL Package Manager - April Fools Edition
EOF
# 构建DEB包
echo "Building DEB package..."
dpkg-deb --build deb_temp "$WSL_PATH/dist/scl-sdp-yrj-1.0.0.deb"
# 清理
echo "Cleaning up..."
rm -rf deb_temp
echo "SDP April Fools DEB build completed!"
echo "Output: $WSL_PATH/dist/scl-sdp-yrj-1.0.0.deb"
'''
# 写入构建脚本
with open("build_sdp_yrj_deb.sh", "w") as f:
f.write(sdp_yrj_deb_script)
# 为脚本添加执行权限
os.chmod("build_sdp_yrj_deb.sh", 0o755)
print_color("Copying build script to WSL...", Colors.CYAN)
result = run_command(f"wsl cp '{wsl_path}/build_sdp_yrj_deb.sh' /tmp/build_sdp_yrj_deb.sh", check=True)
result = run_command("wsl chmod +x /tmp/build_sdp_yrj_deb.sh", check=True)
print_color("Building SDP April Fools DEB package in WSL...", Colors.CYAN)
result = run_command(f"wsl /tmp/build_sdp_yrj_deb.sh '{wsl_path}'", check=True)
if result.returncode != 0:
print()
print_color("Failed to build SDP April Fools DEB package", Colors.BOLD_RED)
print_color("Make sure dpkg-deb is available in WSL", Colors.YELLOW)
print_color("Run: wsl sudo apt update ^&^& wsl sudo apt install dpkg-dev", Colors.GREEN)
input("Press Enter to continue...")
return False
print()
print_color("SDP April Fools DEB build completed!", Colors.BOLD_GREEN)
print_color("Output file: dist\\scl-sdp-yrj-1.0.0.deb", Colors.GREEN)
print()
input("Press Enter to continue...")
return True
# 构建Linux DEB - Editor Only (via WSL)
def build_editor_deb():
print_color("\n========================================", Colors.BOLD_CYAN)
print_color("Building Linux DEB - Editor Only (via WSL)", Colors.BOLD_YELLOW)
print_color("========================================", Colors.BOLD_CYAN)
print()
print_color("Checking WSL...", Colors.CYAN)
result = run_command("wsl echo 'WSL OK'", check=False)
if result.returncode != 0:
print_color("WSL is not installed or not available", Colors.BOLD_RED)
print_color("Please install WSL first:", Colors.YELLOW)
print_color(" wsl --install", Colors.GREEN)
input("Press Enter to continue...")
return False
print_color("WSL found. Preparing build environment...", Colors.GREEN)
# 获取当前目录的WSL路径
result = run_command("wsl wslpath '%cd%'", check=True)
wsl_path = result.stdout.strip()
print_color(f"WSL path: {wsl_path}", Colors.BLUE)
print_color("Creating dist directory...", Colors.CYAN)
os.makedirs("dist", exist_ok=True)
print_color("Copying build script to WSL...", Colors.CYAN)
result = run_command(f"wsl cp '{wsl_path}/build_editor_deb.sh' /tmp/build_editor_deb.sh", check=True)
print_color("Building Editor DEB package in WSL...", Colors.CYAN)
result = run_command(f"wsl /tmp/build_editor_deb.sh '{wsl_path}'", check=True)
if result.returncode != 0:
print()
print_color("Failed to build Editor DEB package", Colors.BOLD_RED)
print_color("Make sure dpkg-deb is available in WSL", Colors.YELLOW)
print_color("Run: wsl sudo apt update ^&^& wsl sudo apt install dpkg-dev", Colors.GREEN)
input("Press Enter to continue...")
return False
print()
print_color("Editor DEB build completed!", Colors.BOLD_GREEN)
print_color("Output file: dist\\scl-editor-1.0.0.deb", Colors.GREEN)
print()
input("Press Enter to continue...")
return True
# 生成macOS Build Script (Mach-O)
def generate_macos_script():
print_color("\n========================================", Colors.BOLD_CYAN)
print_color("Generating macOS Build Script", Colors.BOLD_YELLOW)
print_color("========================================", Colors.BOLD_CYAN)
print()
print_color("Creating macOS build script...", Colors.CYAN)
script_content = '''#!/bin/bash
set -e
echo "Building SCL for macOS (Mach-O)..."
VERSION="1.0.0"
BUILD_DIR="build/macos"
DIST_DIR="dist/macos"
echo "Checking PyInstaller..."
if ! command -v pyinstaller &> /dev/null; then
echo "PyInstaller found"
else
echo "Installing PyInstaller..."
pip3 install pyinstaller
fi
echo "Creating build directories..."
mkdir -p "$BUILD_DIR"
mkdir -p "$DIST_DIR"
echo "Building scl..."
pyinstaller --onefile --name scl --distpath "$DIST_DIR" --workpath "$BUILD_DIR" --specpath "$BUILD_DIR" scl.py
echo "Building sdp..."
pyinstaller --onefile --name sdp --distpath "$DIST_DIR" --workpath "$BUILD_DIR" --specpath "$BUILD_DIR" sdp.py
echo "Building scl_editor_linux..."
pyinstaller --onefile --name scl_editor --distpath "$DIST_DIR" --workpath "$BUILD_DIR" --specpath "$BUILD_DIR" scl_editor_linux.py
echo "Creating DMG package..."
mkdir -p "$DIST_DIR/SCL.app/Contents/MacOS"
mkdir -p "$DIST_DIR/SCL.app/Contents/Resources"
echo "Copying executables..."
cp "$DIST_DIR/scl" "$DIST_DIR/SCL.app/Contents/MacOS/"
cp "$DIST_DIR/sdp" "$DIST_DIR/SCL.app/Contents/MacOS/"
cp "$DIST_DIR/scl_editor" "$DIST_DIR/SCL.app/Contents/MacOS/"
echo "Creating Info.plist..."
cat < "$DIST_DIR/SCL.app/Contents/Info.plist" << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>scl</string>
<key>CFBundleIdentifier</key>
<string>com.scl.lang</string>
<key>CFBundleName</key>
<string>SCL</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$VERSION</string>
<key>CFBundleVersion</key>
<string>$VERSION</string>
</dict>
</plist>
EOF
echo "Building DMG..."
if command -v hdiutil &> /dev/null; then
hdiutil create -volname "SCL" -srcfolder "$DIST_DIR/SCL.app" -ov -format UDZO "$DIST_DIR/SCL-$VERSION.dmg"
echo "DMG created: $DIST_DIR/SCL-$VERSION.dmg"
else
echo "hdiutil not found, skipping DMG creation"
echo "App bundle created: $DIST_DIR/SCL.app"
fi
echo "Build completed!"
echo "Output: $DIST_DIR/"
'''
with open("build_macos.sh", "w") as f:
f.write(script_content)
# 为脚本添加执行权限
os.chmod("build_macos.sh", 0o755)
print()
print_color("macOS build script created: build_macos.sh", Colors.BOLD_GREEN)
print()
print_color("Instructions:", Colors.BOLD_YELLOW)
print_color("1. Copy build_macos.sh to a macOS system", Colors.GREEN)
print_color("2. Make it executable: chmod +x build_macos.sh", Colors.GREEN)
print_color("3. Run it: ./build_macos.sh", Colors.GREEN)
print()
input("Press Enter to continue...")
return True
# 生成SDP macOS Build Script
def generate_sdp_macos_script():
print_color("\n========================================", Colors.BOLD_CYAN)
print_color("Generating SDP macOS Build Script", Colors.BOLD_YELLOW)
print_color("========================================", Colors.BOLD_CYAN)
print()
print_color("Creating SDP macOS build script...", Colors.CYAN)
script_content = '''#!/bin/bash
set -e
echo "Building SDP for macOS (Mach-O)..."
VERSION="1.0.0"
BUILD_DIR="build/sdp-macos"
DIST_DIR="dist/sdp-macos"
echo "Checking PyInstaller..."
if ! command -v pyinstaller &> /dev/null; then
echo "Installing PyInstaller..."
pip3 install pyinstaller
else
echo "PyInstaller found"
fi
echo "Creating build directories..."
mkdir -p "$BUILD_DIR"
mkdir -p "$DIST_DIR"
echo "Building SDP..."
pyinstaller --onefile --name sdp --distpath "$DIST_DIR" --workpath "$BUILD_DIR" --specpath "$BUILD_DIR" sdp.py
echo "Creating SDP App Bundle..."
APP_DIR="$DIST_DIR/SDP.app"
mkdir -p "$APP_DIR/Contents/MacOS"
mkdir -p "$APP_DIR/Contents/Resources"
echo "Copying executable..."
cp "$DIST_DIR/sdp" "$APP_DIR/Contents/MacOS/"
echo "Creating Info.plist..."
cat > "$APP_DIR/Contents/Info.plist" << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>sdp</string>
<key>CFBundleIdentifier</key>
<string>com.scl.sdp</string>
<key>CFBundleName</key>
<string>SDP</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$VERSION</string>
<key>CFBundleVersion</key>
<string>$VERSION</string>
</dict>
</plist>
EOF
echo "Building SDP DMG..."
if command -v hdiutil &> /dev/null; then
hdiutil create -volname "SDP" -srcfolder "$APP_DIR" -ov -format UDZO "$DIST_DIR/SDP-$VERSION.dmg"
echo "DMG created: $DIST_DIR/SDP-$VERSION.dmg"
else
echo "hdiutil not found, skipping DMG creation"
echo "App bundle created: $APP_DIR"
fi
echo "SDP build completed!"
echo "Output: $DIST_DIR/"
'''
with open("build_sdp_macos.sh", "w") as f:
f.write(script_content)
# 为脚本添加执行权限
os.chmod("build_sdp_macos.sh", 0o755)
print()
print_color("SDP macOS build script created: build_sdp_macos.sh", Colors.BOLD_GREEN)
print()
print_color("Instructions:", Colors.BOLD_YELLOW)
print_color("1. Copy build_sdp_macos.sh to a macOS system", Colors.GREEN)
print_color("2. Make it executable: chmod +x build_sdp_macos.sh", Colors.GREEN)
print_color("3. Run it: ./build_sdp_macos.sh", Colors.GREEN)
print()
input("Press Enter to continue...")
return True
# 构建所有 (EXE + DEB)
def build_all():
print_color("\n========================================", Colors.BOLD_CYAN)
print_color("Building All Packages (EXE + DEB)", Colors.BOLD_YELLOW)
print_color("========================================", Colors.BOLD_CYAN)
print()
print_color("Starting Windows EXE build...", Colors.CYAN)
print()
if not build_exe():
return False
print_color("Starting Linux DEB build...", Colors.CYAN)
print()
if not build_deb():
return False
print()
print_color("All builds completed!", Colors.BOLD_GREEN)
print()
input("Press Enter to continue...")
return True
# 显示菜单
def show_menu():
while True:
print_color("========================================", Colors.BOLD_CYAN)
print_color("SCL Build Tool", Colors.BOLD_YELLOW)
print_color("========================================", Colors.BOLD_CYAN)
print()
print_color("Please select build type:", Colors.BOLD_YELLOW)
print_color("[1] Build Windows EXE", Colors.GREEN)
print_color("[2] Build Linux DEB - SCL Full Package (via WSL)", Colors.GREEN)
print_color("[3] Build Linux DEB - SDP Only (via WSL)", Colors.GREEN)
print_color("[4] Build Linux DEB - Editor Only (via WSL)", Colors.GREEN)
print_color("[5] Generate macOS Build Script (Mach-O)", Colors.GREEN)
print_color("[6] Generate SDP macOS Build Script", Colors.GREEN)
print_color("[7] Build All (EXE + DEB)", Colors.GREEN)
print_color("[8] Build Windows EXE - April Fools Edition", Colors.GREEN)
print_color("[9] Build Linux DEB - SDP April Fools Edition (via WSL)", Colors.GREEN)
print_color("[10] Exit", Colors.GREEN)
print()
try:
choice = input(f"{Colors.BOLD_CYAN}Enter option (1-10):{Colors.RESET} ")
print()
if choice == "1":
build_exe()
elif choice == "2":
build_deb()
elif choice == "3":
build_sdp_deb()
elif choice == "4":
build_editor_deb()
elif choice == "5":
generate_macos_script()
elif choice == "6":
generate_sdp_macos_script()
elif choice == "7":
build_all()
elif choice == "8":
build_exe_april_fools()
elif choice == "9":
build_sdp_deb_april_fools()
elif choice == "10":
break
else:
print_color("Invalid option, please try again", Colors.BOLD_RED)
print()
except KeyboardInterrupt:
print()
break
except Exception as e:
print_color(f"An error occurred: {e}", Colors.BOLD_RED)
print()
print_color("\nThank you for using SCL Build Tool!", Colors.BOLD_YELLOW)
print()
input("Press Enter to exit...")
# 主函数
if __name__ == "__main__":
enable_windows_ansi_support()
show_menu()
+424
查看文件
@@ -0,0 +1,424 @@
#!/usr/bin/env python3
"""
SCL to Python Compiler
Converts SCL code to Python code with interpreter and plugins embedded
"""
import sys
import os
import re
import ast
class PluginAnalyzer:
"""Analyze plugin code to understand its syntax and implementation"""
def __init__(self):
self.plugins = {} # Cache for analyzed plugins
self.plugin_file_cache = {} # Cache for plugin file contents
def analyze_plugin(self, plugin_name):
"""Analyze a plugin's code"""
if plugin_name in self.plugins:
return self.plugins[plugin_name]
# Get the plugins directory path relative to the script
script_dir = os.path.dirname(os.path.abspath(__file__))
plugin_file = os.path.join(script_dir, 'plugins', f'{plugin_name}.py')
if not os.path.exists(plugin_file):
print(f"Error: Plugin file '{plugin_file}' not found")
return None
# Check if file content is cached
mtime = os.path.getmtime(plugin_file)
cache_key = (plugin_file, mtime)
if cache_key in self.plugin_file_cache:
code = self.plugin_file_cache[cache_key]
else:
try:
with open(plugin_file, 'r', encoding='utf-8') as f:
code = f.read()
# Cache the file content
self.plugin_file_cache[cache_key] = code
except Exception as e:
print(f"Error reading plugin file {plugin_file}: {e}")
return None
# Parse the code
try:
tree = ast.parse(code)
except SyntaxError as e:
print(f"Error parsing plugin {plugin_name}: Syntax error at line {e.lineno}, column {e.offset}: {e.msg}")
return None
# Extract information
try:
plugin_info = self._extract_plugin_info(tree, plugin_name)
plugin_info['code'] = code
self.plugins[plugin_name] = plugin_info
return plugin_info
except Exception as e:
print(f"Error extracting plugin information from {plugin_name}: {e}")
import traceback
traceback.print_exc()
return None
def _extract_plugin_info(self, tree, plugin_name):
"""Extract plugin information from AST"""
info = {
'name': plugin_name,
'imports': [],
'dependencies': [],
'commands': {},
'class_name': f'{plugin_name.capitalize()}Plugin'
}
# Get the plugins directory path relative to the script
script_dir = os.path.dirname(os.path.abspath(__file__))
plugins_dir = os.path.join(script_dir, 'plugins')
# Extract imports and dependencies
for node in ast.walk(tree):
if isinstance(node, ast.Import):
for alias in node.names:
info['imports'].append(alias.name)
# Check if this is a plugin dependency
if os.path.exists(plugins_dir) and alias.name in os.listdir(plugins_dir) and os.path.isfile(os.path.join(plugins_dir, f'{alias.name}.py')):
info['dependencies'].append(alias.name)
elif isinstance(node, ast.ImportFrom):
if node.module:
info['imports'].append(node.module)
# Check if this is a plugin dependency
if os.path.exists(plugins_dir) and node.module in os.listdir(plugins_dir) and os.path.isfile(os.path.join(plugins_dir, f'{node.module}.py')):
info['dependencies'].append(node.module)
# Extract command patterns from parse_statement
elif isinstance(node, ast.FunctionDef) and node.name == 'parse_statement':
self._extract_commands_from_parse(node, info)
return info
def _extract_commands_from_parse(self, node, info):
"""Extract command patterns from parse_statement function"""
for child in ast.walk(node):
if isinstance(child, ast.Compare) and isinstance(child.left, ast.Subscript):
# Check for tokens[pos][1] == 'command'
if self._is_tokens_access(child.left):
if isinstance(child.comparators[0], ast.Constant):
command = child.comparators[0].value
if isinstance(command, str):
info['commands'][command] = {'type': 'direct'}
elif isinstance(child, ast.Compare) and isinstance(child.left, ast.Name):
# Check for command_suffix == 'c'
if child.left.id == 'command_suffix':
if isinstance(child.comparators[0], ast.Constant):
suffix = child.comparators[0].value
if isinstance(suffix, str):
info['commands'][f'sui-{suffix}'] = {'type': 'sui'}
def _is_tokens_access(self, node):
"""Check if node is tokens[pos][1]"""
if (isinstance(node, ast.Subscript) and
isinstance(node.value, ast.Name) and
node.value.id == 'tokens'):
if isinstance(node.slice, ast.Constant) or isinstance(node.slice, ast.Name):
return True
return False
class SCLCompiler:
def __init__(self):
self.variables = {}
self.imports = set()
self.indent_level = 0
self.plugin_analyzer = PluginAnalyzer()
self.loaded_plugins = set()
def _detect_plugin_conflicts(self, resolved_plugins):
"""Detect command conflicts between plugins"""
command_map = {}
conflicts = []
for plugin_name in resolved_plugins:
plugin_info = self.plugin_analyzer.analyze_plugin(plugin_name)
if not plugin_info:
continue
for command in plugin_info.get('commands', {}):
if command in command_map:
conflicts.append((command, command_map[command], plugin_name))
else:
command_map[command] = plugin_name
return conflicts
def compile(self, scl_code, filename="input.scl", minify=False):
"""Compile SCL code to Python code with embedded interpreter and plugins"""
lines = scl_code.split('\n')
# First pass: collect plugins
plugins_to_load = []
for line in lines:
if line.startswith('simp{') and line.endswith('}'):
import_content = line[5:-1].strip()
if not import_content.startswith('scl :'):
plugins_to_load.append(import_content)
# Resolve plugin dependencies
resolved_plugins = self._resolve_plugin_dependencies(plugins_to_load)
# Detect plugin conflicts
conflicts = self._detect_plugin_conflicts(resolved_plugins)
if conflicts:
print("Warning: Command conflicts detected between plugins:")
for command, plugin1, plugin2 in conflicts:
print(f" Command '{command}' is defined in both {plugin1} and {plugin2}")
print(" The last loaded plugin will take precedence.")
# Load SCL interpreter code
scl_interpreter_code = self._load_scl_interpreter()
# Load plugin codes
plugin_codes = {}
for plugin_name in resolved_plugins:
plugin_info = self.plugin_analyzer.analyze_plugin(plugin_name)
if plugin_info:
plugin_codes[plugin_name] = plugin_info['code']
# Generate embedded Python code
python_code = self._generate_embedded_code(scl_code, scl_interpreter_code, plugin_codes, filename, minify)
return python_code
def _resolve_plugin_dependencies(self, plugins_to_load):
"""Resolve plugin dependencies and return an ordered list"""
resolved = set()
unresolved = set(plugins_to_load)
order = []
print(f"Resolving dependencies for plugins: {plugins_to_load}")
while unresolved:
# Find plugins with all dependencies resolved
progress = False
for plugin_name in list(unresolved):
plugin_info = self.plugin_analyzer.analyze_plugin(plugin_name)
if not plugin_info:
print(f"Warning: Skipping plugin {plugin_name} due to analysis errors")
unresolved.remove(plugin_name)
continue
# Check if all dependencies are resolved
dependencies = plugin_info.get('dependencies', [])
print(f"Plugin {plugin_name} has dependencies: {dependencies}")
if all(dep in resolved for dep in dependencies):
# Add to resolved and order
resolved.add(plugin_name)
order.append(plugin_name)
unresolved.remove(plugin_name)
progress = True
print(f"Resolved plugin: {plugin_name}")
# Add dependencies to unresolved if not already processed
for dep in dependencies:
if dep not in resolved and dep not in unresolved:
print(f"Adding dependency {dep} for plugin {plugin_name}")
unresolved.add(dep)
if not progress:
# No progress made, break to avoid infinite loop
print(f"Warning: Unable to resolve all dependencies. Remaining: {unresolved}")
break
print(f"Resolved plugin order: {order}")
return order
def _minify_code(self, code):
"""Minify Python code by removing comments and whitespace"""
lines = code.split('\n')
minified_lines = []
in_multiline_comment = False
for line in lines:
# Skip empty lines
if not line.strip():
continue
# Handle multiline comments
if '"""' in line or "''" in line:
in_multiline_comment = not in_multiline_comment
continue
if in_multiline_comment:
continue
# Remove single-line comments
if '#' in line:
line = line.split('#')[0].rstrip()
if not line:
continue
# Remove leading and trailing whitespace
line = line.strip()
if line:
minified_lines.append(line)
return '\n'.join(minified_lines)
def _load_scl_interpreter(self):
"""Load SCL interpreter code"""
try:
# Get the script directory
script_dir = os.path.dirname(os.path.abspath(__file__))
scl_path = os.path.join(script_dir, 'scl.py')
with open(scl_path, 'r', encoding='utf-8') as f:
code = f.read()
# Remove the main function execution at the end
lines = code.split('\n')
filtered_lines = []
in_main_block = False
for line in lines:
if line.strip() == 'if __name__ == "__main__":':
in_main_block = True
continue
if in_main_block:
if line.strip() and not line.startswith(' '):
in_main_block = False
else:
continue
filtered_lines.append(line)
return '\n'.join(filtered_lines)
except Exception as e:
print(f"Error loading SCL interpreter: {e}")
return ""
def _generate_header(self, filename):
"""Generate the header for the embedded code"""
return [
'#!/usr/bin/env python3',
f'# Generated from {filename} by SCL Compiler',
'# Embedded SCL interpreter and plugins',
''
]
def _generate_interpreter_code(self, scl_interpreter_code, minify):
"""Generate the SCL interpreter code"""
code = ['\n# ==== SCL INTERPRETER ====\n']
if minify:
code.append(self._minify_code(scl_interpreter_code))
else:
code.append(scl_interpreter_code)
code.append('')
return code
def _generate_plugin_codes(self, plugin_codes, minify):
"""Generate the plugin codes"""
code = []
for plugin_name, plugin_code in plugin_codes.items():
code.append(f'\n# ==== PLUGIN: {plugin_name} ====\n')
if minify:
code.append(self._minify_code(plugin_code))
else:
code.append(plugin_code)
code.append('')
return code
def _generate_main_function(self, plugin_codes, scl_code):
"""Generate the main function code"""
code = ['\n# ==== MAIN EXECUTION ====\n\ndef main():\n """Run the embedded SCL code"""\n print("Running embedded SCL code...")\n print("=" * 50)\n \n # Create SCL interpreter\n interpreter = SCLInterpreter()\n \n # Load plugins\n']
# Add plugin loading code
for plugin_name in plugin_codes:
code.append(f" interpreter.load_plugin('{plugin_name}')\n")
# Add SCL code execution
code.append('\n # SCL code to execute\n scl_code = """')
# 安全地嵌入 SCL 代码,处理三引号
for line in scl_code.split('\n'):
code.append(line.replace('"""', '\\"""'))
code.append('\n')
code.append('"""\n')
# Add execution code
code.append('\n # Execute SCL code\n try:\n success = interpreter.execute(scl_code, "embedded")\n if not success:\n print("Error: Failed to execute SCL code")\n except Exception as e:\n print(f"Error: {e}")\n \n print("=" * 50)\n print("Execution completed.")\n\n\nif __name__ == "__main__":\n main()\n')
return code
def _generate_embedded_code(self, scl_code, scl_interpreter_code, plugin_codes, filename, minify=False):
"""Generate embedded Python code"""
# Use a single string buffer for more efficient concatenation
code_buffer = []
# Add header
code_buffer.extend(self._generate_header(filename))
# Add SCL interpreter code
code_buffer.extend(self._generate_interpreter_code(scl_interpreter_code, minify))
# Add plugin codes
code_buffer.extend(self._generate_plugin_codes(plugin_codes, minify))
# Add main function
code_buffer.extend(self._generate_main_function(plugin_codes, scl_code))
return ''.join(code_buffer)
def main():
"""Main function"""
import argparse
# Parse command line arguments
parser = argparse.ArgumentParser(description='SCL to Python Compiler')
parser.add_argument('input_file', help='Input SCL file')
parser.add_argument('output_file', nargs='?', help='Output Python file (optional, default: stdout)')
parser.add_argument('-m', '--minify', action='store_true', help='Minify the generated code')
args = parser.parse_args()
input_file = args.input_file
output_file = args.output_file
minify = args.minify
# Check if input file exists
if not os.path.exists(input_file):
print(f"Error: Input file '{input_file}' not found")
sys.exit(1)
# Read SCL code
try:
with open(input_file, 'r', encoding='utf-8') as f:
scl_code = f.read()
except Exception as e:
print(f"Error reading file: {e}")
sys.exit(1)
# Compile to Python
compiler = SCLCompiler()
python_code = compiler.compile(scl_code, input_file, minify)
# Output
if output_file:
try:
with open(output_file, 'w', encoding='utf-8') as f:
f.write(python_code)
print(f"Successfully compiled {input_file} to {output_file}")
if minify:
print("The file has been minified to reduce size.")
else:
print("The file includes embedded SCL interpreter and plugins.")
except Exception as e:
print(f"Error writing file: {e}")
sys.exit(1)
else:
print(python_code)
if __name__ == '__main__':
main()
+1366
查看文件
文件差异内容过多而无法显示 加载差异
+1059
查看文件
文件差异内容过多而无法显示 加载差异