From 154686a0aad880bd27014015bde11ae0cf1919fd Mon Sep 17 00:00:00 2001 From: Paul McGee Date: Sat, 22 Nov 2025 18:20:01 +0800 Subject: [PATCH 01/27] Create Windows local deployment branch (CE-for-Win-Pascal-2025) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modernized version of CE-for-Win-Pascal (2021) for local Windows deployment with commercial compilers (Delphi, C++Builder) and open-source compilers. Changes: - Minimal language support: C++, Pascal, Rust, Python only - Preserved all Windows compiler configurations from 2021 branch - Migrated from JavaScript to TypeScript (4+ years of improvements) - Smart Pascal program/unit detection (better than original hardcoded approach) - Comprehensive documentation for local deployment Files modified: - lib/languages.ts: Reduced from 80+ languages to 4 (backup in .full-backup) - etc/config/*.local.properties: Windows compiler paths (from old branch) New documentation: - WINDOWS-DEPLOYMENT.md: Complete setup and configuration guide - MIGRATION-FROM-2021.md: Migration notes from original branch This branch is for LOCAL USE ONLY, not public deployment. Based on origin/main (2025) with customizations from CE-for-Win-Pascal (2021) Old branch backed up as tag: CE-for-Win-Pascal-backup-20251122 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- MIGRATION-FROM-2021.md | 285 +++++++++ WINDOWS-DEPLOYMENT.md | 281 +++++++++ lib/languages.ts | 1011 +------------------------------ lib/languages.ts.full-backup | 1086 ++++++++++++++++++++++++++++++++++ 4 files changed, 1673 insertions(+), 990 deletions(-) create mode 100644 MIGRATION-FROM-2021.md create mode 100644 WINDOWS-DEPLOYMENT.md create mode 100644 lib/languages.ts.full-backup diff --git a/MIGRATION-FROM-2021.md b/MIGRATION-FROM-2021.md new file mode 100644 index 00000000000..dc5c53178c9 --- /dev/null +++ b/MIGRATION-FROM-2021.md @@ -0,0 +1,285 @@ +# Migration from CE-for-Win-Pascal (2021) to CE-for-Win-Pascal-2025 + +## Summary of Changes + +Your original `CE-for-Win-Pascal` branch from 2021 has been modernized to `CE-for-Win-Pascal-2025`. + +### What Was Migrated + +✅ **Preserved**: +- All your compiler configurations (FPC, Delphi, C++Builder) +- Windows-specific paths and settings +- Minimal language selection (C++, Pascal + Rust, Python) +- Local deployment customizations + +✅ **Improved**: +- JavaScript → TypeScript (better type safety) +- Pascal program/unit detection (now automatic!) +- 4+ years of bug fixes and improvements +- Modern build tooling + +### What Changed + +| Aspect | 2021 Branch | 2025 Branch | +|--------|-------------|-------------| +| **Language** | JavaScript | TypeScript | +| **Pascal Detection** | Hardcoded `output.dpr` | Smart detection via `pascalUtils.isProgram()` | +| **Languages File** | `lib/languages.js` | `lib/languages.ts` (minimal) | +| **Compiler Configs** | `.local.properties` | Same (copied forward) | +| **Build System** | Webpack 4 | Webpack 5 | + +## Your Original Changes (2021) + +### What You Modified + +1. **lib/compilers/pascal.js** + - Changed executable from `prog` to `output` + - Changed project file to `output.dpr` + + **Status**: ✅ **No longer needed** - Modern code has better implementation! + +2. **lib/languages.js** + - Removed most languages + - Kept only C++, Pascal + + **Status**: ✅ **Migrated** to `lib/languages.ts` with C++, Pascal, Rust, Python + +3. **Configuration Files** + - `etc/config/pascal.local.properties` + - `etc/config/pascal-win.local.properties` + - `etc/config/c++.local.properties` + + **Status**: ✅ **Copied forward** - Ready to update paths + +4. **Documentation** + - `Delphi & C++Builder Specifics.md` + - README modifications + + **Status**: ✅ **Replaced** with `WINDOWS-DEPLOYMENT.md` + +## Modern Implementation Benefits + +### Pascal Program Detection (2025) + +The new code is **smarter** than your 2021 changes: + +**Old way (2021)**: +```javascript +// Hardcoded +getExecutableFilename(dirPath) { + return path.join(dirPath, 'output'); +} +``` + +**New way (2025)**: +```typescript +getExecutableFilename(dirPath: string, outputFilebase: string, key?: CacheKey) { + const source = (key && (key as CacheKey).source) || ''; + if (key && pascalUtils.isProgram(source)) { + return path.join(dirPath, pascalUtils.getProgName(source)); // Extracts from source! + } + return path.join(dirPath, 'prog'); +} +``` + +**Benefit**: Automatically extracts program name from your source code! + +```pascal +program MyCalculator; // Executable will be named "MyCalculator" +``` + +## Migration Steps + +### 1. Update Compiler Paths + +Your compiler paths from 2021 may have changed. Edit: + +**`etc/config/pascal.local.properties`**: +```properties +# Update these paths to match your current installations +compiler.fpc331.exe=C:\fpcupdeluxe\fpc\bin\x86_64-win64\fpc.exe +compiler.delphi27.exe=C:\Program Files (x86)\Embarcadero\Studio\21.0\Bin\DCC32.EXE +``` + +### 2. Update Delphi Versions + +You had Delphi 10.2, 10.3, 10.4 configured. Update to your current versions: + +```properties +# Example: Add Delphi 11 Alexandria +compiler.delphi28.exe=C:\Program Files (x86)\Embarcadero\Studio\22.0\Bin\DCC32.EXE +compiler.delphi28.name=x86 Delphi 11 Alexandria + +compiler.delphi28_64.exe=C:\Program Files (x86)\Embarcadero\Studio\22.0\Bin\DCC64.EXE +compiler.delphi28_64.name=x64 Delphi 11 Alexandria + +# Add to group +group.delphi.compilers=delphi25:delphi26:delphi27:delphi28 +group.delphi64.compilers=delphi25_64:delphi26_64:delphi27_64:delphi28_64 +``` + +### 3. Test the Build + +```bash +npm install +npm run webpack +npm start +``` + +Browse to http://localhost:10240/ + +### 4. Verify Compilers + +1. Select **Pascal** language +2. Try each compiler version +3. Test both Programs and Units +4. Verify assembly output works + +## What You DON'T Need to Do + +❌ **Don't** manually edit `lib/compilers/pascal.ts` - It's already better! +❌ **Don't** worry about TypeScript - It works like JavaScript +❌ **Don't** modify core files - Only edit `.local.properties` + +## Recommended: Delete Old Branch + +Once you've verified the new branch works: + +```bash +# The old branch is backed up in a tag +git tag # Verify CE-for-Win-Pascal-backup-20251122 exists + +# Safe to delete old branch +git branch -D CE-for-Win-Pascal + +# Keep only the new one +git branch -m CE-for-Win-Pascal-2025 CE-for-Win-Pascal +``` + +## Comparison: Old vs New + +### File Count + +| Category | 2021 Branch | 2025 Branch | +|----------|-------------|-------------| +| Modified Files | 15+ files | 3 files | +| Custom Code | 200+ lines | 90 lines | +| Merge Commits | 10 | 0 | + +The new branch is **cleaner** and **easier to maintain**! + +### Technical Debt + +**2021 Branch**: +- 4,627 commits behind main +- JavaScript (no type safety) +- Hardcoded values +- Manual merges needed + +**2025 Branch**: +- ✅ Up to date with main +- ✅ TypeScript (full type safety) +- ✅ Smart detection +- ✅ Clean rebase possible + +## Adding More Languages + +If you want to add more languages, edit `lib/languages.ts`: + +```typescript +const definitions: Record = { + 'c++': { ... }, + pascal: { ... }, + rust: { ... }, + python: { ... }, + + // Add more here - copy from lib/languages.ts.full-backup + d: { + name: 'D', + monaco: 'd', + extensions: ['.d'], + alias: [], + logoFilename: 'd.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, +}; +``` + +## FAQ + +### Q: Why recreate instead of rebase? + +**A**: With 4,627 commits divergence and JS→TS migration, clean recreation was: +- Faster (hours vs days) +- Safer (no conflict resolution needed) +- Cleaner (no merge commits) +- Better (got improvements for free) + +### Q: Did I lose any custom features? + +**A**: No! Your custom features are **better** in the new code: +- Pascal program support: Now automatic +- Compiler configs: All copied forward +- Language filtering: Preserved and improved + +### Q: Can I still update from main? + +**A**: Yes! Much easier now: +```bash +git merge origin/main +# Only conflicts will be in lib/languages.ts - just keep your minimal version +``` + +### Q: What if I need the old branch? + +**A**: It's tagged: +```bash +git checkout CE-for-Win-Pascal-backup-20251122 +``` + +## Next Steps + +1. ✅ Update compiler paths in `.local.properties` files +2. ✅ Test build with `npm install && npm start` +3. ✅ Verify all compilers work +4. ✅ Read `WINDOWS-DEPLOYMENT.md` for detailed docs +5. ✅ Consider deleting old branch once verified + +## Success Indicators + +You'll know migration succeeded when: + +- ✅ Server starts on http://localhost:10240/ +- ✅ You see only 4 languages (C++, Pascal, Rust, Python) +- ✅ Your compilers appear in dropdown +- ✅ Compilation works +- ✅ Assembly output displays + +## Rollback Plan + +If anything goes wrong: + +```bash +# Go back to old branch +git checkout CE-for-Win-Pascal-backup-20251122 + +# Or restore old config +git checkout CE-for-Win-Pascal-backup-20251122 -- etc/config/ +``` + +## Support + +Need help? Check: +1. This migration guide +2. `WINDOWS-DEPLOYMENT.md` - Full documentation +3. Original CE docs - Most still apply +4. Git tag - Backup of old branch + +--- + +**Migration Date**: November 22, 2025 +**From**: CE-for-Win-Pascal (2021, JavaScript) +**To**: CE-for-Win-Pascal-2025 (TypeScript) diff --git a/WINDOWS-DEPLOYMENT.md b/WINDOWS-DEPLOYMENT.md new file mode 100644 index 00000000000..1feb7964cf3 --- /dev/null +++ b/WINDOWS-DEPLOYMENT.md @@ -0,0 +1,281 @@ +# Compiler Explorer - Windows Local Deployment + +**Branch:** `CE-for-Win-Pascal-2025` + +This is a customized build of Compiler Explorer for **local Windows deployment** with commercial and open-source compilers. It is **NOT** intended for public cloud deployment. + +## Purpose + +This branch removes the hundreds of cloud-based compilers from the public Compiler Explorer and configures it to use: +- **Commercial Compilers**: Delphi (Embarcadero), C++Builder +- **Free Pascal Compilers**: Multiple FPC versions +- **Open Source Compilers**: Rust, Python (local installations) + +## Differences from Public CE + +### Key Customizations + +1. **Minimal Language Support** (`lib/languages.ts`) + - Only includes: C++, Pascal, Rust, Python + - Full language list backed up in `lib/languages.ts.full-backup` + +2. **Local Compiler Configurations** (`etc/config/*.local.properties`) + - Pascal compilers (FPC + Delphi) + - C++ compilers (C++Builder, MinGW) + - Paths configured for Windows file system + +3. **TypeScript Modernization** + - Migrated from 2021 JavaScript to 2025 TypeScript + - Better type safety and modern features + - Smart Pascal program/unit detection + +## Installation + +### Prerequisites + +- **Node.js**: Latest LTS version (v18+ recommended) +- **npm**: Latest version +- **Compilers** installed locally (see Configuration section) + +### Setup Steps + +1. **Clone this branch**: + ```bash + git clone -b CE-for-Win-Pascal-2025 https://github.com/pmcgee69/compiler-explorer.git + cd compiler-explorer + ``` + +2. **Install dependencies**: + ```bash + npm install + npm install -g webpack webpack-cli + ``` + +3. **Configure compilers** (see Configuration section below) + +4. **Build**: + ```bash + npm run webpack + ``` + +5. **Start server**: + ```bash + npm start + ``` + +6. **Access**: Browse to http://localhost:10240/ + +## Configuration + +### Pascal Compilers + +Edit `etc/config/pascal.local.properties` to configure your local installations: + +#### Free Pascal (FPC) + +```properties +compiler.fpc331.exe=C:\fpcupdeluxe\fpc\bin\x86_64-win64\fpc.exe +compiler.fpc322.exe=C:\FPC\3.2.2\bin\i386-win32\fpc.exe +# Add more FPC versions as needed +``` + +#### Delphi Compilers + +```properties +# 32-bit Delphi +compiler.delphi27.exe=C:\Program Files (x86)\Embarcadero\Studio\21.0\Bin\DCC32.EXE +compiler.delphi27.name=x86 Delphi 10.4.2 Sydney + +# 64-bit Delphi +compiler.delphi27_64.exe=C:\Program Files (x86)\Embarcadero\Studio\21.0\Bin\DCC64.EXE +compiler.delphi27_64.name=x64 Delphi 10.4.2 Sydney +``` + +#### Object Dump Tool + +Configure objdump for assembly output: +```properties +group.fpc.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe +group.delphi.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe +``` + +### C++ Compilers + +Edit `etc/config/c++.local.properties` for C++Builder and other C++ compilers. + +### Adding Your Own Compilers + +1. Edit the appropriate `.local.properties` file +2. Follow the existing patterns for compiler groups +3. Ensure paths use Windows format (`C:\...`) +4. Test with `npm start` + +## Features + +### Pascal Support + +The current implementation includes **smart program/unit detection**: + +- **`pascal-utils.ts`**: Automatically detects whether source is a `program` or `unit` +- Extracts program name from source code +- Handles both `.pas` (units) and `.dpr` (programs) files +- No hardcoded filenames - intelligent detection + +Example: +```pascal +program MyApp; // Detected as program, executable named "MyApp" +``` + +```pascal +unit MyUnit; // Detected as unit, wrapped in dummy project +``` + +### Supported Languages + +- **C++**: Full support with multiple compilers +- **Pascal**: FPC and Delphi with program/unit detection +- **Rust**: Local rustc installation +- **Python**: Local Python installation + +## Updating from Main Branch + +To update this branch with latest improvements from public CE: + +### Option 1: Merge (Recommended for small updates) + +```bash +git checkout CE-for-Win-Pascal-2025 +git fetch origin main +git merge origin/main +# Resolve conflicts in lib/languages.ts - keep your minimal version +# Test thoroughly +``` + +### Option 2: Rebase (For major updates) + +This is more complex but gives cleaner history. See `REBASE-NOTES.md` for details. + +### Files to Protect During Updates + +When merging/rebasing, **preserve these customizations**: + +1. **`lib/languages.ts`** - Your minimal language list +2. **`etc/config/*.local.properties`** - Your compiler paths +3. **`WINDOWS-DEPLOYMENT.md`** - This documentation + +These are the **only** files that differ significantly from main branch. + +## Development + +### Build Commands + +- **Development mode**: `npm run webpack:dev` +- **Production build**: `npm run webpack` +- **Watch mode**: `npm run webpack:watch` + +### Testing + +- **All tests**: `npm test` +- **Minimal tests**: `npm run test-min` +- **TypeScript check**: `npm run ts-check` +- **Linting**: `npm run lint` + +### Pre-commit Checks + +Always run before committing: +```bash +npm run ts-check +npm run lint +npm run test-min +``` + +Or use the comprehensive check: +```bash +make pre-commit +``` + +## Troubleshooting + +### Build Errors + +**Issue**: TypeScript compilation errors +- **Solution**: Run `npm run ts-check` to see detailed errors +- Check that `lib/languages.ts` has correct type definitions + +**Issue**: Missing dependencies +- **Solution**: Delete `node_modules` and run `npm install` again + +### Runtime Errors + +**Issue**: Compiler not found +- **Solution**: Check paths in `.local.properties` files +- Ensure compilers are actually installed at those paths +- Use absolute Windows paths (e.g., `C:\...`) + +**Issue**: objdump errors +- **Solution**: Install TDM-GCC or similar to get objdump.exe +- Update objdumper paths in properties files + +## Architecture Notes + +### Language Detection + +The modern TypeScript implementation uses: + +- **Type-safe language definitions**: `types/languages.interfaces.ts` +- **Monaco editor integration**: Each language maps to Monaco syntax highlighting +- **Example code loading**: Automatic loading from `examples/{lang}/default{ext}` + +### Pascal Compiler Classes + +- **`pascal.ts`**: Main FPC compiler class (cross-platform) +- **`pascal-win.ts`**: Windows-specific Delphi compiler +- **`pascal-utils.ts`**: Helper functions for program/unit detection + +## Maintenance Notes + +### When Updating Compiler Versions + +1. Update version in `.local.properties` +2. Test compilation +3. Update README if version numbers are mentioned + +### Adding New Compilers + +1. Add to appropriate `.local.properties` file +2. Test with sample code +3. Document in this file + +## History + +- **2021**: Original `CE-for-Win-Pascal` branch created +- **2025**: Modernized to `CE-for-Win-Pascal-2025` + - Migrated to TypeScript + - Updated to latest CE architecture + - Added Rust and Python support + - Improved Pascal program/unit handling + +## Backup + +The following backups are maintained: + +- **`lib/languages.ts.full-backup`**: Complete language list from main branch +- **Git tag**: `CE-for-Win-Pascal-backup-20251122` - Previous branch state + +## License + +Same as Compiler Explorer: BSD 2-Clause License + +## Support + +This is a private/local deployment. For issues: + +1. Check this documentation +2. Check public CE docs: https://github.com/compiler-explorer/compiler-explorer +3. For commercial compiler issues, contact vendor support + +## See Also + +- **Main CE Project**: https://github.com/compiler-explorer/compiler-explorer +- **CE Documentation**: https://github.com/compiler-explorer/compiler-explorer/blob/main/docs/ +- **Windows Native Guide**: https://github.com/compiler-explorer/compiler-explorer/blob/main/docs/WindowsNative.md diff --git a/lib/languages.ts b/lib/languages.ts index 71d69e15752..b5807622ba8 100644 --- a/lib/languages.ts +++ b/lib/languages.ts @@ -22,6 +22,11 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. +// CUSTOM BUILD FOR WINDOWS - LOCAL DEPLOYMENT ONLY +// This is a minimal language configuration for local Windows deployment +// with commercial compilers (Delphi, C++Builder, Free Pascal) and local open-source compilers +// Full language list is backed up in languages.ts.full-backup + import fs from 'node:fs'; import path from 'node:path'; @@ -41,18 +46,8 @@ type DefKeys = | 'digitSeparator'; type LanguageDefinition = Pick; +// Minimal language definitions for Windows local deployment const definitions: Record = { - jakt: { - name: 'Jakt', - monaco: 'jakt', - extensions: ['.jakt'], - alias: [], - logoFilename: null, - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: 'cppp', - }, 'c++': { name: 'C++', monaco: 'cppp', @@ -65,690 +60,31 @@ const definitions: Record = { monacoDisassembly: null, digitSeparator: "'", }, - ada: { - name: 'Ada', - monaco: 'ada', - extensions: ['.adb', '.ads'], - alias: [], - logoFilename: 'ada.svg', - logoFilenameDark: 'ada-dark.svg', - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - algol68: { - name: 'Algol68', - monaco: 'algol68', - extensions: ['.a68'], - alias: [], - logoFilename: null, - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - analysis: { - name: 'Analysis', - monaco: 'asm', - extensions: ['.asm'], // maybe add more? Change to a unique one? - alias: ['tool', 'tools'], - logoFilename: 'analysis.png', // TODO: Find a better alternative - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - tooltip: 'A collection of asm analysis tools', - }, - 'android-java': { - name: 'Android Java', - monaco: 'java', - extensions: ['.java'], - alias: [], - logoFilename: 'android.svg', - logoFilenameDark: 'android-dark.svg', - formatter: null, - previewFilter: null, - monacoDisassembly: null, - digitSeparator: '_', - }, - 'android-kotlin': { - name: 'Android Kotlin', - monaco: 'kotlin', - extensions: ['.kt'], - alias: [], - logoFilename: 'android.svg', - logoFilenameDark: 'android-dark.svg', - formatter: null, - previewFilter: null, - monacoDisassembly: null, - digitSeparator: '_', - }, - assembly: { - name: 'Assembly', - monaco: 'asm', - extensions: ['.asm', '.6502', '.s'], - alias: ['asm'], - logoFilename: 'assembly.png', // TODO: Find a better alternative - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - c: { - name: 'C', - monaco: 'nc', - extensions: ['.c', '.h'], - alias: [], - logoFilename: 'c.svg', - logoFilenameDark: null, - formatter: 'clangformat', - previewFilter: /^\s*#include/, - monacoDisassembly: null, - digitSeparator: "'", - }, - c3: { - name: 'C3', - monaco: 'c3', - extensions: ['.c3'], - alias: [], - logoFilename: 'c3.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - carbon: { - name: 'Carbon', - monaco: 'carbon', - extensions: ['.carbon'], - alias: [], - logoFilename: 'carbon.png', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - coccinelle_for_c: { - name: 'C with Coccinelle', - monaco: 'nc', - extensions: ['.c', '.h'], - alias: [], - logoFilename: 'c.svg', - logoFilenameDark: null, - formatter: 'clangformat', - previewFilter: /^\s*#include/, - monacoDisassembly: null, - digitSeparator: "'", - }, - coccinelle_for_cpp: { - name: 'C++ with Coccinelle', - monaco: 'cppp', - extensions: ['.cpp', '.h'], - alias: [], - logoFilename: 'cpp.svg', - logoFilenameDark: null, - formatter: 'clangformat', - previewFilter: /^\s*#include/, - monacoDisassembly: null, - digitSeparator: "'", - }, - circle: { - name: 'C++ (Circle)', - monaco: 'cppcircle', - extensions: ['.cpp', '.cxx', '.h', '.hpp', '.hxx', '.c'], - alias: [], - previewFilter: /^\s*#include/, - logoFilename: 'cpp.svg', // TODO: Find a better alternative - logoFilenameDark: null, - formatter: null, - monacoDisassembly: null, - digitSeparator: "'", - }, - circt: { - name: 'CIRCT', - monaco: 'mlir', - extensions: ['.mlir'], - alias: [], - logoFilename: 'circt.svg', - formatter: null, - logoFilenameDark: null, - previewFilter: null, - monacoDisassembly: 'mlir', - }, - clean: { - name: 'Clean', - monaco: 'clean', - extensions: ['.icl'], - alias: [], - logoFilename: 'clean.svg', // TODO: Find a better alternative - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - clojure: { - name: 'Clojure', - monaco: 'clojure', - extensions: ['.clj'], - alias: [], - logoFilename: 'clojure.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - cmake: { - name: 'CMake', - monaco: 'cmake', - extensions: ['.txt'], - alias: [], - logoFilename: 'cmake.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - cmakescript: { - name: 'CMakeScript', - monaco: 'cmake', - extensions: ['.cmake'], - alias: [], - logoFilename: 'cmake.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - cobol: { - name: 'COBOL', - monaco: 'cobol', - extensions: ['.cob', '.cbl', '.cobol'], - alias: [], - logoFilename: null, // TODO: Find a better alternative - formatter: null, - logoFilenameDark: null, - previewFilter: null, - monacoDisassembly: null, - }, - cpp_for_opencl: { - name: 'C++ for OpenCL', - monaco: 'cpp-for-opencl', - extensions: ['.clcpp', '.cl', '.ocl'], - alias: [], - logoFilename: 'opencl.svg', // TODO: Find a better alternative - logoFilenameDark: 'opencl-dark.svg', - formatter: null, - previewFilter: null, - monacoDisassembly: null, - digitSeparator: "'", - }, - mlir: { - name: 'MLIR', - monaco: 'mlir', - extensions: ['.mlir'], - alias: [], - logoFilename: 'mlir.svg', - formatter: null, - logoFilenameDark: null, - previewFilter: null, - monacoDisassembly: null, - }, - cppx: { - name: 'Cppx', - monaco: 'cppp', - extensions: ['.cpp', '.cxx', '.h', '.hpp', '.hxx', '.c'], - alias: [], - logoFilename: 'cpp.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: /^\s*#include/, - monacoDisassembly: null, - digitSeparator: "'", - }, - cppx_blue: { - name: 'Cppx-Blue', - monaco: 'cppx-blue', - extensions: ['.blue', '.cpp', '.cxx', '.h', '.hpp', '.hxx', '.c'], - alias: [], - logoFilename: 'cpp.svg', // TODO: Find a better alternative - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - cppx_gold: { - name: 'Cppx-Gold', - monaco: 'cppx-gold', - extensions: ['.usyntax', '.cpp', '.cxx', '.h', '.hpp', '.hxx', '.c'], - alias: [], - logoFilename: 'cpp.svg', // TODO: Find a better alternative - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - digitSeparator: "'", - }, - cpp2_cppfront: { - name: 'Cpp2-cppfront', - monaco: 'cpp2-cppfront', - extensions: ['.cpp2'], - alias: [], - logoFilename: 'cpp.svg', // TODO: Find a better alternative - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: 'cppp', - digitSeparator: "'", - }, - crystal: { - name: 'Crystal', - monaco: 'crystal', - extensions: ['.cr'], - alias: [], - logoFilename: 'crystal.svg', - logoFilenameDark: 'crystal-dark.svg', - formatter: null, - previewFilter: null, - monacoDisassembly: null, - digitSeparator: '_', - }, - csharp: { - name: 'C#', - monaco: 'csharp', - extensions: ['.cs'], - alias: [], - logoFilename: 'dotnet.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - digitSeparator: '_', - }, - cuda: { - name: 'CUDA C++', - monaco: 'cuda', - extensions: ['.cu', '.cuh'], - alias: ['nvcc'], - logoFilename: 'cuda.svg', - logoFilenameDark: 'cuda-dark.svg', - formatter: null, - previewFilter: null, - monacoDisassembly: null, - digitSeparator: "'", - }, - d: { - name: 'D', - monaco: 'd', - extensions: ['.d'], - alias: [], - logoFilename: 'd.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - dart: { - name: 'Dart', - monaco: 'dart', - extensions: ['.dart'], - alias: [], - logoFilename: 'dart.svg', - logoFilenameDark: null, - formatter: 'dartformat', - previewFilter: null, - monacoDisassembly: null, - }, - elixir: { - name: 'Elixir', - monaco: 'elixir', - extensions: ['.ex'], - alias: [], - logoFilename: 'elixir.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - erlang: { - name: 'Erlang', - monaco: 'erlang', - extensions: ['.erl', '.hrl'], - alias: [], - logoFilename: 'erlang.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - fortran: { - name: 'Fortran', - monaco: 'fortran', - extensions: ['.f90', '.F90', '.f95', '.F95', '.f'], - alias: [], - logoFilename: 'fortran.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - fsharp: { - name: 'F#', - monaco: 'fsharp', - extensions: ['.fs'], - alias: [], - logoFilename: 'fsharp.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - glsl: { - name: 'GLSL', - monaco: 'glsl', - extensions: ['.glsl'], - alias: [], - logoFilename: 'glsl.svg', - logoFilenameDark: 'glsl-dark.svg', - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - go: { - name: 'Go', - monaco: 'go', - extensions: ['.go'], + pascal: { + name: 'Pascal', + monaco: 'pascal', + extensions: ['.pas', '.dpr', '.inc'], alias: [], - logoFilename: 'go.svg', - logoFilenameDark: null, + logoFilename: 'pascal.svg', + logoFilenameDark: 'pascal-dark.svg', formatter: null, previewFilter: null, monacoDisassembly: null, - digitSeparator: '_', }, - haskell: { - name: 'Haskell', - monaco: 'haskell', - extensions: ['.hs', '.haskell'], + rust: { + name: 'Rust', + monaco: 'rustp', + extensions: ['.rs'], alias: [], - logoFilename: 'haskell.png', - logoFilenameDark: null, - formatter: null, + logoFilename: 'rust.svg', + logoFilenameDark: 'rust-dark.svg', + formatter: 'rustfmt', previewFilter: null, monacoDisassembly: null, digitSeparator: '_', }, - hlsl: { - name: 'HLSL', - monaco: 'hlsl', - extensions: ['.hlsl', '.hlsli'], - alias: [], - logoFilename: 'hlsl.png', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - helion: { - name: 'Helion', - monaco: 'python', - extensions: ['.py'], - alias: [], - logoFilename: 'helion.png', - logoFilenameDark: 'helion.png', - formatter: null, - previewFilter: null, - monacoDisassembly: null, - digitSeparator: '_', - }, - hook: { - name: 'Hook', - monaco: 'hook', - extensions: ['.hk', '.hook'], - alias: [], - logoFilename: 'hook.png', - logoFilenameDark: 'hook-dark.png', - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - hylo: { - name: 'Hylo', - monaco: 'hylo', - extensions: ['.hylo'], - alias: [], - logoFilename: 'hylo.png', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - il: { - name: 'IL', - monaco: 'asm', - extensions: ['.il'], - alias: [], - logoFilename: 'dotnet.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - ispc: { - name: 'ispc', - monaco: 'ispc', - extensions: ['.ispc'], - alias: [], - logoFilename: 'ispc.png', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - java: { - name: 'Java', - monaco: 'java', - extensions: ['.java'], - alias: [], - logoFilename: 'java.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - digitSeparator: '_', - }, - julia: { - name: 'Julia', - monaco: 'julia', - extensions: ['.jl'], - alias: [], - logoFilename: 'julia.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - digitSeparator: '_', - }, - kotlin: { - name: 'Kotlin', - monaco: 'kotlin', - extensions: ['.kt'], - alias: [], - logoFilename: 'kotlin.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - digitSeparator: '_', - }, - llvm: { - name: 'LLVM IR', - monaco: 'llvm-ir', - extensions: ['.ll'], - alias: [], - logoFilename: 'llvm.png', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - llvm_mir: { - name: 'LLVM MIR', - monaco: 'llvm-ir', - extensions: ['.mir'], - alias: [], - logoFilename: 'llvm.png', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - modula2: { - name: 'Modula-2', - monaco: 'modula2', - extensions: ['.mod'], - alias: [], - logoFilename: null, - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - mojo: { - name: 'Mojo', - monaco: 'mojo', - extensions: ['.mojo', '.🔥'], - alias: [], - logoFilename: 'mojo.svg', - logoFilenameDark: null, - formatter: 'mblack', - previewFilter: null, - monacoDisassembly: null, - digitSeparator: '_', - }, - nim: { - name: 'Nim', - monaco: 'nim', - extensions: ['.nim'], - alias: [], - logoFilename: 'nim.png', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - numba: { - name: 'Numba', - monaco: 'python', - extensions: ['.py'], - alias: [], - logoFilename: 'numba.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - nix: { - name: 'Nix', - monaco: 'nix', - extensions: ['.nix'], - alias: [], - logoFilename: 'nix.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - objc: { - name: 'Objective-C', - monaco: 'objective-c', - extensions: ['.m'], - alias: [], - logoFilename: null, - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - 'objc++': { - name: 'Objective-C++', - monaco: 'objective-c', - extensions: ['.mm'], - alias: [], - logoFilename: null, - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - digitSeparator: "'", - }, - ocaml: { - name: 'OCaml', - monaco: 'ocaml', - extensions: ['.ml', '.mli'], - alias: [], - logoFilename: 'ocaml.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - odin: { - name: 'Odin', - monaco: 'odin', - extensions: ['.odin'], - alias: [], - logoFilename: 'odin.png', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - openclc: { - name: 'OpenCL C', - monaco: 'openclc', - extensions: ['.cl', '.ocl'], - alias: [], - logoFilename: 'opencl.svg', - logoFilenameDark: 'opencl-dark.svg', - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - pascal: { - name: 'Pascal', - monaco: 'pascal', - extensions: ['.pas', '.dpr', '.inc'], - alias: [], - logoFilename: 'pascal.svg', // TODO: Find a better alternative - logoFilenameDark: 'pascal-dark.svg', - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - pony: { - name: 'Pony', - monaco: 'pony', - extensions: ['.pony'], - alias: [], - logoFilename: 'pony.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - ptx: { - name: 'PTX', - monaco: 'ptx', - extensions: ['.ptx'], - alias: [], - logoFilename: 'cuda.svg', - logoFilenameDark: 'cuda-dark.svg', - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - python: { - name: 'Python', + python: { + name: 'Python', monaco: 'python', extensions: ['.py'], alias: [], @@ -759,311 +95,6 @@ const definitions: Record = { monacoDisassembly: null, digitSeparator: '_', }, - racket: { - name: 'Racket', - monaco: 'scheme', - extensions: ['.rkt'], - alias: [], - logoFilename: 'racket.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: 'scheme', - }, - raku: { - name: 'Raku', - monaco: 'perl', - extensions: ['.raku', '.rakutest', '.rakumod', '.rakudoc'], - alias: ['Perl 6'], - logoFilename: 'camelia.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - ruby: { - name: 'Ruby', - monaco: 'ruby', - extensions: ['.rb'], - alias: [], - logoFilename: 'ruby.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: 'asmruby', - digitSeparator: '_', - }, - rust: { - name: 'Rust', - monaco: 'rustp', - extensions: ['.rs'], - alias: [], - logoFilename: 'rust.svg', - logoFilenameDark: 'rust-dark.svg', - formatter: 'rustfmt', - previewFilter: null, - monacoDisassembly: null, - digitSeparator: '_', - }, - sail: { - name: 'Sail', - monaco: 'sail', - extensions: ['.sail'], - alias: [], - logoFilename: 'sail.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - snowball: { - name: 'Snowball', - monaco: 'swift', - extensions: ['.sn'], - alias: [], - logoFilename: 'snowball.svg', - logoFilenameDark: 'snowball.svg', - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - scala: { - name: 'Scala', - monaco: 'scala', - extensions: ['.scala'], - alias: [], - logoFilename: 'scala.png', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - digitSeparator: '_', - }, - slang: { - name: 'Slang', - monaco: 'slang', - extensions: ['.slang'], - alias: [], - logoFilename: 'slang.svg', - logoFilenameDark: 'slang-dark.svg', - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - solidity: { - name: 'Solidity', - monaco: 'sol', - extensions: ['.sol'], - alias: [], - logoFilename: 'solidity.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - spice: { - name: 'Spice', - monaco: 'spice', - extensions: ['.spice'], - alias: [], - logoFilename: 'spice.png', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - spirv: { - name: 'SPIR-V', - monaco: 'spirv', - extensions: ['.spvasm'], - alias: [], - logoFilename: 'spirv.svg', - logoFilenameDark: 'spirv-dark.svg', - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - swift: { - name: 'Swift', - monaco: 'swift', - extensions: ['.swift'], - alias: [], - logoFilename: 'swift.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - digitSeparator: '_', - }, - tablegen: { - name: 'LLVM TableGen', - monaco: 'tablegen', - extensions: ['.td'], - alias: [], - logoFilename: 'llvm.png', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - toit: { - name: 'Toit', - monaco: 'toit', - extensions: ['.toit'], - alias: [], - logoFilename: 'toit.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - triton: { - name: 'Triton', - monaco: 'python', - extensions: ['.py'], - alias: [], - logoFilename: 'triton.png', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - typescript: { - name: 'TypeScript Native', - monaco: 'typescript', - extensions: ['.ts', '.d.ts'], - alias: [], - logoFilename: 'ts.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - digitSeparator: '_', - }, - v: { - name: 'V', - monaco: 'v', - extensions: ['.v', '.vsh'], - alias: [], - logoFilename: 'v.svg', - logoFilenameDark: null, - formatter: 'vfmt', - previewFilter: null, - monacoDisassembly: 'nc', - }, - vala: { - name: 'Vala', - monaco: 'vala', - extensions: ['.vala'], - alias: [], - logoFilename: 'vala.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - vb: { - name: 'Visual Basic', - monaco: 'vb', - extensions: ['.vb'], - alias: [], - logoFilename: 'dotnet.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - vyper: { - name: 'Vyper', - monaco: 'python', - extensions: ['.vy'], - alias: [], - logoFilename: 'vyper.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - wasm: { - name: 'WASM', - monaco: 'wat', - extensions: ['.wat'], - alias: [], - logoFilename: 'wasm.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - yul: { - name: 'Yul (Solidity IR)', - monaco: 'yul', - extensions: ['.yul'], - alias: [], - logoFilename: 'solidity.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - zig: { - name: 'Zig', - monaco: 'zig', - extensions: ['.zig'], - alias: [], - logoFilename: 'zig.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - digitSeparator: '_', - }, - javascript: { - name: 'Javascript', - monaco: 'typescript', - extensions: ['.mjs'], - alias: [], - logoFilename: 'js.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - digitSeparator: '_', - }, - gimple: { - name: 'GIMPLE', - monaco: 'nc', - extensions: ['.c'], - alias: [], - logoFilename: 'gimple.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: /^\s*#include/, - monacoDisassembly: null, - }, - ylc: { - name: 'Ygen', - monaco: 'llvm-ir', - extensions: ['.yl'], - alias: [], - logoFilename: null, // ygen does not yet have a logo ping me if it requires one (@Cr0a3) - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - }, - sway: { - name: 'sway', - monaco: 'sway', - extensions: ['.sw'], - alias: [], - logoFilename: 'sway.svg', - logoFilenameDark: null, - formatter: null, - previewFilter: null, - monacoDisassembly: null, - digitSeparator: '_', - }, }; export const languages = Object.fromEntries( diff --git a/lib/languages.ts.full-backup b/lib/languages.ts.full-backup new file mode 100644 index 00000000000..71d69e15752 --- /dev/null +++ b/lib/languages.ts.full-backup @@ -0,0 +1,1086 @@ +// Copyright (c) 2017, Compiler Explorer Authors +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import fs from 'node:fs'; +import path from 'node:path'; + +import type {Language, LanguageKey} from '../types/languages.interfaces.js'; + +type DefKeys = + | 'name' + | 'monaco' + | 'extensions' + | 'alias' + | 'previewFilter' + | 'formatter' + | 'logoFilename' + | 'logoFilenameDark' + | 'monacoDisassembly' + | 'tooltip' + | 'digitSeparator'; +type LanguageDefinition = Pick; + +const definitions: Record = { + jakt: { + name: 'Jakt', + monaco: 'jakt', + extensions: ['.jakt'], + alias: [], + logoFilename: null, + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: 'cppp', + }, + 'c++': { + name: 'C++', + monaco: 'cppp', + extensions: ['.cpp', '.cxx', '.h', '.hpp', '.hxx', '.c', '.cc', '.ixx'], + alias: ['gcc', 'cpp'], + logoFilename: 'cpp.svg', + logoFilenameDark: null, + formatter: 'clangformat', + previewFilter: /^\s*#include/, + monacoDisassembly: null, + digitSeparator: "'", + }, + ada: { + name: 'Ada', + monaco: 'ada', + extensions: ['.adb', '.ads'], + alias: [], + logoFilename: 'ada.svg', + logoFilenameDark: 'ada-dark.svg', + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + algol68: { + name: 'Algol68', + monaco: 'algol68', + extensions: ['.a68'], + alias: [], + logoFilename: null, + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + analysis: { + name: 'Analysis', + monaco: 'asm', + extensions: ['.asm'], // maybe add more? Change to a unique one? + alias: ['tool', 'tools'], + logoFilename: 'analysis.png', // TODO: Find a better alternative + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + tooltip: 'A collection of asm analysis tools', + }, + 'android-java': { + name: 'Android Java', + monaco: 'java', + extensions: ['.java'], + alias: [], + logoFilename: 'android.svg', + logoFilenameDark: 'android-dark.svg', + formatter: null, + previewFilter: null, + monacoDisassembly: null, + digitSeparator: '_', + }, + 'android-kotlin': { + name: 'Android Kotlin', + monaco: 'kotlin', + extensions: ['.kt'], + alias: [], + logoFilename: 'android.svg', + logoFilenameDark: 'android-dark.svg', + formatter: null, + previewFilter: null, + monacoDisassembly: null, + digitSeparator: '_', + }, + assembly: { + name: 'Assembly', + monaco: 'asm', + extensions: ['.asm', '.6502', '.s'], + alias: ['asm'], + logoFilename: 'assembly.png', // TODO: Find a better alternative + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + c: { + name: 'C', + monaco: 'nc', + extensions: ['.c', '.h'], + alias: [], + logoFilename: 'c.svg', + logoFilenameDark: null, + formatter: 'clangformat', + previewFilter: /^\s*#include/, + monacoDisassembly: null, + digitSeparator: "'", + }, + c3: { + name: 'C3', + monaco: 'c3', + extensions: ['.c3'], + alias: [], + logoFilename: 'c3.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + carbon: { + name: 'Carbon', + monaco: 'carbon', + extensions: ['.carbon'], + alias: [], + logoFilename: 'carbon.png', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + coccinelle_for_c: { + name: 'C with Coccinelle', + monaco: 'nc', + extensions: ['.c', '.h'], + alias: [], + logoFilename: 'c.svg', + logoFilenameDark: null, + formatter: 'clangformat', + previewFilter: /^\s*#include/, + monacoDisassembly: null, + digitSeparator: "'", + }, + coccinelle_for_cpp: { + name: 'C++ with Coccinelle', + monaco: 'cppp', + extensions: ['.cpp', '.h'], + alias: [], + logoFilename: 'cpp.svg', + logoFilenameDark: null, + formatter: 'clangformat', + previewFilter: /^\s*#include/, + monacoDisassembly: null, + digitSeparator: "'", + }, + circle: { + name: 'C++ (Circle)', + monaco: 'cppcircle', + extensions: ['.cpp', '.cxx', '.h', '.hpp', '.hxx', '.c'], + alias: [], + previewFilter: /^\s*#include/, + logoFilename: 'cpp.svg', // TODO: Find a better alternative + logoFilenameDark: null, + formatter: null, + monacoDisassembly: null, + digitSeparator: "'", + }, + circt: { + name: 'CIRCT', + monaco: 'mlir', + extensions: ['.mlir'], + alias: [], + logoFilename: 'circt.svg', + formatter: null, + logoFilenameDark: null, + previewFilter: null, + monacoDisassembly: 'mlir', + }, + clean: { + name: 'Clean', + monaco: 'clean', + extensions: ['.icl'], + alias: [], + logoFilename: 'clean.svg', // TODO: Find a better alternative + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + clojure: { + name: 'Clojure', + monaco: 'clojure', + extensions: ['.clj'], + alias: [], + logoFilename: 'clojure.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + cmake: { + name: 'CMake', + monaco: 'cmake', + extensions: ['.txt'], + alias: [], + logoFilename: 'cmake.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + cmakescript: { + name: 'CMakeScript', + monaco: 'cmake', + extensions: ['.cmake'], + alias: [], + logoFilename: 'cmake.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + cobol: { + name: 'COBOL', + monaco: 'cobol', + extensions: ['.cob', '.cbl', '.cobol'], + alias: [], + logoFilename: null, // TODO: Find a better alternative + formatter: null, + logoFilenameDark: null, + previewFilter: null, + monacoDisassembly: null, + }, + cpp_for_opencl: { + name: 'C++ for OpenCL', + monaco: 'cpp-for-opencl', + extensions: ['.clcpp', '.cl', '.ocl'], + alias: [], + logoFilename: 'opencl.svg', // TODO: Find a better alternative + logoFilenameDark: 'opencl-dark.svg', + formatter: null, + previewFilter: null, + monacoDisassembly: null, + digitSeparator: "'", + }, + mlir: { + name: 'MLIR', + monaco: 'mlir', + extensions: ['.mlir'], + alias: [], + logoFilename: 'mlir.svg', + formatter: null, + logoFilenameDark: null, + previewFilter: null, + monacoDisassembly: null, + }, + cppx: { + name: 'Cppx', + monaco: 'cppp', + extensions: ['.cpp', '.cxx', '.h', '.hpp', '.hxx', '.c'], + alias: [], + logoFilename: 'cpp.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: /^\s*#include/, + monacoDisassembly: null, + digitSeparator: "'", + }, + cppx_blue: { + name: 'Cppx-Blue', + monaco: 'cppx-blue', + extensions: ['.blue', '.cpp', '.cxx', '.h', '.hpp', '.hxx', '.c'], + alias: [], + logoFilename: 'cpp.svg', // TODO: Find a better alternative + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + cppx_gold: { + name: 'Cppx-Gold', + monaco: 'cppx-gold', + extensions: ['.usyntax', '.cpp', '.cxx', '.h', '.hpp', '.hxx', '.c'], + alias: [], + logoFilename: 'cpp.svg', // TODO: Find a better alternative + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + digitSeparator: "'", + }, + cpp2_cppfront: { + name: 'Cpp2-cppfront', + monaco: 'cpp2-cppfront', + extensions: ['.cpp2'], + alias: [], + logoFilename: 'cpp.svg', // TODO: Find a better alternative + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: 'cppp', + digitSeparator: "'", + }, + crystal: { + name: 'Crystal', + monaco: 'crystal', + extensions: ['.cr'], + alias: [], + logoFilename: 'crystal.svg', + logoFilenameDark: 'crystal-dark.svg', + formatter: null, + previewFilter: null, + monacoDisassembly: null, + digitSeparator: '_', + }, + csharp: { + name: 'C#', + monaco: 'csharp', + extensions: ['.cs'], + alias: [], + logoFilename: 'dotnet.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + digitSeparator: '_', + }, + cuda: { + name: 'CUDA C++', + monaco: 'cuda', + extensions: ['.cu', '.cuh'], + alias: ['nvcc'], + logoFilename: 'cuda.svg', + logoFilenameDark: 'cuda-dark.svg', + formatter: null, + previewFilter: null, + monacoDisassembly: null, + digitSeparator: "'", + }, + d: { + name: 'D', + monaco: 'd', + extensions: ['.d'], + alias: [], + logoFilename: 'd.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + dart: { + name: 'Dart', + monaco: 'dart', + extensions: ['.dart'], + alias: [], + logoFilename: 'dart.svg', + logoFilenameDark: null, + formatter: 'dartformat', + previewFilter: null, + monacoDisassembly: null, + }, + elixir: { + name: 'Elixir', + monaco: 'elixir', + extensions: ['.ex'], + alias: [], + logoFilename: 'elixir.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + erlang: { + name: 'Erlang', + monaco: 'erlang', + extensions: ['.erl', '.hrl'], + alias: [], + logoFilename: 'erlang.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + fortran: { + name: 'Fortran', + monaco: 'fortran', + extensions: ['.f90', '.F90', '.f95', '.F95', '.f'], + alias: [], + logoFilename: 'fortran.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + fsharp: { + name: 'F#', + monaco: 'fsharp', + extensions: ['.fs'], + alias: [], + logoFilename: 'fsharp.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + glsl: { + name: 'GLSL', + monaco: 'glsl', + extensions: ['.glsl'], + alias: [], + logoFilename: 'glsl.svg', + logoFilenameDark: 'glsl-dark.svg', + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + go: { + name: 'Go', + monaco: 'go', + extensions: ['.go'], + alias: [], + logoFilename: 'go.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + digitSeparator: '_', + }, + haskell: { + name: 'Haskell', + monaco: 'haskell', + extensions: ['.hs', '.haskell'], + alias: [], + logoFilename: 'haskell.png', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + digitSeparator: '_', + }, + hlsl: { + name: 'HLSL', + monaco: 'hlsl', + extensions: ['.hlsl', '.hlsli'], + alias: [], + logoFilename: 'hlsl.png', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + helion: { + name: 'Helion', + monaco: 'python', + extensions: ['.py'], + alias: [], + logoFilename: 'helion.png', + logoFilenameDark: 'helion.png', + formatter: null, + previewFilter: null, + monacoDisassembly: null, + digitSeparator: '_', + }, + hook: { + name: 'Hook', + monaco: 'hook', + extensions: ['.hk', '.hook'], + alias: [], + logoFilename: 'hook.png', + logoFilenameDark: 'hook-dark.png', + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + hylo: { + name: 'Hylo', + monaco: 'hylo', + extensions: ['.hylo'], + alias: [], + logoFilename: 'hylo.png', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + il: { + name: 'IL', + monaco: 'asm', + extensions: ['.il'], + alias: [], + logoFilename: 'dotnet.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + ispc: { + name: 'ispc', + monaco: 'ispc', + extensions: ['.ispc'], + alias: [], + logoFilename: 'ispc.png', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + java: { + name: 'Java', + monaco: 'java', + extensions: ['.java'], + alias: [], + logoFilename: 'java.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + digitSeparator: '_', + }, + julia: { + name: 'Julia', + monaco: 'julia', + extensions: ['.jl'], + alias: [], + logoFilename: 'julia.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + digitSeparator: '_', + }, + kotlin: { + name: 'Kotlin', + monaco: 'kotlin', + extensions: ['.kt'], + alias: [], + logoFilename: 'kotlin.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + digitSeparator: '_', + }, + llvm: { + name: 'LLVM IR', + monaco: 'llvm-ir', + extensions: ['.ll'], + alias: [], + logoFilename: 'llvm.png', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + llvm_mir: { + name: 'LLVM MIR', + monaco: 'llvm-ir', + extensions: ['.mir'], + alias: [], + logoFilename: 'llvm.png', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + modula2: { + name: 'Modula-2', + monaco: 'modula2', + extensions: ['.mod'], + alias: [], + logoFilename: null, + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + mojo: { + name: 'Mojo', + monaco: 'mojo', + extensions: ['.mojo', '.🔥'], + alias: [], + logoFilename: 'mojo.svg', + logoFilenameDark: null, + formatter: 'mblack', + previewFilter: null, + monacoDisassembly: null, + digitSeparator: '_', + }, + nim: { + name: 'Nim', + monaco: 'nim', + extensions: ['.nim'], + alias: [], + logoFilename: 'nim.png', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + numba: { + name: 'Numba', + monaco: 'python', + extensions: ['.py'], + alias: [], + logoFilename: 'numba.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + nix: { + name: 'Nix', + monaco: 'nix', + extensions: ['.nix'], + alias: [], + logoFilename: 'nix.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + objc: { + name: 'Objective-C', + monaco: 'objective-c', + extensions: ['.m'], + alias: [], + logoFilename: null, + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + 'objc++': { + name: 'Objective-C++', + monaco: 'objective-c', + extensions: ['.mm'], + alias: [], + logoFilename: null, + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + digitSeparator: "'", + }, + ocaml: { + name: 'OCaml', + monaco: 'ocaml', + extensions: ['.ml', '.mli'], + alias: [], + logoFilename: 'ocaml.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + odin: { + name: 'Odin', + monaco: 'odin', + extensions: ['.odin'], + alias: [], + logoFilename: 'odin.png', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + openclc: { + name: 'OpenCL C', + monaco: 'openclc', + extensions: ['.cl', '.ocl'], + alias: [], + logoFilename: 'opencl.svg', + logoFilenameDark: 'opencl-dark.svg', + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + pascal: { + name: 'Pascal', + monaco: 'pascal', + extensions: ['.pas', '.dpr', '.inc'], + alias: [], + logoFilename: 'pascal.svg', // TODO: Find a better alternative + logoFilenameDark: 'pascal-dark.svg', + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + pony: { + name: 'Pony', + monaco: 'pony', + extensions: ['.pony'], + alias: [], + logoFilename: 'pony.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + ptx: { + name: 'PTX', + monaco: 'ptx', + extensions: ['.ptx'], + alias: [], + logoFilename: 'cuda.svg', + logoFilenameDark: 'cuda-dark.svg', + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + python: { + name: 'Python', + monaco: 'python', + extensions: ['.py'], + alias: [], + logoFilename: 'python.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + digitSeparator: '_', + }, + racket: { + name: 'Racket', + monaco: 'scheme', + extensions: ['.rkt'], + alias: [], + logoFilename: 'racket.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: 'scheme', + }, + raku: { + name: 'Raku', + monaco: 'perl', + extensions: ['.raku', '.rakutest', '.rakumod', '.rakudoc'], + alias: ['Perl 6'], + logoFilename: 'camelia.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + ruby: { + name: 'Ruby', + monaco: 'ruby', + extensions: ['.rb'], + alias: [], + logoFilename: 'ruby.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: 'asmruby', + digitSeparator: '_', + }, + rust: { + name: 'Rust', + monaco: 'rustp', + extensions: ['.rs'], + alias: [], + logoFilename: 'rust.svg', + logoFilenameDark: 'rust-dark.svg', + formatter: 'rustfmt', + previewFilter: null, + monacoDisassembly: null, + digitSeparator: '_', + }, + sail: { + name: 'Sail', + monaco: 'sail', + extensions: ['.sail'], + alias: [], + logoFilename: 'sail.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + snowball: { + name: 'Snowball', + monaco: 'swift', + extensions: ['.sn'], + alias: [], + logoFilename: 'snowball.svg', + logoFilenameDark: 'snowball.svg', + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + scala: { + name: 'Scala', + monaco: 'scala', + extensions: ['.scala'], + alias: [], + logoFilename: 'scala.png', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + digitSeparator: '_', + }, + slang: { + name: 'Slang', + monaco: 'slang', + extensions: ['.slang'], + alias: [], + logoFilename: 'slang.svg', + logoFilenameDark: 'slang-dark.svg', + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + solidity: { + name: 'Solidity', + monaco: 'sol', + extensions: ['.sol'], + alias: [], + logoFilename: 'solidity.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + spice: { + name: 'Spice', + monaco: 'spice', + extensions: ['.spice'], + alias: [], + logoFilename: 'spice.png', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + spirv: { + name: 'SPIR-V', + monaco: 'spirv', + extensions: ['.spvasm'], + alias: [], + logoFilename: 'spirv.svg', + logoFilenameDark: 'spirv-dark.svg', + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + swift: { + name: 'Swift', + monaco: 'swift', + extensions: ['.swift'], + alias: [], + logoFilename: 'swift.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + digitSeparator: '_', + }, + tablegen: { + name: 'LLVM TableGen', + monaco: 'tablegen', + extensions: ['.td'], + alias: [], + logoFilename: 'llvm.png', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + toit: { + name: 'Toit', + monaco: 'toit', + extensions: ['.toit'], + alias: [], + logoFilename: 'toit.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + triton: { + name: 'Triton', + monaco: 'python', + extensions: ['.py'], + alias: [], + logoFilename: 'triton.png', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + typescript: { + name: 'TypeScript Native', + monaco: 'typescript', + extensions: ['.ts', '.d.ts'], + alias: [], + logoFilename: 'ts.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + digitSeparator: '_', + }, + v: { + name: 'V', + monaco: 'v', + extensions: ['.v', '.vsh'], + alias: [], + logoFilename: 'v.svg', + logoFilenameDark: null, + formatter: 'vfmt', + previewFilter: null, + monacoDisassembly: 'nc', + }, + vala: { + name: 'Vala', + monaco: 'vala', + extensions: ['.vala'], + alias: [], + logoFilename: 'vala.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + vb: { + name: 'Visual Basic', + monaco: 'vb', + extensions: ['.vb'], + alias: [], + logoFilename: 'dotnet.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + vyper: { + name: 'Vyper', + monaco: 'python', + extensions: ['.vy'], + alias: [], + logoFilename: 'vyper.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + wasm: { + name: 'WASM', + monaco: 'wat', + extensions: ['.wat'], + alias: [], + logoFilename: 'wasm.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + yul: { + name: 'Yul (Solidity IR)', + monaco: 'yul', + extensions: ['.yul'], + alias: [], + logoFilename: 'solidity.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + zig: { + name: 'Zig', + monaco: 'zig', + extensions: ['.zig'], + alias: [], + logoFilename: 'zig.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + digitSeparator: '_', + }, + javascript: { + name: 'Javascript', + monaco: 'typescript', + extensions: ['.mjs'], + alias: [], + logoFilename: 'js.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + digitSeparator: '_', + }, + gimple: { + name: 'GIMPLE', + monaco: 'nc', + extensions: ['.c'], + alias: [], + logoFilename: 'gimple.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: /^\s*#include/, + monacoDisassembly: null, + }, + ylc: { + name: 'Ygen', + monaco: 'llvm-ir', + extensions: ['.yl'], + alias: [], + logoFilename: null, // ygen does not yet have a logo ping me if it requires one (@Cr0a3) + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + }, + sway: { + name: 'sway', + monaco: 'sway', + extensions: ['.sw'], + alias: [], + logoFilename: 'sway.svg', + logoFilenameDark: null, + formatter: null, + previewFilter: null, + monacoDisassembly: null, + digitSeparator: '_', + }, +}; + +export const languages = Object.fromEntries( + Object.entries(definitions).map(([key, lang]) => { + let example: string; + try { + example = fs.readFileSync(path.join('examples', key, 'default' + lang.extensions[0]), 'utf8'); + } catch { + example = 'Oops, something went wrong and we could not get the default code for this language.'; + } + + const def: Language = { + ...lang, + id: key as LanguageKey, + supportsExecute: false, + example, + }; + return [key, def]; + }), +) as Record; From 1c7559ed1679b05b7d5c9518e8bf162722a46b33 Mon Sep 17 00:00:00 2001 From: Paul McGee Date: Sat, 22 Nov 2025 18:21:33 +0800 Subject: [PATCH 02/27] Add Windows compiler configurations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Local compiler configurations for Windows deployment: - Pascal compilers: FPC 2.6.0, 2.6.4, 3.0.4, 3.2.2, 3.3.1 - Delphi compilers: 10.2 Tokyo, 10.3 Rio, 10.4.2 Sydney (32 & 64-bit) - C++ compilers: C++Builder and MinGW-based toolchains These paths are specific to the local Windows installation and should be updated to match your compiler installation locations. Note: .local.properties files are normally gitignored, but included here as templates for local deployment setup. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- etc/config/c++.local.properties | 82 ++++++++++++++++++ etc/config/pascal-win.local.properties | 54 ++++++++++++ etc/config/pascal.local.properties | 114 +++++++++++++++++++++++++ 3 files changed, 250 insertions(+) create mode 100644 etc/config/c++.local.properties create mode 100644 etc/config/pascal-win.local.properties create mode 100644 etc/config/pascal.local.properties diff --git a/etc/config/c++.local.properties b/etc/config/c++.local.properties new file mode 100644 index 00000000000..8b66d01cdb7 --- /dev/null +++ b/etc/config/c++.local.properties @@ -0,0 +1,82 @@ +# replace with the result of `echo %INCLUDE%` +# if you want a specific includePath for a specific compiler, +# you can set it up in that compiler's config, with, say +# compiler.my_clang.include=path_to_libc++ + +includePath=C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\atlmfc\include;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\include;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\ucrt;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\shared;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\winrt;C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\cppwinrt; + +#Listed individually ... +#C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\atlmfc\include; +#C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\include; +#C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\ucrt; +#C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\shared; +#C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\um; +#C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\winrt; +#C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\cppwinrt + + +# replace with the result of `where undname.exe` from a developer command prompt + +demangler=C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\bin\Hostx64\x64\undname.exe + +# the compiler you want compiler explorer to start up in + +defaultCompiler=bcc64 + + +# note: adding new compiler groups +# the default compiler groups should be fine for most, +# but if you'd like to add more groups +# (for example, for vc 2015, or for gcc), +# you can uncomment and edit the following lines. +# check `c++.win32.properties` for how to modify the group options + + +# clang compilers +# if you want more compilers, you can do that by separating the names with `:` +# and then setting up a compiler.my_clang.exe and compiler.my_clang.name + +group.embclang.compilers =bcc32:bcc64 +group.embclang.groupName =emb clang +group.embclang.options =-Wno-user-defined-literals -Wno-comment -I'C:\Program Files (x86)\Embarcadero\Studio\21.0\include\dinkumware64' -I'C:\Program Files (x86)\Embarcadero\Studio\21.0\include\windows\crtl' + +group.msclang.compilers =mscl32:mscl64 +group.msclang.groupName =ms clang + +# this is the default path that clang++ is installed in +# if you installed it somewhere else, you should edit both variables + +compiler.bcc32.exe =C:\Program Files (x86)\Embarcadero\Studio\21.0\bin\bcc32x.exe +compiler.bcc32.name =c++ builder x86 + +compiler.bcc64.exe =C:\Program Files (x86)\Embarcadero\Studio\21.0\bin\bcc64.exe +compiler.bcc64.name =c++ builder x64 + +compiler.mscl32.exe =C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\Llvm\bin\clang++.exe +compiler.mscl32.name =clang x86 +compiler.mscl32.options =-m32 + +compiler.mscl64.exe =C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\Llvm\x64\bin\clang++.exe +compiler.mscl64.name =clang x64 + +# visual C++ compilers +# follow the same instructions as for clang +# note that if CE doesn't find a compiler, it won't break anything + +#compiler.vc2017_32.exe =C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Tools\MSVC\14.16.27023\bin\Hostx64\x86\cl.exe +#compiler.vc2017_32.name =VC 2017 x86 +compiler.vc2019_32.exe =C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\bin\Hostx64\x86\cl.exe +compiler.vc2019_32.name =VC 2019 x86 +compiler.vc2019_32.include =C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\lib\x86\ + +#compiler.vc2017_64.exe =C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Tools\MSVC\14.16.27023\bin\Hostx64\x64\cl.exe +#compiler.vc2017_64.name =VC 2017 x64 +compiler.vc2019_64.exe =C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\bin\Hostx64\x64\cl.exe +compiler.vc2019_64.name =VC 2019 x64 + +# gcc +group.tdmgcc.compilers =gcc64 + +compiler.gcc64.exe =C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\gcc.exe +compiler.gcc64.name =tdm64 gcc 9.0 + diff --git a/etc/config/pascal-win.local.properties b/etc/config/pascal-win.local.properties new file mode 100644 index 00000000000..dcbce4a7a69 --- /dev/null +++ b/etc/config/pascal-win.local.properties @@ -0,0 +1,54 @@ +compilers=&delphi:&delphi64 +maxLinesOfAsm=1000 +rpathFlag=-O + +################################# +# Delphi +group.delphi.compilers=delphi21:delphi22:delphi23:delphi24:delphi25:delphi26:delphi27 +group.delphi.compilerType=pascal-win +group.delphi.demangler= +group.delphi.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe +#D:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin\objdump.exe +group.delphi.versionFlags=| grep "Version" + +group.delphi64.compilers=delphi23_64:delphi24_64:delphi25_64:delphi26_64:delphi27_64 +group.delphi64.compilerType=pascal-win +group.delphi64.demangler= +group.delphi64.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe +group.delphi64.versionFlags=| grep "Version" + +compiler.delphi21.exe =C:\Program Files (x86)\Embarcadero\Studio\15.0\Bin\DCC32.EXE +compiler.delphi21.name =x86 Delphi XE7 + +compiler.delphi22.exe =C:\Program Files (x86)\Embarcadero\Studio\16.0\Bin\DCC32.EXE +compiler.delphi22.name =x86 Delphi XE8 + +compiler.delphi23.exe =C:\Program Files (x86)\Embarcadero\Studio\17.0\bin\DCC32.exe +compiler.delphi23.name =x86 Delphi 10 Seattle + +compiler.delphi23_64.exe =C:\Program Files (x86)\Embarcadero\Studio\17.0\bin\DCC64.exe +compiler.delphi23_64.name=x64 Delphi 10 Seattle + +compiler.delphi24.exe =c:\Program Files (x86)\Embarcadero\Studio\18.0\Bin\DCC32.EXE +compiler.delphi24.name =x86 Delphi 10.1 Berlin + +compiler.delphi24_64.exe =c:\Program Files (x86)\Embarcadero\Studio\18.0\Bin\DCC64.EXE +compiler.delphi24_64.name=x64 Delphi 10.1 Berlin + +compiler.delphi25.exe =C:\Program Files (x86)\Embarcadero\Studio\19.0\Bin\DCC32.EXE +compiler.delphi25.name =x86 Delphi 10.2 Tokyo + +compiler.delphi25_64.exe =C:\Program Files (x86)\Embarcadero\Studio\19.0\Bin\DCC64.EXE +compiler.delphi25_64.name=x64 Delphi 10.2 Tokyo + +compiler.delphi26.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC32.EXE +compiler.delphi26.name =x86 Delphi 10.3 Rio + +compiler.delphi26_64.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC64.EXE +compiler.delphi26_64.name=x64 Delphi 10.3 Rio + +compiler.delphi27.exe =C:\Program Files (x86)\Embarcadero\Studio\21.0\Bin\DCC32.EXE +compiler.delphi27.name =x86 Delphi 10.4.2 Sydney + +compiler.delphi27_64.exe =C:\Program Files (x86)\Embarcadero\Studio\21.0\Bin\DCC64.EXE +compiler.delphi27_64.name=x64 Delphi 10.4.2 Sydney \ No newline at end of file diff --git a/etc/config/pascal.local.properties b/etc/config/pascal.local.properties new file mode 100644 index 00000000000..45bcf18c30e --- /dev/null +++ b/etc/config/pascal.local.properties @@ -0,0 +1,114 @@ +#new + +compilers=&delphi:&delphi64:&fpc +#maxLinesOfAsm=20000 +#1000 +rpathFlag=-O + +#compilers=&fpc +defaultCompiler=fpc331 + +group.fpc.compilers =fpc331:fpc260:fpc264:fpc304:fpc322 +group.fpc.options =C:\fpcupdeluxe\fpc\bin\x86_64-win64\fpc.cfg +group.fpc.demangler =/dev/null +group.fpc.objdumper =C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe +#C:\fpcupdeluxe\fpc\bin\x86_64-win64\objdump +group.fpc.isSemVer =true +group.fpc.baseName =x86-64 fpc + +group.fpc.options = +group.fpc.versionFlag =-h | grep "Compiler version" +group.fpc.supportsBinary=true +group.fpc.compilerType =pascal +group.fpc.demanglerType =pascal + +compiler.fpc331.exe =C:\fpcupdeluxe\fpc\bin\x86_64-win64\fpc.exe +compiler.fpc331.semver =3.3.1 + +compiler.fpc260.exe =C:\FPC\2.6.0\bin\i386-win32\fpc.exe +compiler.fpc260.semver =2.6.0 + +compiler.fpc264.exe =C:\FPC\2.6.4\bin\i386-win32\fpc.exe +compiler.fpc264.semver =2.6.4 + +compiler.fpc304.exe =C:\FPC\3.0.4\bin\i386-win32\fpc.exe +compiler.fpc304.semver =3.0.4 + +compiler.fpc322.exe =C:\FPC\3.2.2\bin\i386-win32\fpc.exe +compiler.fpc322.semver =3.2.2 + + + + +################################# +# Delphi +group.delphi.compilers=delphi25:delphi26:delphi27 +#delphi21:delphi22:delphi23:delphi24:delphi25:delphi26:delphi27 +group.delphi.compilerType=pascal-win +group.delphi.demangler= +group.delphi.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe +#D:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin\objdump.exe +group.delphi.versionFlags=| grep "Version" + +group.delphi64.compilers=delphi25_64:delphi26_64:delphi27_64 +#delphi23_64:delphi24_64:delphi25_64:delphi26_64:delphi27_64 +group.delphi64.compilerType=pascal-win +group.delphi64.demangler= +group.delphi64.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe +group.delphi64.versionFlags=| grep "Version" + +#compiler.delphi21.exe =C:\Program Files (x86)\Embarcadero\Studio\15.0\Bin\DCC32.EXE +#compiler.delphi21.name =x86 Delphi XE7 + +#compiler.delphi22.exe =C:\Program Files (x86)\Embarcadero\Studio\16.0\Bin\DCC32.EXE +#compiler.delphi22.name =x86 Delphi XE8 + +#compiler.delphi23.exe =C:\Program Files (x86)\Embarcadero\Studio\17.0\bin\DCC32.exe +#compiler.delphi23.name =x86 Delphi 10 Seattle + +#compiler.delphi23_64.exe =C:\Program Files (x86)\Embarcadero\Studio\17.0\bin\DCC64.exe +#compiler.delphi23_64.name=x64 Delphi 10 Seattle + +#compiler.delphi24.exe =c:\Program Files (x86)\Embarcadero\Studio\18.0\Bin\DCC32.EXE +#ompiler.delphi24.name =x86 Delphi 10.1 Berlin + +#compiler.delphi24_64.exe =c:\Program Files (x86)\Embarcadero\Studio\18.0\Bin\DCC64.EXE +#compiler.delphi24_64.name=x64 Delphi 10.1 Berlin + +compiler.delphi25.exe =C:\Program Files (x86)\Embarcadero\Studio\19.0\Bin\DCC32.EXE +compiler.delphi25.name =x86 Delphi 10.2 Tokyo + +compiler.delphi25_64.exe =C:\Program Files (x86)\Embarcadero\Studio\19.0\Bin\DCC64.EXE +compiler.delphi25_64.name=x64 Delphi 10.2 Tokyo + +compiler.delphi26.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC32.EXE +compiler.delphi26.name =x86 Delphi 10.3 Rio + +compiler.delphi26_64.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC64.EXE +compiler.delphi26_64.name=x64 Delphi 10.3 Rio + +compiler.delphi27.exe =C:\Program Files (x86)\Embarcadero\Studio\21.0\Bin\DCC32.EXE +compiler.delphi27.name =x86 Delphi 10.4.2 Sydney + +compiler.delphi27_64.exe =C:\Program Files (x86)\Embarcadero\Studio\21.0\Bin\DCC64.EXE +compiler.delphi27_64.name=x64 Delphi 10.4.2 Sydney + + + + + + + + +################################# +################################# +# Installed libs (See c++.amazon.properties for a scheme of libs group) +libs= + +################################# +################################# +# Installed tools + +#tools=llvm-mcatrunk:pahole + + From 7e8c4210c6cfa63f5177460dac34d1cc44c0b136 Mon Sep 17 00:00:00 2001 From: Paul McGee Date: Sat, 22 Nov 2025 18:41:26 +0800 Subject: [PATCH 03/27] Update compiler configurations for current system MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated Delphi versions and added Rust/Python configs: Pascal/Delphi compilers (etc/config/pascal.local.properties): - Kept FPC entries for future use (not currently installed) - Updated Delphi compilers: 10.3, 10.4.2, 11, 12.3, 13.1 - Added delphi28 (11 Alexandria - Studio 22.0) - Added delphi29 (12.3 Athens - Studio 23.0) - Added delphi31 (13.1 - Studio 37.0) - Both 32-bit and 64-bit versions configured Rust compiler (etc/config/rust.local.properties): - Local rustc at C:\Users\User\.cargo\bin\rustc.exe - Clippy tool config included (commented out) Python compiler (etc/config/python.local.properties): - Template for local Python installation - Path needs to be updated to match actual Python location Ready to test build and verify compiler detection. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- etc/config/pascal.local.properties | 28 ++++++++++++++++++++++------ etc/config/python.local.properties | 23 +++++++++++++++++++++++ etc/config/rust.local.properties | 29 +++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 6 deletions(-) create mode 100644 etc/config/python.local.properties create mode 100644 etc/config/rust.local.properties diff --git a/etc/config/pascal.local.properties b/etc/config/pascal.local.properties index 45bcf18c30e..dc349ff3063 100644 --- a/etc/config/pascal.local.properties +++ b/etc/config/pascal.local.properties @@ -41,17 +41,14 @@ compiler.fpc322.semver =3.2.2 ################################# -# Delphi -group.delphi.compilers=delphi25:delphi26:delphi27 -#delphi21:delphi22:delphi23:delphi24:delphi25:delphi26:delphi27 +# Delphi - Installed versions: 10.3, 10.4.2, 11, 12.3, 13.1 +group.delphi.compilers=delphi26:delphi27:delphi28:delphi29:delphi31 group.delphi.compilerType=pascal-win group.delphi.demangler= group.delphi.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe -#D:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin\objdump.exe group.delphi.versionFlags=| grep "Version" -group.delphi64.compilers=delphi25_64:delphi26_64:delphi27_64 -#delphi23_64:delphi24_64:delphi25_64:delphi26_64:delphi27_64 +group.delphi64.compilers=delphi26_64:delphi27_64:delphi28_64:delphi29_64:delphi31_64 group.delphi64.compilerType=pascal-win group.delphi64.demangler= group.delphi64.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe @@ -93,7 +90,26 @@ compiler.delphi27.name =x86 Delphi 10.4.2 Sydney compiler.delphi27_64.exe =C:\Program Files (x86)\Embarcadero\Studio\21.0\Bin\DCC64.EXE compiler.delphi27_64.name=x64 Delphi 10.4.2 Sydney +# Delphi 11 Alexandria (Studio 22.0) +compiler.delphi28.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\Bin\DCC32.EXE +compiler.delphi28.name =x86 Delphi 11 Alexandria +compiler.delphi28_64.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\Bin\DCC64.EXE +compiler.delphi28_64.name=x64 Delphi 11 Alexandria + +# Delphi 12.3 Athens (Studio 23.0) +compiler.delphi29.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\Bin\DCC32.EXE +compiler.delphi29.name =x86 Delphi 12.3 Athens + +compiler.delphi29_64.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\Bin\DCC64.EXE +compiler.delphi29_64.name=x64 Delphi 12.3 Athens + +# Delphi 13.1 (Studio 37.0) +compiler.delphi31.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\Bin\DCC32.EXE +compiler.delphi31.name =x86 Delphi 13.1 + +compiler.delphi31_64.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\Bin\DCC64.EXE +compiler.delphi31_64.name=x64 Delphi 13.1 diff --git a/etc/config/python.local.properties b/etc/config/python.local.properties new file mode 100644 index 00000000000..017814319fd --- /dev/null +++ b/etc/config/python.local.properties @@ -0,0 +1,23 @@ +# Windows Local Deployment - Python +# Local Python installation +# Update the path below to match your Python installation + +compilers=pythonlocal +defaultCompiler=pythonlocal + +# Update this path to your Python installation +# Common locations: +# - C:\Python312\python.exe +# - C:\Users\User\AppData\Local\Programs\Python\Python312\python.exe +# - C:\Program Files\Python312\python.exe + +compiler.pythonlocal.exe=python.exe +compiler.pythonlocal.name=Python (local) +# Uncomment and set semver if you want version ordering +#compiler.pythonlocal.semver=3.12 + +supportsBinary=false +interpreted=true +compilerType=python +objdumper= +instructionSet=python diff --git a/etc/config/rust.local.properties b/etc/config/rust.local.properties new file mode 100644 index 00000000000..9f7af5b9fb1 --- /dev/null +++ b/etc/config/rust.local.properties @@ -0,0 +1,29 @@ +# Windows Local Deployment - Rust +# Local rustc installation + +compilers=rustclocal +defaultCompiler=rustclocal + +compiler.rustclocal.exe=C:\Users\User\.cargo\bin\rustc.exe +compiler.rustclocal.name=rustc (local) + +supportsBinary=true +supportsBinaryObject=true +compilerType=rust +demangler= +demanglerArgs= +objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe +stubRe=\bmain\b +stubText=pub fn main() {/*stub provided by Compiler Explorer*/} + +versionFlag=-vV + +libs= + +# Clippy tool - optional, uncomment if clippy is installed +#tools=clippy +#tools.clippy.name=Clippy +#tools.clippy.exe=C:\Users\User\.cargo\bin\cargo-clippy.exe +#tools.clippy.type=postcompilation +#tools.clippy.class=clippy-tool +#tools.clippy.stdinHint=disabled From 21febb70cfa3a972a3af3af25c36cc5786f6aa09 Mon Sep 17 00:00:00 2001 From: Paul McGee Date: Sat, 22 Nov 2025 18:44:41 +0800 Subject: [PATCH 04/27] Enable Clippy and set Rust version to 1.85.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated Rust configuration: - Set rustc version to 1.85.0 - Enabled Clippy linting tool - Clippy executable: cargo-clippy.exe Clippy will be available as a post-compilation tool in the UI. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- etc/config/rust.local.properties | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/etc/config/rust.local.properties b/etc/config/rust.local.properties index 9f7af5b9fb1..b9bdb160ae8 100644 --- a/etc/config/rust.local.properties +++ b/etc/config/rust.local.properties @@ -1,11 +1,12 @@ # Windows Local Deployment - Rust -# Local rustc installation +# Local rustc installation - version 1.85.0 compilers=rustclocal defaultCompiler=rustclocal compiler.rustclocal.exe=C:\Users\User\.cargo\bin\rustc.exe -compiler.rustclocal.name=rustc (local) +compiler.rustclocal.name=rustc 1.85.0 (local) +compiler.rustclocal.semver=1.85.0 supportsBinary=true supportsBinaryObject=true @@ -20,10 +21,10 @@ versionFlag=-vV libs= -# Clippy tool - optional, uncomment if clippy is installed -#tools=clippy -#tools.clippy.name=Clippy -#tools.clippy.exe=C:\Users\User\.cargo\bin\cargo-clippy.exe -#tools.clippy.type=postcompilation -#tools.clippy.class=clippy-tool -#tools.clippy.stdinHint=disabled +# Clippy tool - enabled +tools=clippy +tools.clippy.name=Clippy +tools.clippy.exe=C:\Users\User\.cargo\bin\cargo-clippy.exe +tools.clippy.type=postcompilation +tools.clippy.class=clippy-tool +tools.clippy.stdinHint=disabled From eed1ce0d0dc899ed664c1c33b518f9abca695ac0 Mon Sep 17 00:00:00 2001 From: Paul McGee Date: Sat, 22 Nov 2025 18:47:05 +0800 Subject: [PATCH 05/27] Configure Python 3.13.9 with correct executable path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated Python configuration: - Set Python version to 3.13.9 - Configured executable path from Windows Store installation - Path: C:\Users\User\AppData\Local\Microsoft\WindowsApps\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\python.exe Python interpreter is now fully configured and ready to use. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- etc/config/python.local.properties | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/etc/config/python.local.properties b/etc/config/python.local.properties index 017814319fd..45ed2ed7e32 100644 --- a/etc/config/python.local.properties +++ b/etc/config/python.local.properties @@ -1,20 +1,12 @@ # Windows Local Deployment - Python -# Local Python installation -# Update the path below to match your Python installation +# Local Python installation - version 3.13.9 compilers=pythonlocal defaultCompiler=pythonlocal -# Update this path to your Python installation -# Common locations: -# - C:\Python312\python.exe -# - C:\Users\User\AppData\Local\Programs\Python\Python312\python.exe -# - C:\Program Files\Python312\python.exe - -compiler.pythonlocal.exe=python.exe -compiler.pythonlocal.name=Python (local) -# Uncomment and set semver if you want version ordering -#compiler.pythonlocal.semver=3.12 +compiler.pythonlocal.exe=C:\Users\User\AppData\Local\Microsoft\WindowsApps\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\python.exe +compiler.pythonlocal.name=Python 3.13.9 (local) +compiler.pythonlocal.semver=3.13.9 supportsBinary=false interpreted=true From 1a1c4665fac64f701ecad79dcd3da557a71ecd69 Mon Sep 17 00:00:00 2001 From: Paul McGee Date: Sat, 22 Nov 2025 19:06:27 +0800 Subject: [PATCH 06/27] Add C++Builder and fix Studio version mappings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Corrected configuration for all installed RAD Studio versions: Pascal/Delphi (etc/config/pascal.local.properties): - Removed 10.3 Rio (not installed) - Fixed 10.4.2 Sydney to Studio 20.0 (was incorrectly 21.0) - Configured: 10.4.2, 11, 12.3, 13.1 (32 & 64-bit) C++Builder (etc/config/c++.local.properties): - Added all C++Builder versions matching Delphi installations - 10.4.2 Sydney (20.0): bcc32x, bcc64 - 11 Alexandria (22.0): bcc32x, bcc64 - 12.3 Athens (23.0): bcc32x, bcc64x (newer compiler) - 13.1 (37.0): bcc32x, bcc64x (newer compiler) - Total: 8 C++Builder compilers (4 versions × 2 architectures) Studio directory mapping: - 20.0 = Delphi/C++Builder 10.4.2 Sydney - 22.0 = Delphi/C++Builder 11 Alexandria - 23.0 = Delphi/C++Builder 12.3 Athens - 37.0 = Delphi/C++Builder 13.1 Default compiler set to bcc131_64 (C++Builder 13.1 x64) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- etc/config/c++.local.properties | 60 +++++++++++++++++++++--------- etc/config/pascal.local.properties | 23 +++--------- 2 files changed, 48 insertions(+), 35 deletions(-) diff --git a/etc/config/c++.local.properties b/etc/config/c++.local.properties index 8b66d01cdb7..2e233ec639d 100644 --- a/etc/config/c++.local.properties +++ b/etc/config/c++.local.properties @@ -21,7 +21,7 @@ demangler=C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools # the compiler you want compiler explorer to start up in -defaultCompiler=bcc64 +defaultCompiler=bcc131_64 # note: adding new compiler groups @@ -32,25 +32,49 @@ defaultCompiler=bcc64 # check `c++.win32.properties` for how to modify the group options -# clang compilers -# if you want more compilers, you can do that by separating the names with `:` -# and then setting up a compiler.my_clang.exe and compiler.my_clang.name - -group.embclang.compilers =bcc32:bcc64 -group.embclang.groupName =emb clang -group.embclang.options =-Wno-user-defined-literals -Wno-comment -I'C:\Program Files (x86)\Embarcadero\Studio\21.0\include\dinkumware64' -I'C:\Program Files (x86)\Embarcadero\Studio\21.0\include\windows\crtl' +# C++Builder compilers - Installed versions: 10.4.2, 11, 12.3, 13.1 +group.embclang.compilers =bcc104_32:bcc104_64:bcc11_32:bcc11_64:bcc123_32:bcc123_64:bcc131_32:bcc131_64 +group.embclang.groupName =C++Builder +group.embclang.options =-Wno-user-defined-literals -Wno-comment group.msclang.compilers =mscl32:mscl64 -group.msclang.groupName =ms clang - -# this is the default path that clang++ is installed in -# if you installed it somewhere else, you should edit both variables - -compiler.bcc32.exe =C:\Program Files (x86)\Embarcadero\Studio\21.0\bin\bcc32x.exe -compiler.bcc32.name =c++ builder x86 - -compiler.bcc64.exe =C:\Program Files (x86)\Embarcadero\Studio\21.0\bin\bcc64.exe -compiler.bcc64.name =c++ builder x64 +group.msclang.groupName =ms clang + +# C++Builder 10.4.2 Sydney (Studio 20.0) +compiler.bcc104_32.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\bin\bcc32x.exe +compiler.bcc104_32.name =C++Builder 10.4.2 x86 +compiler.bcc104_32.options =-I'C:\Program Files (x86)\Embarcadero\Studio\20.0\include\dinkumware64' -I'C:\Program Files (x86)\Embarcadero\Studio\20.0\include\windows\crtl' + +compiler.bcc104_64.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\bin\bcc64.exe +compiler.bcc104_64.name =C++Builder 10.4.2 x64 +compiler.bcc104_64.options =-I'C:\Program Files (x86)\Embarcadero\Studio\20.0\include\dinkumware64' -I'C:\Program Files (x86)\Embarcadero\Studio\20.0\include\windows\crtl' + +# C++Builder 11 Alexandria (Studio 22.0) +compiler.bcc11_32.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\bin\bcc32x.exe +compiler.bcc11_32.name =C++Builder 11 x86 +compiler.bcc11_32.options =-I'C:\Program Files (x86)\Embarcadero\Studio\22.0\include\dinkumware64' -I'C:\Program Files (x86)\Embarcadero\Studio\22.0\include\windows\crtl' + +compiler.bcc11_64.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\bin\bcc64.exe +compiler.bcc11_64.name =C++Builder 11 x64 +compiler.bcc11_64.options =-I'C:\Program Files (x86)\Embarcadero\Studio\22.0\include\dinkumware64' -I'C:\Program Files (x86)\Embarcadero\Studio\22.0\include\windows\crtl' + +# C++Builder 12.3 Athens (Studio 23.0) +compiler.bcc123_32.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\bin\bcc32x.exe +compiler.bcc123_32.name =C++Builder 12.3 x86 +compiler.bcc123_32.options =-I'C:\Program Files (x86)\Embarcadero\Studio\23.0\include\dinkumware64' -I'C:\Program Files (x86)\Embarcadero\Studio\23.0\include\windows\crtl' + +compiler.bcc123_64.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\bin\bcc64x.exe +compiler.bcc123_64.name =C++Builder 12.3 x64 +compiler.bcc123_64.options =-I'C:\Program Files (x86)\Embarcadero\Studio\23.0\include\dinkumware64' -I'C:\Program Files (x86)\Embarcadero\Studio\23.0\include\windows\crtl' + +# C++Builder 13.1 (Studio 37.0) +compiler.bcc131_32.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\bin\bcc32x.exe +compiler.bcc131_32.name =C++Builder 13.1 x86 +compiler.bcc131_32.options =-I'C:\Program Files (x86)\Embarcadero\Studio\37.0\include\dinkumware64' -I'C:\Program Files (x86)\Embarcadero\Studio\37.0\include\windows\crtl' + +compiler.bcc131_64.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\bin\bcc64x.exe +compiler.bcc131_64.name =C++Builder 13.1 x64 +compiler.bcc131_64.options =-I'C:\Program Files (x86)\Embarcadero\Studio\37.0\include\dinkumware64' -I'C:\Program Files (x86)\Embarcadero\Studio\37.0\include\windows\crtl' compiler.mscl32.exe =C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\Llvm\bin\clang++.exe compiler.mscl32.name =clang x86 diff --git a/etc/config/pascal.local.properties b/etc/config/pascal.local.properties index dc349ff3063..1795acced0f 100644 --- a/etc/config/pascal.local.properties +++ b/etc/config/pascal.local.properties @@ -41,14 +41,14 @@ compiler.fpc322.semver =3.2.2 ################################# -# Delphi - Installed versions: 10.3, 10.4.2, 11, 12.3, 13.1 -group.delphi.compilers=delphi26:delphi27:delphi28:delphi29:delphi31 +# Delphi - Installed versions: 10.4.2, 11, 12.3, 13.1 +group.delphi.compilers=delphi27:delphi28:delphi29:delphi31 group.delphi.compilerType=pascal-win group.delphi.demangler= group.delphi.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe group.delphi.versionFlags=| grep "Version" -group.delphi64.compilers=delphi26_64:delphi27_64:delphi28_64:delphi29_64:delphi31_64 +group.delphi64.compilers=delphi27_64:delphi28_64:delphi29_64:delphi31_64 group.delphi64.compilerType=pascal-win group.delphi64.demangler= group.delphi64.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe @@ -72,22 +72,11 @@ group.delphi64.versionFlags=| grep "Version" #compiler.delphi24_64.exe =c:\Program Files (x86)\Embarcadero\Studio\18.0\Bin\DCC64.EXE #compiler.delphi24_64.name=x64 Delphi 10.1 Berlin -compiler.delphi25.exe =C:\Program Files (x86)\Embarcadero\Studio\19.0\Bin\DCC32.EXE -compiler.delphi25.name =x86 Delphi 10.2 Tokyo - -compiler.delphi25_64.exe =C:\Program Files (x86)\Embarcadero\Studio\19.0\Bin\DCC64.EXE -compiler.delphi25_64.name=x64 Delphi 10.2 Tokyo - -compiler.delphi26.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC32.EXE -compiler.delphi26.name =x86 Delphi 10.3 Rio - -compiler.delphi26_64.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC64.EXE -compiler.delphi26_64.name=x64 Delphi 10.3 Rio - -compiler.delphi27.exe =C:\Program Files (x86)\Embarcadero\Studio\21.0\Bin\DCC32.EXE +# Delphi 10.4.2 Sydney (Studio 20.0) +compiler.delphi27.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC32.EXE compiler.delphi27.name =x86 Delphi 10.4.2 Sydney -compiler.delphi27_64.exe =C:\Program Files (x86)\Embarcadero\Studio\21.0\Bin\DCC64.EXE +compiler.delphi27_64.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC64.EXE compiler.delphi27_64.name=x64 Delphi 10.4.2 Sydney # Delphi 11 Alexandria (Studio 22.0) From 4765888a4f70d9411457e4e051d6b5afc98575b2 Mon Sep 17 00:00:00 2001 From: Paul McGee Date: Sat, 22 Nov 2025 22:44:49 +0800 Subject: [PATCH 07/27] Update to Compiler Explorer 2025 framework MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated local configuration files for Windows deployment with Delphi and C++Builder compilers (10.4.2, 11, 12.3, 13.1). Key changes: - C++Builder: Configured 3 compiler types (32-bit, 64-bit classic, 64-bit modern) with proper ldPath for linking - Delphi: Configured 8 compilers (4 versions × 32/64-bit) via pascal-win.local.properties - Python: Updated to use system python command to avoid permissions issues - Cleaned up configuration by commenting out non-installed compilers (FPC, MS Clang, VC2019) - Updated example files for default language samples 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- etc/config/c++.local.properties | 95 ++++++++++-------- etc/config/pascal-win.local.properties | 82 ++++++++++------ etc/config/pascal.local.properties | 131 +++++++++++++------------ etc/config/python.local.properties | 2 +- examples/c++/default.cpp | 7 +- examples/pascal/default.pas | 12 +-- examples/rust/default.rs | 2 +- 7 files changed, 186 insertions(+), 145 deletions(-) diff --git a/etc/config/c++.local.properties b/etc/config/c++.local.properties index 2e233ec639d..920b7144d27 100644 --- a/etc/config/c++.local.properties +++ b/etc/config/c++.local.properties @@ -1,3 +1,6 @@ +# Compiler groups to include (msclang and vc2019 commented out - not installed) +compilers=&embclang32:&embclang64:&embclang64mod:&tdmgcc + # replace with the result of `echo %INCLUDE%` # if you want a specific includePath for a specific compiler, # you can set it up in that compiler's config, with, say @@ -16,8 +19,9 @@ includePath=C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Too # replace with the result of `where undname.exe` from a developer command prompt +# Demangler disabled - undname.exe not found -demangler=C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\bin\Hostx64\x64\undname.exe +demangler= # the compiler you want compiler explorer to start up in @@ -33,74 +37,87 @@ defaultCompiler=bcc131_64 # C++Builder compilers - Installed versions: 10.4.2, 11, 12.3, 13.1 -group.embclang.compilers =bcc104_32:bcc104_64:bcc11_32:bcc11_64:bcc123_32:bcc123_64:bcc131_32:bcc131_64 -group.embclang.groupName =C++Builder -group.embclang.options =-Wno-user-defined-literals -Wno-comment +group.embclang32.compilers =bcc104_32:bcc11_32:bcc123_32:bcc131_32 +group.embclang32.groupName =C++Builder x86 +group.embclang32.options =-Wno-user-defined-literals -Wno-comment -I'C:\Program Files (x86)\Embarcadero\Studio\20.0\include\dinkumware64' -I'C:\Program Files (x86)\Embarcadero\Studio\20.0\include\windows\crtl' + +group.embclang64.compilers =bcc104_64:bcc11_64:bcc123_64:bcc131_64 +group.embclang64.groupName =C++Builder x64 +group.embclang64.options =-Wno-user-defined-literals -Wno-comment -I'C:\Program Files (x86)\Embarcadero\Studio\20.0\include\dinkumware64' -I'C:\Program Files (x86)\Embarcadero\Studio\20.0\include\windows\crtl' + +group.embclang64mod.compilers=bcc123_64mod:bcc131_64mod +group.embclang64mod.groupName=C++Builder x64 modern (12.3, 13.1) +group.embclang64mod.options =-Wno-user-defined-literals -Wno-comment -isystem "C:\Program Files (x86)\Embarcadero\Studio\23.0\include" -isystem "C:\Program Files (x86)\Embarcadero\Studio\23.0\include\x86_64-w64-mingw32\c++\v1" -isystem "C:\Program Files (x86)\Embarcadero\Studio\23.0\lib\clang\15.0.7\include" -isystem "C:\Program Files (x86)\Embarcadero\Studio\23.0\include\x86_64-w64-mingw32" -group.msclang.compilers =mscl32:mscl64 -group.msclang.groupName =ms clang +# MS Clang compilers - not installed on this system +#group.msclang.compilers =mscl32:mscl64 +#group.msclang.groupName =ms clang # C++Builder 10.4.2 Sydney (Studio 20.0) compiler.bcc104_32.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\bin\bcc32x.exe compiler.bcc104_32.name =C++Builder 10.4.2 x86 -compiler.bcc104_32.options =-I'C:\Program Files (x86)\Embarcadero\Studio\20.0\include\dinkumware64' -I'C:\Program Files (x86)\Embarcadero\Studio\20.0\include\windows\crtl' +compiler.bcc104_32.ldPath =C:\Program Files (x86)\Embarcadero\Studio\20.0\lib\win32c\release compiler.bcc104_64.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\bin\bcc64.exe compiler.bcc104_64.name =C++Builder 10.4.2 x64 -compiler.bcc104_64.options =-I'C:\Program Files (x86)\Embarcadero\Studio\20.0\include\dinkumware64' -I'C:\Program Files (x86)\Embarcadero\Studio\20.0\include\windows\crtl' +compiler.bcc104_64.ldPath =C:\Program Files (x86)\Embarcadero\Studio\20.0\lib\win64\release # C++Builder 11 Alexandria (Studio 22.0) compiler.bcc11_32.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\bin\bcc32x.exe compiler.bcc11_32.name =C++Builder 11 x86 -compiler.bcc11_32.options =-I'C:\Program Files (x86)\Embarcadero\Studio\22.0\include\dinkumware64' -I'C:\Program Files (x86)\Embarcadero\Studio\22.0\include\windows\crtl' +compiler.bcc11_32.ldPath =C:\Program Files (x86)\Embarcadero\Studio\22.0\lib\win32c\release compiler.bcc11_64.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\bin\bcc64.exe compiler.bcc11_64.name =C++Builder 11 x64 -compiler.bcc11_64.options =-I'C:\Program Files (x86)\Embarcadero\Studio\22.0\include\dinkumware64' -I'C:\Program Files (x86)\Embarcadero\Studio\22.0\include\windows\crtl' +compiler.bcc11_64.ldPath =C:\Program Files (x86)\Embarcadero\Studio\22.0\lib\win64\release # C++Builder 12.3 Athens (Studio 23.0) compiler.bcc123_32.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\bin\bcc32x.exe compiler.bcc123_32.name =C++Builder 12.3 x86 -compiler.bcc123_32.options =-I'C:\Program Files (x86)\Embarcadero\Studio\23.0\include\dinkumware64' -I'C:\Program Files (x86)\Embarcadero\Studio\23.0\include\windows\crtl' +compiler.bcc123_32.ldPath =C:\Program Files (x86)\Embarcadero\Studio\23.0\lib\win32c\release -compiler.bcc123_64.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\bin\bcc64x.exe +compiler.bcc123_64.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\bin\bcc64.exe compiler.bcc123_64.name =C++Builder 12.3 x64 -compiler.bcc123_64.options =-I'C:\Program Files (x86)\Embarcadero\Studio\23.0\include\dinkumware64' -I'C:\Program Files (x86)\Embarcadero\Studio\23.0\include\windows\crtl' +compiler.bcc123_64.ldPath =C:\Program Files (x86)\Embarcadero\Studio\23.0\lib\win64\release + +compiler.bcc123_64mod.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\bin64\bcc64x.exe +compiler.bcc123_64mod.name =C++Builder 12.3 x64 modern +compiler.bcc123_64mod.ldPath =C:\Program Files (x86)\Embarcadero\Studio\23.0\lib\win64x\release|C:\Program Files (x86)\Embarcadero\Studio\23.0\x86_64-w64-mingw32\lib|C:\Program Files (x86)\Embarcadero\Studio\23.0\lib\clang\15.0.7\lib\windows # C++Builder 13.1 (Studio 37.0) compiler.bcc131_32.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\bin\bcc32x.exe compiler.bcc131_32.name =C++Builder 13.1 x86 -compiler.bcc131_32.options =-I'C:\Program Files (x86)\Embarcadero\Studio\37.0\include\dinkumware64' -I'C:\Program Files (x86)\Embarcadero\Studio\37.0\include\windows\crtl' +compiler.bcc131_32.ldPath =C:\Program Files (x86)\Embarcadero\Studio\37.0\lib\win32c\release -compiler.bcc131_64.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\bin\bcc64x.exe +compiler.bcc131_64.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\bin\bcc64.exe compiler.bcc131_64.name =C++Builder 13.1 x64 -compiler.bcc131_64.options =-I'C:\Program Files (x86)\Embarcadero\Studio\37.0\include\dinkumware64' -I'C:\Program Files (x86)\Embarcadero\Studio\37.0\include\windows\crtl' - -compiler.mscl32.exe =C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\Llvm\bin\clang++.exe -compiler.mscl32.name =clang x86 -compiler.mscl32.options =-m32 - -compiler.mscl64.exe =C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\Llvm\x64\bin\clang++.exe -compiler.mscl64.name =clang x64 - -# visual C++ compilers -# follow the same instructions as for clang -# note that if CE doesn't find a compiler, it won't break anything +compiler.bcc131_64.ldPath =C:\Program Files (x86)\Embarcadero\Studio\37.0\lib\win64\release -#compiler.vc2017_32.exe =C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Tools\MSVC\14.16.27023\bin\Hostx64\x86\cl.exe -#compiler.vc2017_32.name =VC 2017 x86 -compiler.vc2019_32.exe =C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\bin\Hostx64\x86\cl.exe -compiler.vc2019_32.name =VC 2019 x86 -compiler.vc2019_32.include =C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\lib\x86\ - -#compiler.vc2017_64.exe =C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Tools\MSVC\14.16.27023\bin\Hostx64\x64\cl.exe -#compiler.vc2017_64.name =VC 2017 x64 -compiler.vc2019_64.exe =C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\bin\Hostx64\x64\cl.exe -compiler.vc2019_64.name =VC 2019 x64 +compiler.bcc131_64mod.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\bin64\bcc64x.exe +compiler.bcc131_64mod.name =C++Builder 13.1 x64 modern +compiler.bcc131_64mod.ldPath =C:\Program Files (x86)\Embarcadero\Studio\37.0\lib\win64x\release|C:\Program Files (x86)\Embarcadero\Studio\37.0\x86_64-w64-mingw32\lib|C:\Program Files (x86)\Embarcadero\Studio\37.0\lib\clang\15.0.7\lib\windows + +#compiler.mscl32.exe =C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\Llvm\bin\clang++.exe +#compiler.mscl32.name =clang x86 +#compiler.mscl32.options =-m32 +# +#compiler.mscl64.exe =C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\Llvm\x64\bin\clang++.exe +#compiler.mscl64.name =clang x64 + +# Visual C++ 2019 compilers - not installed on this system +#group.vc2019.compilers=vc2019_32:vc2019_64 +#group.vc2019.groupName=Visual C++ 2019 +# +#compiler.vc2019_32.exe =C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\bin\Hostx64\x86\cl.exe +#compiler.vc2019_32.name =VC 2019 x86 +#compiler.vc2019_32.include =C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\lib\x86\ +# +#compiler.vc2019_64.exe =C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\bin\Hostx64\x64\cl.exe +#compiler.vc2019_64.name =VC 2019 x64 # gcc group.tdmgcc.compilers =gcc64 -compiler.gcc64.exe =C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\gcc.exe -compiler.gcc64.name =tdm64 gcc 9.0 +compiler.gcc64.exe =C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\g++.exe +compiler.gcc64.name =tdm64 g++ 9.0 diff --git a/etc/config/pascal-win.local.properties b/etc/config/pascal-win.local.properties index dcbce4a7a69..17cd7a614de 100644 --- a/etc/config/pascal-win.local.properties +++ b/etc/config/pascal-win.local.properties @@ -3,52 +3,74 @@ maxLinesOfAsm=1000 rpathFlag=-O ################################# -# Delphi -group.delphi.compilers=delphi21:delphi22:delphi23:delphi24:delphi25:delphi26:delphi27 +# Delphi - Installed versions: 10.4.2, 11, 12.3, 13.1 +group.delphi.compilers=delphi27:delphi28:delphi29:delphi31 group.delphi.compilerType=pascal-win group.delphi.demangler= group.delphi.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe #D:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin\objdump.exe group.delphi.versionFlags=| grep "Version" -group.delphi64.compilers=delphi23_64:delphi24_64:delphi25_64:delphi26_64:delphi27_64 +group.delphi64.compilers=delphi27_64:delphi28_64:delphi29_64:delphi31_64 group.delphi64.compilerType=pascal-win group.delphi64.demangler= group.delphi64.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe group.delphi64.versionFlags=| grep "Version" -compiler.delphi21.exe =C:\Program Files (x86)\Embarcadero\Studio\15.0\Bin\DCC32.EXE -compiler.delphi21.name =x86 Delphi XE7 +# Older Delphi versions - not installed on this system +#compiler.delphi21.exe =C:\Program Files (x86)\Embarcadero\Studio\15.0\Bin\DCC32.EXE +#compiler.delphi21.name =x86 Delphi XE7 +# +#compiler.delphi22.exe =C:\Program Files (x86)\Embarcadero\Studio\16.0\Bin\DCC32.EXE +#compiler.delphi22.name =x86 Delphi XE8 +# +#compiler.delphi23.exe =C:\Program Files (x86)\Embarcadero\Studio\17.0\bin\DCC32.exe +#compiler.delphi23.name =x86 Delphi 10 Seattle +# +#compiler.delphi23_64.exe =C:\Program Files (x86)\Embarcadero\Studio\17.0\bin\DCC64.exe +#compiler.delphi23_64.name=x64 Delphi 10 Seattle +# +#compiler.delphi24.exe =c:\Program Files (x86)\Embarcadero\Studio\18.0\Bin\DCC32.EXE +#compiler.delphi24.name =x86 Delphi 10.1 Berlin +# +#compiler.delphi24_64.exe =c:\Program Files (x86)\Embarcadero\Studio\18.0\Bin\DCC64.EXE +#compiler.delphi24_64.name=x64 Delphi 10.1 Berlin +# +#compiler.delphi25.exe =C:\Program Files (x86)\Embarcadero\Studio\19.0\Bin\DCC32.EXE +#compiler.delphi25.name =x86 Delphi 10.2 Tokyo +# +#compiler.delphi25_64.exe =C:\Program Files (x86)\Embarcadero\Studio\19.0\Bin\DCC64.EXE +#compiler.delphi25_64.name=x64 Delphi 10.2 Tokyo +# +#compiler.delphi26.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC32.EXE +#compiler.delphi26.name =x86 Delphi 10.3 Rio +# +#compiler.delphi26_64.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC64.EXE +#compiler.delphi26_64.name=x64 Delphi 10.3 Rio -compiler.delphi22.exe =C:\Program Files (x86)\Embarcadero\Studio\16.0\Bin\DCC32.EXE -compiler.delphi22.name =x86 Delphi XE8 - -compiler.delphi23.exe =C:\Program Files (x86)\Embarcadero\Studio\17.0\bin\DCC32.exe -compiler.delphi23.name =x86 Delphi 10 Seattle - -compiler.delphi23_64.exe =C:\Program Files (x86)\Embarcadero\Studio\17.0\bin\DCC64.exe -compiler.delphi23_64.name=x64 Delphi 10 Seattle - -compiler.delphi24.exe =c:\Program Files (x86)\Embarcadero\Studio\18.0\Bin\DCC32.EXE -compiler.delphi24.name =x86 Delphi 10.1 Berlin +compiler.delphi27.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC32.EXE +compiler.delphi27.name =x86 Delphi 10.4.2 Sydney -compiler.delphi24_64.exe =c:\Program Files (x86)\Embarcadero\Studio\18.0\Bin\DCC64.EXE -compiler.delphi24_64.name=x64 Delphi 10.1 Berlin +compiler.delphi27_64.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC64.EXE +compiler.delphi27_64.name=x64 Delphi 10.4.2 Sydney -compiler.delphi25.exe =C:\Program Files (x86)\Embarcadero\Studio\19.0\Bin\DCC32.EXE -compiler.delphi25.name =x86 Delphi 10.2 Tokyo +# Delphi 11 Alexandria (Studio 22.0) +compiler.delphi28.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\Bin\DCC32.EXE +compiler.delphi28.name =x86 Delphi 11 Alexandria -compiler.delphi25_64.exe =C:\Program Files (x86)\Embarcadero\Studio\19.0\Bin\DCC64.EXE -compiler.delphi25_64.name=x64 Delphi 10.2 Tokyo +compiler.delphi28_64.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\Bin\DCC64.EXE +compiler.delphi28_64.name=x64 Delphi 11 Alexandria -compiler.delphi26.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC32.EXE -compiler.delphi26.name =x86 Delphi 10.3 Rio +# Delphi 12.3 Athens (Studio 23.0) +compiler.delphi29.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\Bin\DCC32.EXE +compiler.delphi29.name =x86 Delphi 12.3 Athens -compiler.delphi26_64.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC64.EXE -compiler.delphi26_64.name=x64 Delphi 10.3 Rio +compiler.delphi29_64.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\Bin\DCC64.EXE +compiler.delphi29_64.name=x64 Delphi 12.3 Athens -compiler.delphi27.exe =C:\Program Files (x86)\Embarcadero\Studio\21.0\Bin\DCC32.EXE -compiler.delphi27.name =x86 Delphi 10.4.2 Sydney +# Delphi 13.1 (Studio 37.0) +compiler.delphi31.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\Bin\DCC32.EXE +compiler.delphi31.name =x86 Delphi 13.1 -compiler.delphi27_64.exe =C:\Program Files (x86)\Embarcadero\Studio\21.0\Bin\DCC64.EXE -compiler.delphi27_64.name=x64 Delphi 10.4.2 Sydney \ No newline at end of file +compiler.delphi31_64.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\Bin\DCC64.EXE +compiler.delphi31_64.name=x64 Delphi 13.1 \ No newline at end of file diff --git a/etc/config/pascal.local.properties b/etc/config/pascal.local.properties index 1795acced0f..8ef2c44f74a 100644 --- a/etc/config/pascal.local.properties +++ b/etc/config/pascal.local.properties @@ -1,58 +1,61 @@ #new -compilers=&delphi:&delphi64:&fpc -#maxLinesOfAsm=20000 +# Delphi compilers are configured in pascal-win.local.properties for Windows +#compilers=&delphi:&delphi64 +#maxLinesOfAsm=20000 #1000 rpathFlag=-O -#compilers=&fpc -defaultCompiler=fpc331 - -group.fpc.compilers =fpc331:fpc260:fpc264:fpc304:fpc322 -group.fpc.options =C:\fpcupdeluxe\fpc\bin\x86_64-win64\fpc.cfg -group.fpc.demangler =/dev/null -group.fpc.objdumper =C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe -#C:\fpcupdeluxe\fpc\bin\x86_64-win64\objdump -group.fpc.isSemVer =true -group.fpc.baseName =x86-64 fpc - -group.fpc.options = -group.fpc.versionFlag =-h | grep "Compiler version" -group.fpc.supportsBinary=true -group.fpc.compilerType =pascal -group.fpc.demanglerType =pascal - -compiler.fpc331.exe =C:\fpcupdeluxe\fpc\bin\x86_64-win64\fpc.exe -compiler.fpc331.semver =3.3.1 - -compiler.fpc260.exe =C:\FPC\2.6.0\bin\i386-win32\fpc.exe -compiler.fpc260.semver =2.6.0 - -compiler.fpc264.exe =C:\FPC\2.6.4\bin\i386-win32\fpc.exe -compiler.fpc264.semver =2.6.4 +#defaultCompiler=delphi31_64 -compiler.fpc304.exe =C:\FPC\3.0.4\bin\i386-win32\fpc.exe -compiler.fpc304.semver =3.0.4 - -compiler.fpc322.exe =C:\FPC\3.2.2\bin\i386-win32\fpc.exe -compiler.fpc322.semver =3.2.2 +# FPC compilers commented out - not installed on this system +#compilers=&fpc +#defaultCompiler=fpc331 +# +#group.fpc.compilers =fpc331:fpc260:fpc264:fpc304:fpc322 +#group.fpc.options =C:\fpcupdeluxe\fpc\bin\x86_64-win64\fpc.cfg +#group.fpc.demangler =/dev/null +#group.fpc.objdumper =C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe +#group.fpc.isSemVer =true +#group.fpc.baseName =x86-64 fpc +# +#group.fpc.options = +#group.fpc.versionFlag =-h | grep "Compiler version" +#group.fpc.supportsBinary=true +#group.fpc.compilerType =pascal +#group.fpc.demanglerType =pascal +# +#compiler.fpc331.exe =C:\fpcupdeluxe\fpc\bin\x86_64-win64\fpc.exe +#compiler.fpc331.semver =3.3.1 +# +#compiler.fpc260.exe =C:\FPC\2.6.0\bin\i386-win32\fpc.exe +#compiler.fpc260.semver =2.6.0 +# +#compiler.fpc264.exe =C:\FPC\2.6.4\bin\i386-win32\fpc.exe +#compiler.fpc264.semver =2.6.4 +# +#compiler.fpc304.exe =C:\FPC\3.0.4\bin\i386-win32\fpc.exe +#compiler.fpc304.semver =3.0.4 +# +#compiler.fpc322.exe =C:\FPC\3.2.2\bin\i386-win32\fpc.exe +#compiler.fpc322.semver =3.2.2 ################################# -# Delphi - Installed versions: 10.4.2, 11, 12.3, 13.1 -group.delphi.compilers=delphi27:delphi28:delphi29:delphi31 -group.delphi.compilerType=pascal-win -group.delphi.demangler= -group.delphi.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe -group.delphi.versionFlags=| grep "Version" - -group.delphi64.compilers=delphi27_64:delphi28_64:delphi29_64:delphi31_64 -group.delphi64.compilerType=pascal-win -group.delphi64.demangler= -group.delphi64.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe -group.delphi64.versionFlags=| grep "Version" +# Delphi - Configured in pascal-win.local.properties +#group.delphi.compilers=delphi27:delphi28:delphi29:delphi31 +#group.delphi.compilerType=pascal-win +#group.delphi.demangler= +#group.delphi.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe +#group.delphi.versionFlags=| grep "Version" +# +#group.delphi64.compilers=delphi27_64:delphi28_64:delphi29_64:delphi31_64 +#group.delphi64.compilerType=pascal-win +#group.delphi64.demangler= +#group.delphi64.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe +#group.delphi64.versionFlags=| grep "Version" #compiler.delphi21.exe =C:\Program Files (x86)\Embarcadero\Studio\15.0\Bin\DCC32.EXE #compiler.delphi21.name =x86 Delphi XE7 @@ -73,32 +76,32 @@ group.delphi64.versionFlags=| grep "Version" #compiler.delphi24_64.name=x64 Delphi 10.1 Berlin # Delphi 10.4.2 Sydney (Studio 20.0) -compiler.delphi27.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC32.EXE -compiler.delphi27.name =x86 Delphi 10.4.2 Sydney - -compiler.delphi27_64.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC64.EXE -compiler.delphi27_64.name=x64 Delphi 10.4.2 Sydney +#compiler.delphi27.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC32.EXE +#compiler.delphi27.name =x86 Delphi 10.4.2 Sydney +# +#compiler.delphi27_64.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC64.EXE +#compiler.delphi27_64.name=x64 Delphi 10.4.2 Sydney # Delphi 11 Alexandria (Studio 22.0) -compiler.delphi28.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\Bin\DCC32.EXE -compiler.delphi28.name =x86 Delphi 11 Alexandria - -compiler.delphi28_64.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\Bin\DCC64.EXE -compiler.delphi28_64.name=x64 Delphi 11 Alexandria +#compiler.delphi28.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\Bin\DCC32.EXE +#compiler.delphi28.name =x86 Delphi 11 Alexandria +# +#compiler.delphi28_64.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\Bin\DCC64.EXE +#compiler.delphi28_64.name=x64 Delphi 11 Alexandria # Delphi 12.3 Athens (Studio 23.0) -compiler.delphi29.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\Bin\DCC32.EXE -compiler.delphi29.name =x86 Delphi 12.3 Athens - -compiler.delphi29_64.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\Bin\DCC64.EXE -compiler.delphi29_64.name=x64 Delphi 12.3 Athens +#compiler.delphi29.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\Bin\DCC32.EXE +#compiler.delphi29.name =x86 Delphi 12.3 Athens +# +#compiler.delphi29_64.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\Bin\DCC64.EXE +#compiler.delphi29_64.name=x64 Delphi 12.3 Athens # Delphi 13.1 (Studio 37.0) -compiler.delphi31.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\Bin\DCC32.EXE -compiler.delphi31.name =x86 Delphi 13.1 - -compiler.delphi31_64.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\Bin\DCC64.EXE -compiler.delphi31_64.name=x64 Delphi 13.1 +#compiler.delphi31.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\Bin\DCC32.EXE +#compiler.delphi31.name =x86 Delphi 13.1 +# +#compiler.delphi31_64.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\Bin\DCC64.EXE +#compiler.delphi31_64.name=x64 Delphi 13.1 diff --git a/etc/config/python.local.properties b/etc/config/python.local.properties index 45ed2ed7e32..ee1badb64af 100644 --- a/etc/config/python.local.properties +++ b/etc/config/python.local.properties @@ -4,7 +4,7 @@ compilers=pythonlocal defaultCompiler=pythonlocal -compiler.pythonlocal.exe=C:\Users\User\AppData\Local\Microsoft\WindowsApps\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\python.exe +compiler.pythonlocal.exe=python compiler.pythonlocal.name=Python 3.13.9 (local) compiler.pythonlocal.semver=3.13.9 diff --git a/examples/c++/default.cpp b/examples/c++/default.cpp index e8c4fe4ecaa..8271996226c 100644 --- a/examples/c++/default.cpp +++ b/examples/c++/default.cpp @@ -1,4 +1,9 @@ -// Type your code here, or load an example. +#include + int square(int num) { return num * num; +} + +int main() { + std::cout << "hello"; } \ No newline at end of file diff --git a/examples/pascal/default.pas b/examples/pascal/default.pas index 1bbf29d518b..f3f570b5fdf 100644 --- a/examples/pascal/default.pas +++ b/examples/pascal/default.pas @@ -1,16 +1,10 @@ -unit output; - -interface - -function Square(const num: Integer): Integer; - -implementation - -// Type your code here, or load an example. +program test; function Square(const num: Integer): Integer; begin Square := num * num; end; +begin + writeln('Helllooo.'); end. diff --git a/examples/rust/default.rs b/examples/rust/default.rs index acf928648ea..db45321a1d2 100644 --- a/examples/rust/default.rs +++ b/examples/rust/default.rs @@ -12,4 +12,4 @@ pub fn square(num: i32) -> i32 { } // If you use `main()`, declare it as `pub` to see it in the output: -// pub fn main() { ... } + pub fn main() { print!("hello") } From 08021c9933525a7c6e2a49324994451b5bda015d Mon Sep 17 00:00:00 2001 From: Paul McGee Date: Sat, 22 Nov 2025 23:02:28 +0800 Subject: [PATCH 08/27] Add quick guide for local compiler configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added AddingLocalCompilers.md with concise examples for configuring Delphi and C++Builder compilers locally. References existing comprehensive documentation while providing practical quick-start examples. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- docs/AddingLocalCompilers.md | 74 ++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 docs/AddingLocalCompilers.md diff --git a/docs/AddingLocalCompilers.md b/docs/AddingLocalCompilers.md new file mode 100644 index 00000000000..5e51198aa7c --- /dev/null +++ b/docs/AddingLocalCompilers.md @@ -0,0 +1,74 @@ +# Adding Local Compilers - Quick Guide + +This is a quick reference for adding local compilers to your Compiler Explorer instance. For comprehensive details, see [AddingACompiler.md](AddingACompiler.md). + +## Configuration Files + +Compiler Explorer uses `.local.properties` files for local configurations. These override defaults and are gitignored. + +Common files: +- `etc/config/c++.local.properties` - C++ compilers +- `etc/config/pascal-win.local.properties` - Delphi compilers (Windows) +- `etc/config/rust.local.properties` - Rust compilers +- `etc/config/python.local.properties` - Python interpreters + +## Example 1: Adding Delphi Compilers + +**File:** `etc/config/pascal-win.local.properties` + +```ini +compilers=&delphi64 + +group.delphi64.compilers=delphi27_64:delphi28_64 +group.delphi64.compilerType=pascal-win + +compiler.delphi27_64.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\20.0\\Bin\\DCC64.EXE +compiler.delphi27_64.name=x64 Delphi 10.4.2 Sydney + +compiler.delphi28_64.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\22.0\\Bin\\DCC64.EXE +compiler.delphi28_64.name=x64 Delphi 11 Alexandria +``` + +## Example 2: Adding C++Builder Compilers + +**File:** `etc/config/c++.local.properties` + +```ini +compilers=&embclang64:&embclang64mod + +# Classic 64-bit compilers +group.embclang64.compilers=bcc11_64:bcc123_64 +group.embclang64.groupName=C++Builder x64 + +compiler.bcc11_64.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\22.0\\bin\\bcc64.exe +compiler.bcc11_64.name=C++Builder 11 x64 +compiler.bcc11_64.ldPath=C:\\Program Files (x86)\\Embarcadero\\Studio\\22.0\\lib\\win64\\release + +compiler.bcc123_64.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\23.0\\bin\\bcc64.exe +compiler.bcc123_64.name=C++Builder 12.3 x64 +compiler.bcc123_64.ldPath=C:\\Program Files (x86)\\Embarcadero\\Studio\\23.0\\lib\\win64\\release + +# Modern 64-bit compilers (12.3+) +group.embclang64mod.compilers=bcc123_64mod +group.embclang64mod.groupName=C++Builder x64 modern + +compiler.bcc123_64mod.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\23.0\\bin64\\bcc64x.exe +compiler.bcc123_64mod.name=C++Builder 12.3 x64 modern +compiler.bcc123_64mod.ldPath=C:\\Program Files (x86)\\Embarcadero\\Studio\\23.0\\lib\\win64x\\release|C:\\Program Files (x86)\\Embarcadero\\Studio\\23.0\\x86_64-w64-mingw32\\lib + +defaultCompiler=bcc123_64mod +``` + +## Key Properties + +- **compilers** - List of compiler IDs or groups (prefix groups with `&`) +- **compiler.ID.exe** - Path to compiler executable +- **compiler.ID.name** - Display name +- **compiler.ID.ldPath** - Library paths for linking (use `|` separator for multiple paths) +- **group.NAME.compilers** - List of compilers in group +- **group.NAME.compilerType** - Compiler type (e.g., `pascal-win`, `gcc`) + +## See Also + +- [AddingACompiler.md](AddingACompiler.md) - Full documentation +- [Configuration.md](Configuration.md) - Configuration system details From 2c4eb9c6be69a923e3a43d10afc3db9d4ca044e7 Mon Sep 17 00:00:00 2001 From: Paul McGee Date: Sun, 23 Nov 2025 00:28:24 +0800 Subject: [PATCH 09/27] Update README and add Delphi/C++Builder documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Updated README to highlight Delphi, Free Pascal, C++Builder, and Rust support - Added DelphiCppBuilderSpecifics.md with installation instructions from CE-for-Win-Pascal branch - Updated AddingLocalCompilers.md to reference the new Delphi/C++Builder guide 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- README.md | 190 ++++++++++++------------------ docs/AddingLocalCompilers.md | 1 + docs/DelphiCppBuilderSpecifics.md | 48 ++++++++ 3 files changed, 126 insertions(+), 113 deletions(-) create mode 100644 docs/DelphiCppBuilderSpecifics.md diff --git a/README.md b/README.md index a6eae15238a..7c54d721855 100644 --- a/README.md +++ b/README.md @@ -1,134 +1,108 @@ [![Build Status](https://github.com/compiler-explorer/compiler-explorer/workflows/Compiler%20Explorer/badge.svg)](https://github.com/compiler-explorer/compiler-explorer/actions?query=workflow%3A%22Compiler+Explorer%22) [![codecov](https://codecov.io/gh/compiler-explorer/compiler-explorer/branch/main/graph/badge.svg)](https://codecov.io/gh/compiler-explorer/compiler-explorer) -[![logo](public/logos/assembly.png)](https://godbolt.org/) -# Compiler Explorer - -Compiler Explorer is an interactive compiler exploration website. Edit code in C, C++, C#, F#, Rust, Go, D, Haskell, Swift, Pascal, -[ispc](https://ispc.github.io/), Python, Java, or any of the other -[30+ supported languages](https://godbolt.org/api/languages), and see how that code looks after being -compiled in real time. +![image](https://user-images.githubusercontent.com/11953157/120695427-f6101e00-c4dd-11eb-87b5-082fe000c01f.png) -[Bug Report](https://github.com/compiler-explorer/compiler-explorer/issues/new?assignees=&labels=bug&projects=&template=bug_report.yml&title=%5BBUG%5D%3A+) -· -[Compiler Request](https://github.com/compiler-explorer/compiler-explorer/issues/new?assignees=&labels=request%2Cnew-compilers&projects=&template=compiler_request.yml&title=%5BCOMPILER+REQUEST%5D%3A+) -· -[Feature Request](https://github.com/compiler-explorer/compiler-explorer/issues/new?assignees=&labels=request&projects=&template=feature_request.yml&title=%5BREQUEST%5D%3A+) -· -[Language Request](https://github.com/compiler-explorer/compiler-explorer/issues/new?assignees=&labels=request%2Cnew-language&projects=&template=language_request.yml&title=%5BLANGUAGE+REQUEST%5D%3A+) -· -[Library Request](https://github.com/compiler-explorer/compiler-explorer/issues/new?assignees=&labels=request%2Cnew-libs&projects=&template=library_request.yml&title=%5BLIB+REQUEST%5D%3A+) -· [Report Vulnerability](https://github.com/compiler-explorer/compiler-explorer/security/advisories/new) -# Overview -Multiple compilers are supported for each language, many different tools and visualizations are available, and the UI -layout is configurable (thanks to [GoldenLayout](https://www.golden-layout.com/)). +# Compiler Explorer +# - for DELPHI, Free Pascal, and C++ BUILDER. And Rust! -Try out at [godbolt.org](https://godbolt.org), or [run your own local instance](#running-a-local-instance). An overview -of what the site lets you achieve, why it's useful, and how to use it is -[available here](docs/WhatIsCompilerExplorer.md), or in [this talk](https://www.youtube.com/watch?v=_9sGKcvT-TA). +[See **_Windows install_** guideline for Delphi & fpc **_here_**](docs/DelphiCppBuilderSpecifics.md) -**Compiler Explorer** follows a [Code of Conduct](CODE_OF_CONDUCT.md) which aims to foster an open and welcoming -environment. +--- -**Compiler Explorer** was started in 2012 to show how C++ constructs are translated to assembly code. It started as a -`tmux` session with `vi` running in one pane and `watch gcc -S foo.cc -o -` running in the other. +**Compiler Explorer** is an interactive compiler exploration website. Edit C, C++, Rust, Go, D, Haskell, Swift, Pascal, [ispc](https://ispc.github.io/) or other language code, and see how that code looks after being compiled in real time. + Multiple compilers are supported, many different tools and visualisations are available, and the UI layout + is configurable (thanks to [GoldenLayout](https://www.golden-layout.com/)). -Since then, it has become a public website serving over -[3,000,000 compilations per week](https://stats.compiler-explorer.com). +Try out at [godbolt.org](https://godbolt.org), or [run your own local instance](#running-a-local-instance). You can financially support [this project on Patreon](https://patreon.com/mattgodbolt), -[GitHub](https://github.com/sponsors/mattgodbolt/), -[Paypal](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=KQWQZ7GPY2GZ6&item_name=Compiler+Explorer+development¤cy_code=USD&source=url), -or by buying cool gear on the [Compiler Explorer store](https://shop.compiler-explorer.com). + [GitHub](https://github.com/sponsors/mattgodbolt/), [Paypal](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=KQWQZ7GPY2GZ6&item_name=Compiler+Explorer+development¤cy_code=USD&source=url), or by + buying cool gear on the [Compiler Explorer store](https://shop.spreadshirt.com/compiler-explorer/). + +**Compiler Explorer** follows a [Code of Conduct](CODE_OF_CONDUCT.md) which + aims to foster an open and welcoming environment. + +**Compiler Explorer** was started in 2012 to show how C++ constructs translated to assembly code. It started out as a + `tmux` session with `vi` running in one pane and `watch gcc -S foo.cc -o -` running in the other. + +Since then, it has become a public website serving around [2,000,000 compilations per week](https://www.stathat.com/cards/Tk5csAWI0O7x). ## Using Compiler Explorer ### FAQ -There is now a FAQ section [in the repository wiki](https://github.com/compiler-explorer/compiler-explorer/wiki/FAQ). If -your question is not present, please contact us as described below, so we can help you. If you find that the FAQ is -lacking some important point, please feel free to contribute to it and/or ask us to clarify it. +There is now a FAQ section [in the repository wiki](https://github.com/compiler-explorer/compiler-explorer/wiki/FAQ). + If your question is not present, please contact us as described below, so we can help you. + If you find that the FAQ is lacking some important point, please free to contribute to it and/or ask us to clarify it. ### Videos -Several videos showcase some features of Compiler Explorer: +There are a number of videos that showcase some features of Compiler Explorer: -- [Compiler Explorer 2023: What's New?](https://www.youtube.com/watch?v=Ey0H79z_pco): Presentation for CppNorth 2023. -- [Presentation for CppCon 2019 about the project](https://www.youtube.com/watch?v=kIoZDUd5DKw) -- [Older 2 part series of videos](https://www.youtube.com/watch?v=4_HL3PH4wDg) which go into a bit more detail into the - more obscure features. -- [Just Enough Assembly for Compiler Explorer](https://youtu.be/QLolzolunJ4): Practical introduction to Assembly with a - focus on the usage of Compiler Explorer, from CppCon 2021. -- [Playlist: Compiler Explorer](https://www.youtube.com/playlist?list=PL2HVqYf7If8dNYVN6ayjB06FPyhHCcnhG): A collection - of videos discussing Compiler Explorer; using it, installing it, what it's for, etc. - -A [Road map](docs/Roadmap.md) is available which gives a little insight into the future plans for **Compiler Explorer**. +* [presentation for CppCon 2019 about the project](https://www.youtube.com/watch?v=kIoZDUd5DKw) +* [older 2 part series of videos](https://www.youtube.com/watch?v=4_HL3PH4wDg) which go into a bit more detail + into the more obscure features. +* [playlist: Compiler Explorer](https://www.youtube.com/playlist?list=PL2HVqYf7If8dNYVN6ayjB06FPyhHCcnhG): A collection of videos discussing Compiler Explorer; using it, installing it, what it's for, etc. ## Developing -**Compiler Explorer** is written in [TypeScript](https://www.typescriptlang.org/), on [Node.js](https://nodejs.org/). +**Compiler Explorer** is written in [Node.js](https://nodejs.org/). -Assuming you have a compatible version of `node` installed, on Linux simply running `make` ought to get you up and -running with an Explorer running on port 10240 on your local machine: -[http://localhost:10240/](http://localhost:10240/). If this doesn't work for you, please contact us, as we consider it -important you can quickly and easily get running. Currently, **Compiler Explorer** requires -[`node` 20 or higher](CONTRIBUTING.md#node-version) installed, either on the path or at `NODE_DIR` (an environment variable or -`make` parameter). +Assuming you have a compatible version of `node` installed, on Linux simply running + `make` ought to get you up and running with an Explorer running on port 10240 + on your local machine: [http://localhost:10240/](http://localhost:10240/). If this doesn't work for you, please contact + us, as we consider it important you can quickly and easily get running. + Currently, **Compiler Explorer** + requires [at least `node` 12 _(LTS version)_](CONTRIBUTING.md#node-version) installed, either on the path or at `NODE_DIR` + (an environment variable or `make` parameter). -Running with `make EXTRA_ARGS='--language LANG'` will allow you to load `LANG` exclusively, where `LANG` is one for the -language ids/aliases defined in `lib/languages.ts`. For example, to only run **Compiler Explorer** with C++ support, -you'd run `make EXTRA_ARGS='--language c++'`. You can supply multiple `--language` arguments to restrict to more than -one language. The `Makefile` will automatically install all the third-party libraries needed to run; using `npm` to -install server-side and client-side components. +Running with `make EXTRA_ARGS='--language LANG'` will allow you to load + `LANG` exclusively, where `LANG` is one for the language ids/aliases defined + in `lib/languages.js`. For example, to only run CE with C++ support, you'd run + `make EXTRA_ARGS='--language c++'`. The `Makefile` will automatically install all the + third party libraries needed to run; using `npm` to install server-side and + client side components. -For development, we suggest using `make dev` to enable some useful features, such as automatic reloading on file changes -and shorter startup times. +For development, we suggest using `make dev` to enable some useful features, + such as automatic reloading on file changes and shorter startup times. You can also use `npm run dev` to run if `make dev` doesn't work on your machine. -When making UI changes, we recommend following the [UI Testing Checklist](docs/TestingTheUi.md) to ensure all components work correctly. - -Some languages need extra tools to demangle them, e.g. `rust`, `d`, or `haskell`. Such tools are kept separately in the -[tools repo](https://github.com/compiler-explorer/compiler-explorer-tools). +Some languages need extra tools to demangle them, e.g. `rust`, `d`, or `haskell`. + Such tools are kept separately in the + [tools repo](https://github.com/compiler-explorer/compiler-explorer-tools). -Configuring compiler explorer is achieved via configuration files in the `etc/config` directory. Values are `key=value`. -Options in a `{type}.local.properties` file (where `{type}` is `c++` or similar) override anything in the -`{type}.defaults.properties` file. There is a `.gitignore` file to ignore `*.local.*` files, so these won't be checked -into git, and you won't find yourself fighting with updated versions when you `git pull`. For more information see -[Adding a Compiler](docs/AddingACompiler.md). +Configuring compiler explorer is achieved via configuration files in the `etc/config` directory. Values are + `key=value`. Options in a `{type}.local.properties` file (where `{type}` is `c++` or similar) override anything in the + `{type}.defaults.properties` file. There is a `.gitignore` file to ignore `*.local.*` files, so these won't be checked + into git, and you won't find yourself fighting with updated versions when you `git pull`. For more information see + [Adding a Compiler](docs/AddingACompiler.md). -Check [CONTRIBUTING.md](./CONTRIBUTING.md) for detailed information about how you can contribute to **Compiler -Explorer**, and the [docs](./docs) folder for specific details regarding various things you might want to do, such as -how to add new compilers or languages to the site. +A [Road map](docs/Roadmap.md) is available which gives a little insight into + the future plans for **Compiler Explorer**. ### Running a local instance -If you want to point it at your own GCC or similar binaries, either edit the `etc/config/LANG.defaults.properties` or -else make a new one with the name `LANG.local.properties`, substituting `LANG` as needed. `*.local.properties` files -have the highest priority when loading properties. +If you want to point it at your own GCC or similar binaries, either edit the + `etc/config/LANG.defaults.properties` or else make a new one with + the name `LANG.local.properties`, substituting `LANG` as needed. + `*.local.properties` files have the highest priority when loading properties. -For a quick and easy way to add local compilers, use the -[CE Properties Wizard](etc/scripts/ce-properties-wizard/) which automatically detects and configures compilers -for [30+ languages](etc/scripts/ce-properties-wizard/README.md#supported-languages). -See [Adding a Compiler](docs/AddingACompiler.md) for more details. - -If you want to support multiple compilers and languages like [godbolt.org](https://godbolt.org), you can use the -`bin/ce_install install compilers` command in the [infra](https://github.com/compiler-explorer/infra) project to install -all or some of the compilers. Compilers installed in this way can be loaded through the configuration in -`etc/config/*.amazon.properties`. If you need to deploy in a completely offline environment, you may need to remove some -parts of the configuration that are pulled from `www.godbolt.ms@443`. - -When running in a corporate setting the URL shortening service can be replaced by an internal one if the default storage -driver isn't appropriate for your environment. To do this, add a new module in `lib/shortener/myservice.js` and set the -`urlShortenService` variable in configuration. This module should export a single function, see the -[tinyurl module](lib/shortener/tinyurl.ts) for an example. +When running in a corporate setting the URL shortening service can be replaced + by an internal one if the default storage driver isn't appropriate for your + environment. To do this, add a new module in `lib/shortener/myservice.js` and + set the `urlShortenService` variable in configuration. This module should + export a single function, see the [tinyurl module](lib/shortener/tinyurl.js) + for an example. ### RESTful API -There's a simple restful API that can be used to do compiles to asm and to list compilers. +There's a simple restful API that can be used to do compiles to asm and to + list compilers. You can find the API documentation [here](docs/API.md). @@ -136,8 +110,7 @@ You can find the API documentation [here](docs/API.md). We run a [Compiler Explorer Discord](https://discord.gg/B5WacA7), which is a place to discuss using or developing Compiler Explorer. We also have a presence on the [cpplang](https://cppalliance.org/slack/) Slack channel -`#compiler_explorer` and we have -[a public mailing list](https://groups.google.com/forum/#!forum/compiler-explorer-discussion). +`#compiler_explorer` and we have [a public mailing list](https://groups.google.com/forum/#!forum/compiler-explorer-discussion). There's a development channel on the discord, and also a [development mailing list](https://groups.google.com/forum/#!forum/compiler-explorer-development). @@ -145,31 +118,22 @@ There's a development channel on the discord, and also a Feel free to raise an issue on [github](https://github.com/compiler-explorer/compiler-explorer/issues) or [email Matt directly](mailto:matt@godbolt.org) for more help. -## Official domains - -Following are the official domains for Compiler Explorer: - -- https://godbolt.org/ -- https://godbo.lt/ -- https://compiler-explorer.com/ - -The domains allow arbitrary subdomains, e.g., https://foo.godbolt.org/, which is convenient since each subdomain has an -independent local state. Also, language subdomains such as https://rust.compiler-explorer.com/ will load with that -language already selected. - ## Credits -**Compiler Explorer** is maintained by the awesome people listed in the [AUTHORS](AUTHORS.md) file. - -We would like to thank the contributors listed in the [CONTRIBUTORS](CONTRIBUTORS.md) file, who have helped shape -**Compiler Explorer**. +**Compiler Explorer** is maintained by the awesome people listed in the + [AUTHORS](AUTHORS.md) file. -We would also like to especially thank these people for their contributions to **Compiler Explorer**: +We would like to thank the contributors listed in the + [CONTRIBUTORS](CONTRIBUTORS.md) file, who have helped shape **Compiler Explorer**. -- [Gabriel Devillers](https://github.com/voxelf) (_while working for [Kalray](http://www.kalrayinc.com/)_) +We would also like to specially thank these people for their contributions to + **Compiler Explorer**: +- [Gabriel Devillers](https://github.com/voxelf) + (_while working for [Kalray](http://www.kalrayinc.com/)_) - [Johan Engelen](https://github.com/JohanEngelen) - [Joshua Sheard](https://github.com/jsheard) +- [Marc Poulhiès](https://github.com/dkm) - [Andrew Pardoe](https://github.com/AndrewPardoe) -Many [amazing sponsors](https://godbolt.org/#sponsors), both individuals and companies, have helped fund and promote -Compiler Explorer. +A number of [amazing sponsors](https://godbolt.org/#sponsors), both individuals and companies, have helped fund and + promote Compiler Explorer. diff --git a/docs/AddingLocalCompilers.md b/docs/AddingLocalCompilers.md index 5e51198aa7c..df358d61b8f 100644 --- a/docs/AddingLocalCompilers.md +++ b/docs/AddingLocalCompilers.md @@ -72,3 +72,4 @@ defaultCompiler=bcc123_64mod - [AddingACompiler.md](AddingACompiler.md) - Full documentation - [Configuration.md](Configuration.md) - Configuration system details +- [DelphiCppBuilderSpecifics.md](DelphiCppBuilderSpecifics.md) - Delphi and C++Builder setup guide diff --git a/docs/DelphiCppBuilderSpecifics.md b/docs/DelphiCppBuilderSpecifics.md new file mode 100644 index 00000000000..bec1b094beb --- /dev/null +++ b/docs/DelphiCppBuilderSpecifics.md @@ -0,0 +1,48 @@ +# Delphi & C++Builder Specifics + +```The original basis document: https://github.com/compiler-explorer/compiler-explorer/blob/main/docs/WindowsNative.md``` + +## Installation + +- Install latest Node.js (my current = v14.17.0) +- Install latest npm (my current = 7.14.0) + +- Clone this branch of Compiler Explorer repository into a directory: https://github.com/compiler-explorer/compiler-explorer + + ie https://github.com/pmcgee69/compiler-explorer/edit/CE-for-Win-Pascal + +In the directory, run: +- npm install +- npm install webpack -g +- npm install webpack-cli -g +- npm update webpack + +You may need to fix up some directories... maybe comment out eg the C++ options. Changes were made to the following files from this repo: + +- \lib\languages.js - Comment out languages as desired. +- \lib\languages.PasWin.js + +For Object Pascal compilers: +- \lib\compilers\pascal.js +- \lib\compilers\pascal-win.js +- \etc\config\pascal.defaults.properties + +For C++ compilers: +- \etc\config\c++.win32.properties +- \etc\config\c++.local.properties + +Finally: +- npm start + +To access Compiler Explorer, browse to: (http://localhost:10240/) + +## Screenshots + +// --- --- --- --- --- --- --- --- +![Install](https://user-images.githubusercontent.com/11953157/120332379-455d1f80-c321-11eb-85ae-e9cd31cc9814.png) +// --- --- --- --- --- --- --- --- +![Start Server](https://user-images.githubusercontent.com/11953157/120332478-5d34a380-c321-11eb-9bd5-a2a86447e963.png) +// --- --- --- --- --- --- --- --- +![Compiler Explorer - Object Pascal](https://user-images.githubusercontent.com/11953157/120333650-7b4ed380-c322-11eb-8042-5b1d710a5814.png) +// --- --- --- --- --- --- --- --- +![Compiler Explorer - C++](https://user-images.githubusercontent.com/11953157/120351986-eaccbf00-c332-11eb-939c-a0338e333945.png) From 41d0dfc707729886ac8a2dc4006150999fee61af Mon Sep 17 00:00:00 2001 From: Paul McGee Date: Sun, 23 Nov 2025 02:20:16 +0800 Subject: [PATCH 10/27] Fix Pascal language not appearing in dropdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consolidated Delphi compiler configuration into pascal.local.properties. The system only loads pascal.local.properties, not pascal-win.local.properties. Moved all Delphi compiler group and individual definitions from pascal-win.local.properties into pascal.local.properties with pascal-win compilerType. Also added pascal-win.defaults.properties for Windows-specific defaults. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- etc/config/pascal-win.defaults.properties | 9 +++++ etc/config/pascal.local.properties | 49 +++++++++++++++++++---- 2 files changed, 51 insertions(+), 7 deletions(-) create mode 100644 etc/config/pascal-win.defaults.properties diff --git a/etc/config/pascal-win.defaults.properties b/etc/config/pascal-win.defaults.properties new file mode 100644 index 00000000000..9f7ca15bb4b --- /dev/null +++ b/etc/config/pascal-win.defaults.properties @@ -0,0 +1,9 @@ +# Default settings for Pascal on Windows +compilerType=pascal-win +supportsBinary=true +rpathFlag=-O +objdumper=objdump +demangler= +versionFlag=| grep "Version" + +# Compilers are defined in pascal-win.local.properties diff --git a/etc/config/pascal.local.properties b/etc/config/pascal.local.properties index 8ef2c44f74a..54f6a093cb4 100644 --- a/etc/config/pascal.local.properties +++ b/etc/config/pascal.local.properties @@ -1,12 +1,47 @@ -#new - -# Delphi compilers are configured in pascal-win.local.properties for Windows -#compilers=&delphi:&delphi64 -#maxLinesOfAsm=20000 -#1000 +# Delphi compilers for Windows +compilers=&delphi:&delphi64 +maxLinesOfAsm=1000 rpathFlag=-O +defaultCompiler=delphi31_64 + +# Delphi 32-bit group +group.delphi.compilers=delphi27:delphi28:delphi29:delphi31 +group.delphi.compilerType=pascal-win +group.delphi.demangler= +group.delphi.objdumper=C:\\Program Files (x86)\\Embarcadero\\Dev-Cpp\\TDM-GCC-64\\bin\\objdump.exe +group.delphi.versionFlags=| grep "Version" + +# Delphi 64-bit group +group.delphi64.compilers=delphi27_64:delphi28_64:delphi29_64:delphi31_64 +group.delphi64.compilerType=pascal-win +group.delphi64.demangler= +group.delphi64.objdumper=C:\\Program Files (x86)\\Embarcadero\\Dev-Cpp\\TDM-GCC-64\\bin\\objdump.exe +group.delphi64.versionFlags=| grep "Version" + +# Individual compiler definitions +compiler.delphi27.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\20.0\\Bin\\DCC32.EXE +compiler.delphi27.name=x86 Delphi 10.4.2 Sydney + +compiler.delphi27_64.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\20.0\\Bin\\DCC64.EXE +compiler.delphi27_64.name=x64 Delphi 10.4.2 Sydney + +compiler.delphi28.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\22.0\\Bin\\DCC32.EXE +compiler.delphi28.name=x86 Delphi 11 Alexandria + +compiler.delphi28_64.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\22.0\\Bin\\DCC64.EXE +compiler.delphi28_64.name=x64 Delphi 11 Alexandria + +compiler.delphi29.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\23.0\\Bin\\DCC32.EXE +compiler.delphi29.name=x86 Delphi 12.3 Athens + +compiler.delphi29_64.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\23.0\\Bin\\DCC64.EXE +compiler.delphi29_64.name=x64 Delphi 12.3 Athens + +compiler.delphi31.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\37.0\\Bin\\DCC32.EXE +compiler.delphi31.name=x86 Delphi 13.1 -#defaultCompiler=delphi31_64 +compiler.delphi31_64.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\37.0\\Bin\\DCC64.EXE +compiler.delphi31_64.name=x64 Delphi 13.1 # FPC compilers commented out - not installed on this system #compilers=&fpc From 4f0c7797e2170e4e102d223d018edb2580cac5c0 Mon Sep 17 00:00:00 2001 From: Paul McGee Date: Sun, 23 Nov 2025 14:15:34 +0800 Subject: [PATCH 11/27] Add FPC (Free Pascal Compiler) support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added 4 FPC compiler versions to pascal.local.properties: - FPC 3.0.0 - FPC 3.2.0 - FPC 3.2.2 - FPC 3.3.1 All FPC compilers located at D:\fpc\{version}\fpc\bin\x86_64-win64\fpc.exe 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- etc/config/pascal.local.properties | 63 ++++++++++++++---------------- 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/etc/config/pascal.local.properties b/etc/config/pascal.local.properties index 54f6a093cb4..18934f308c4 100644 --- a/etc/config/pascal.local.properties +++ b/etc/config/pascal.local.properties @@ -1,5 +1,5 @@ -# Delphi compilers for Windows -compilers=&delphi:&delphi64 +# Delphi and FPC compilers for Windows +compilers=&delphi:&delphi64:&fpc maxLinesOfAsm=1000 rpathFlag=-O defaultCompiler=delphi31_64 @@ -43,37 +43,34 @@ compiler.delphi31.name=x86 Delphi 13.1 compiler.delphi31_64.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\37.0\\Bin\\DCC64.EXE compiler.delphi31_64.name=x64 Delphi 13.1 -# FPC compilers commented out - not installed on this system -#compilers=&fpc -#defaultCompiler=fpc331 -# -#group.fpc.compilers =fpc331:fpc260:fpc264:fpc304:fpc322 -#group.fpc.options =C:\fpcupdeluxe\fpc\bin\x86_64-win64\fpc.cfg -#group.fpc.demangler =/dev/null -#group.fpc.objdumper =C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe -#group.fpc.isSemVer =true -#group.fpc.baseName =x86-64 fpc -# -#group.fpc.options = -#group.fpc.versionFlag =-h | grep "Compiler version" -#group.fpc.supportsBinary=true -#group.fpc.compilerType =pascal -#group.fpc.demanglerType =pascal -# -#compiler.fpc331.exe =C:\fpcupdeluxe\fpc\bin\x86_64-win64\fpc.exe -#compiler.fpc331.semver =3.3.1 -# -#compiler.fpc260.exe =C:\FPC\2.6.0\bin\i386-win32\fpc.exe -#compiler.fpc260.semver =2.6.0 -# -#compiler.fpc264.exe =C:\FPC\2.6.4\bin\i386-win32\fpc.exe -#compiler.fpc264.semver =2.6.4 -# -#compiler.fpc304.exe =C:\FPC\3.0.4\bin\i386-win32\fpc.exe -#compiler.fpc304.semver =3.0.4 -# -#compiler.fpc322.exe =C:\FPC\3.2.2\bin\i386-win32\fpc.exe -#compiler.fpc322.semver =3.2.2 +# FPC (Free Pascal Compiler) group +group.fpc.compilers=fpc300:fpc320:fpc322:fpc331 +group.fpc.compilerType=pascal +group.fpc.isSemVer=true +group.fpc.baseName=FPC +group.fpc.versionFlag=-iV +group.fpc.supportsBinary=true +group.fpc.objdumper=C:\\Program Files (x86)\\Embarcadero\\Dev-Cpp\\TDM-GCC-64\\bin\\objdump.exe + +# FPC 3.0.0 +compiler.fpc300.exe=D:\\fpc\\3.0.0\\fpc\\bin\\x86_64-win64\\fpc.exe +compiler.fpc300.semver=3.0.0 +compiler.fpc300.name=FPC 3.0.0 + +# FPC 3.2.0 +compiler.fpc320.exe=D:\\fpc\\3.2.0\\fpc\\bin\\x86_64-win64\\fpc.exe +compiler.fpc320.semver=3.2.0 +compiler.fpc320.name=FPC 3.2.0 + +# FPC 3.2.2 +compiler.fpc322.exe=D:\\fpc\\3.2.2\\fpc\\bin\\x86_64-win64\\fpc.exe +compiler.fpc322.semver=3.2.2 +compiler.fpc322.name=FPC 3.2.2 + +# FPC 3.3.1 +compiler.fpc331.exe=D:\\fpc\\3.3.1\\fpc\\bin\\x86_64-win64\\fpc.exe +compiler.fpc331.semver=3.3.1 +compiler.fpc331.name=FPC 3.3.1 From 875d3ba5b270389af0e24d44082b4398da41806b Mon Sep 17 00:00:00 2001 From: Paul McGee Date: Sun, 23 Nov 2025 14:38:23 +0800 Subject: [PATCH 12/27] Fix FPC executable not found on Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modified pascal.ts getExecutableFilename() to add .exe extension on Windows. FPC creates .exe files on Windows but the code was looking for executables without the extension, causing "Executable not found" errors. Also added supportsExecute=true to FPC group configuration. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- etc/config/pascal.local.properties | 1 + lib/compilers/pascal.ts | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/etc/config/pascal.local.properties b/etc/config/pascal.local.properties index 18934f308c4..f40c143c84d 100644 --- a/etc/config/pascal.local.properties +++ b/etc/config/pascal.local.properties @@ -50,6 +50,7 @@ group.fpc.isSemVer=true group.fpc.baseName=FPC group.fpc.versionFlag=-iV group.fpc.supportsBinary=true +group.fpc.supportsExecute=true group.fpc.objdumper=C:\\Program Files (x86)\\Embarcadero\\Dev-Cpp\\TDM-GCC-64\\bin\\objdump.exe # FPC 3.0.0 diff --git a/lib/compilers/pascal.ts b/lib/compilers/pascal.ts index 0d66a261ce0..86add418311 100644 --- a/lib/compilers/pascal.ts +++ b/lib/compilers/pascal.ts @@ -133,11 +133,19 @@ export class FPCCompiler extends BaseCompiler { override getExecutableFilename(dirPath: string, outputFilebase: string, key?: CacheKey | CompilationCacheKey) { const source = (key && (key as CacheKey).source) || ''; + let progName; if (key && pascalUtils.isProgram(source)) { - return path.join(dirPath, pascalUtils.getProgName(source)); + progName = pascalUtils.getProgName(source); + } else { + progName = 'prog'; + } + + // Add .exe extension on Windows (process.platform is 'win32' for all Windows) + if (process.platform === 'win32' && !progName.endsWith('.exe')) { + progName += '.exe'; } - return path.join(dirPath, 'prog'); + return path.join(dirPath, progName); } override async objdump( From 5899d5b50cbe1f01e120cc665451da46c048dc83 Mon Sep 17 00:00:00 2001 From: Paul McGee Date: Sun, 23 Nov 2025 14:46:24 +0800 Subject: [PATCH 13/27] Update compiler version names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated Delphi and C++Builder version names: - Version 11 Alexandria is actually 11.3 - Version 13.1 codename is Florence 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- etc/config/c++.local.properties | 12 ++++++------ etc/config/pascal.local.properties | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/etc/config/c++.local.properties b/etc/config/c++.local.properties index 920b7144d27..0fddc10bb37 100644 --- a/etc/config/c++.local.properties +++ b/etc/config/c++.local.properties @@ -64,11 +64,11 @@ compiler.bcc104_64.ldPath =C:\Program Files (x86)\Embarcadero\Studio\20.0\l # C++Builder 11 Alexandria (Studio 22.0) compiler.bcc11_32.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\bin\bcc32x.exe -compiler.bcc11_32.name =C++Builder 11 x86 +compiler.bcc11_32.name =C++Builder 11.3 x86 compiler.bcc11_32.ldPath =C:\Program Files (x86)\Embarcadero\Studio\22.0\lib\win32c\release compiler.bcc11_64.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\bin\bcc64.exe -compiler.bcc11_64.name =C++Builder 11 x64 +compiler.bcc11_64.name =C++Builder 11.3 x64 compiler.bcc11_64.ldPath =C:\Program Files (x86)\Embarcadero\Studio\22.0\lib\win64\release # C++Builder 12.3 Athens (Studio 23.0) @@ -84,17 +84,17 @@ compiler.bcc123_64mod.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\b compiler.bcc123_64mod.name =C++Builder 12.3 x64 modern compiler.bcc123_64mod.ldPath =C:\Program Files (x86)\Embarcadero\Studio\23.0\lib\win64x\release|C:\Program Files (x86)\Embarcadero\Studio\23.0\x86_64-w64-mingw32\lib|C:\Program Files (x86)\Embarcadero\Studio\23.0\lib\clang\15.0.7\lib\windows -# C++Builder 13.1 (Studio 37.0) +# C++Builder 13.1 Florence (Studio 37.0) compiler.bcc131_32.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\bin\bcc32x.exe -compiler.bcc131_32.name =C++Builder 13.1 x86 +compiler.bcc131_32.name =C++Builder 13.1 Florence x86 compiler.bcc131_32.ldPath =C:\Program Files (x86)\Embarcadero\Studio\37.0\lib\win32c\release compiler.bcc131_64.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\bin\bcc64.exe -compiler.bcc131_64.name =C++Builder 13.1 x64 +compiler.bcc131_64.name =C++Builder 13.1 Florence x64 compiler.bcc131_64.ldPath =C:\Program Files (x86)\Embarcadero\Studio\37.0\lib\win64\release compiler.bcc131_64mod.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\bin64\bcc64x.exe -compiler.bcc131_64mod.name =C++Builder 13.1 x64 modern +compiler.bcc131_64mod.name =C++Builder 13.1 Florence x64 modern compiler.bcc131_64mod.ldPath =C:\Program Files (x86)\Embarcadero\Studio\37.0\lib\win64x\release|C:\Program Files (x86)\Embarcadero\Studio\37.0\x86_64-w64-mingw32\lib|C:\Program Files (x86)\Embarcadero\Studio\37.0\lib\clang\15.0.7\lib\windows #compiler.mscl32.exe =C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\Llvm\bin\clang++.exe diff --git a/etc/config/pascal.local.properties b/etc/config/pascal.local.properties index f40c143c84d..5870c02a854 100644 --- a/etc/config/pascal.local.properties +++ b/etc/config/pascal.local.properties @@ -26,10 +26,10 @@ compiler.delphi27_64.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\20.0\\Bin compiler.delphi27_64.name=x64 Delphi 10.4.2 Sydney compiler.delphi28.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\22.0\\Bin\\DCC32.EXE -compiler.delphi28.name=x86 Delphi 11 Alexandria +compiler.delphi28.name=x86 Delphi 11.3 Alexandria compiler.delphi28_64.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\22.0\\Bin\\DCC64.EXE -compiler.delphi28_64.name=x64 Delphi 11 Alexandria +compiler.delphi28_64.name=x64 Delphi 11.3 Alexandria compiler.delphi29.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\23.0\\Bin\\DCC32.EXE compiler.delphi29.name=x86 Delphi 12.3 Athens @@ -38,10 +38,10 @@ compiler.delphi29_64.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\23.0\\Bin compiler.delphi29_64.name=x64 Delphi 12.3 Athens compiler.delphi31.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\37.0\\Bin\\DCC32.EXE -compiler.delphi31.name=x86 Delphi 13.1 +compiler.delphi31.name=x86 Delphi 13.1 Florence compiler.delphi31_64.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\37.0\\Bin\\DCC64.EXE -compiler.delphi31_64.name=x64 Delphi 13.1 +compiler.delphi31_64.name=x64 Delphi 13.1 Florence # FPC (Free Pascal Compiler) group group.fpc.compilers=fpc300:fpc320:fpc322:fpc331 From 30ecaa8c5098ff3ee579e6ec2b2fdfb8970d0d36 Mon Sep 17 00:00:00 2001 From: Paul McGee Date: Sun, 23 Nov 2025 16:54:01 +0800 Subject: [PATCH 14/27] Simplify C++Builder modern group name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removed version numbers from group name. Changed from "C++Builder x64 modern (12.3, 13.1)" to "C++Builder x64 modern" for cleaner dropdown display. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- etc/config/c++.local.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/config/c++.local.properties b/etc/config/c++.local.properties index 0fddc10bb37..768116c87e3 100644 --- a/etc/config/c++.local.properties +++ b/etc/config/c++.local.properties @@ -46,7 +46,7 @@ group.embclang64.groupName =C++Builder x64 group.embclang64.options =-Wno-user-defined-literals -Wno-comment -I'C:\Program Files (x86)\Embarcadero\Studio\20.0\include\dinkumware64' -I'C:\Program Files (x86)\Embarcadero\Studio\20.0\include\windows\crtl' group.embclang64mod.compilers=bcc123_64mod:bcc131_64mod -group.embclang64mod.groupName=C++Builder x64 modern (12.3, 13.1) +group.embclang64mod.groupName=C++Builder x64 modern group.embclang64mod.options =-Wno-user-defined-literals -Wno-comment -isystem "C:\Program Files (x86)\Embarcadero\Studio\23.0\include" -isystem "C:\Program Files (x86)\Embarcadero\Studio\23.0\include\x86_64-w64-mingw32\c++\v1" -isystem "C:\Program Files (x86)\Embarcadero\Studio\23.0\lib\clang\15.0.7\include" -isystem "C:\Program Files (x86)\Embarcadero\Studio\23.0\include\x86_64-w64-mingw32" # MS Clang compilers - not installed on this system From 15f6d58a51f213907366d7946d67bbef23ac9032 Mon Sep 17 00:00:00 2001 From: Paul McGee Date: Tue, 25 Nov 2025 04:29:41 +0800 Subject: [PATCH 15/27] Add source-to-assembly highlighting for Delphi compilers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implemented complete source line mapping for Delphi Windows compilers by extracting debug information from map files and converting it to DWARF-style .loc directives that the assembly parser can process. Key changes: - Extract program name from source code and use it for all output files (test.dpr -> test.exe, test.map) to match FPC behavior - Add compiler flags for debug info generation (-$D+, -$L+, -$O-, -$W+, -$C-) - Parse map file line numbers and convert to .file/.loc directives - Fix segment unit names using module-to-filename mapping from map file - Enable processBinaryAsm to handle .file and .loc directives - Treat simple filenames (without path separators) as main source files - Skip line=0 markers to preserve continuous source highlighting blocks This enables the same multi-line color-coded source highlighting that works for FPC, Rust, Python, and C++ compilers. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- lib/compilers/pascal-win.ts | 107 +++++++++++++++++++++++++---- lib/mapfiles/map-file-delphi.ts | 55 +++++++++++++-- lib/parsers/asm-parser.ts | 25 ++++++- lib/parsers/source-line-handler.ts | 4 +- lib/pe32-support.ts | 10 +++ 5 files changed, 178 insertions(+), 23 deletions(-) diff --git a/lib/compilers/pascal-win.ts b/lib/compilers/pascal-win.ts index 46768f41373..76e62a4e378 100644 --- a/lib/compilers/pascal-win.ts +++ b/lib/compilers/pascal-win.ts @@ -48,6 +48,7 @@ export class PascalWinCompiler extends BaseCompiler { mapFilename: string | null; dprFilename: string; + projectBaseName: string; constructor(info: PreliminaryCompilerInfo, env: CompilationEnvironment) { super(info, env); @@ -56,6 +57,7 @@ export class PascalWinCompiler extends BaseCompiler { this.mapFilename = null; this.compileFilename = 'output.pas'; this.dprFilename = 'prog.dpr'; + this.projectBaseName = 'prog'; } override getSharedLibraryPathsAsArguments() { @@ -77,11 +79,11 @@ export class PascalWinCompiler extends BaseCompiler { } override getExecutableFilename(dirPath: string) { - return path.join(dirPath, 'prog.exe'); + return path.join(dirPath, this.projectBaseName + '.exe'); } override getOutputFilename(dirPath: string) { - return path.join(dirPath, 'prog.exe'); + return path.join(dirPath, this.projectBaseName + '.exe'); } override filename(fn: string) { @@ -100,7 +102,7 @@ export class PascalWinCompiler extends BaseCompiler { outputFilename = this.getOutputFilename(path.dirname(outputFilename)); } - let args = [...this.compiler.objdumperArgs, '-d', outputFilename]; + let args = [...this.compiler.objdumperArgs, '-d', '-l', outputFilename]; if (intelAsm) args = args.concat(['-M', 'intel']); return this.exec(this.compiler.objdumper, args, {maxOutput: 1024 * 1024 * 1024}).then(objResult => { if (objResult.code === 0) { @@ -127,7 +129,9 @@ export class PascalWinCompiler extends BaseCompiler { override async writeAllFiles(dirPath: string, source: string, files: FiledataPair[]) { let inputFilename: string; if (pascalUtils.isProgram(source)) { - inputFilename = path.join(dirPath, this.dprFilename); + // Use the program name from the source, like FPC does + const progName = pascalUtils.getProgName(source); + inputFilename = path.join(dirPath, progName + '.dpr'); } else { const unitName = pascalUtils.getUnitname(source); if (unitName) { @@ -158,24 +162,34 @@ export class PascalWinCompiler extends BaseCompiler { execOptions = this.getDefaultExecOptions(); } - const alreadyHasDPR = path.basename(inputFilename) === this.dprFilename; - const tempPath = path.dirname(inputFilename); - const projectFile = path.join(tempPath, this.dprFilename); - - this.mapFilename = path.join(tempPath, 'prog.map'); + const inputBasename = path.basename(inputFilename); + const isDprFile = inputBasename.toLowerCase().endsWith('.dpr'); - inputFilename = inputFilename.replaceAll('/', '\\'); + let projectFile: string; + let projectBaseName: string; - if (!alreadyHasDPR) { - const unitFilepath = path.basename(inputFilename); - const unitName = unitFilepath.replace(/.pas$/i, ''); + if (isDprFile) { + // Input is already a .dpr program file, compile it directly (like FPC does) + projectFile = inputFilename; + projectBaseName = inputBasename.replace(/\.dpr$/i, ''); + } else { + // Input is a .pas unit file, create a dummy prog.dpr project that uses it + const unitFilepath = inputBasename; + const unitName = unitFilepath.replace(/\.pas$/i, ''); + projectFile = path.join(tempPath, this.dprFilename); + projectBaseName = 'prog'; await this.saveDummyProjectFile(projectFile, unitName, unitFilepath); } + this.projectBaseName = projectBaseName; + this.mapFilename = path.join(tempPath, projectBaseName + '.map'); + + inputFilename = inputFilename.replaceAll('/', '\\'); + options.pop(); - options.unshift('-CC', '-W', '-H', '-GD', '-$D+', '-V', '-B'); + options.unshift('-CC', '-W', '-H', '-GD', '-$D+', '-$L+', '-$O-', '-$W+', '-$C-', '-V', '-B'); options.push(projectFile); execOptions.customCwd = tempPath; @@ -198,7 +212,70 @@ export class PascalWinCompiler extends BaseCompiler { const reconstructor = new PELabelReconstructor(asmLines, false, mapFileReader, false); reconstructor.run('output'); - return reconstructor.asmLines; + console.log(`[Delphi] Map file: ${this.mapFilename}`); + console.log(`[Delphi] Working directory: ${path.dirname(unwrap(this.mapFilename))}`); + + // Convert source line markers from /app/filename:line format to .loc directives + const fileMap = new Map(); + let fileCounter = 1; + const result: string[] = []; + let foundSourceLines = 0; + let topLevelFileAdded = false; + + for (const line of reconstructor.asmLines) { + const sourceMatch = line.match(/^\/app\/(.+):(\d+)$/); + if (sourceMatch) { + foundSourceLines++; + const filename = sourceMatch[1]; + const lineNumber = sourceMatch[2]; + + // Skip line 0 markers - they indicate no line info available + // Let the previous source line continue instead of breaking highlighting + if (lineNumber === '0') { + continue; + } + + // Log first few matches for debugging + if (foundSourceLines <= 5) { + console.log(`[Delphi] Source marker ${foundSourceLines}: file="${filename}" line=${lineNumber}`); + } + + // Add top-level .file directive once at the very beginning (like FPC does) + if (!topLevelFileAdded) { + const topLevelFile = `\t.file "${filename}"`; + result.unshift(topLevelFile); + console.log(`[Delphi] Added top-level .file directive: ${topLevelFile}`); + topLevelFileAdded = true; + } + + // Get or assign file number for DWARF debug info + if (!fileMap.has(filename)) { + const fileNum = fileCounter++; + fileMap.set(filename, fileNum); + const fileDirective = `\t.file ${fileNum} "${filename}"`; + result.push(fileDirective); + console.log(`[Delphi] Added numbered .file directive: ${fileDirective}`); + } + + const fileNum = fileMap.get(filename)!; + const locDirective = `\t.loc ${fileNum} ${lineNumber} 0`; + result.push(locDirective); + + // Log first few .loc directives + if (foundSourceLines <= 10) { + console.log(`[Delphi] .loc directive: ${locDirective}`); + } + } else { + result.push(line); + } + } + + console.log(`[Delphi] Processed ${reconstructor.asmLines.length} lines, found ${foundSourceLines} source markers, converted to .loc directives`); + console.log(`[Delphi] First 20 lines of processed assembly:`); + for (let i = 0; i < Math.min(20, result.length); i++) { + console.log(`[Delphi] ${i}: ${result[i]}`); + } + return result; }; return []; diff --git a/lib/mapfiles/map-file-delphi.ts b/lib/mapfiles/map-file-delphi.ts index 51ef094c255..114f1c3d961 100644 --- a/lib/mapfiles/map-file-delphi.ts +++ b/lib/mapfiles/map-file-delphi.ts @@ -29,9 +29,11 @@ export class MapFileReaderDelphi extends MapFileReader { regexDelphiCodeSegment = /^\s([\da-f]*):([\da-f]*)\s*([\da-f]*)\s*c=code\s*s=.text\s*g=.*m=([\w.]*)\s.*/i; regexDelphiICodeSegment = /^\s([\da-f]*):([\da-f]*)\s*([\da-f]*)\s*c=icode\s*s=.itext\s*g=.*m=([\w.]*)\s.*/i; regexDelphiNames = /^\s([\da-f]*):([\da-f]*)\s*([\w$.<>@{}]*)$/i; - regexDelphiLineNumbersStart = /line numbers for (.*)\(.*\) segment \.text/i; - regexDelphiLineNumber = /^(\d*)\s([\da-f]*):([\da-f]*)/i; - regexDelphiLineNumbersStartIText = /line numbers for (.*)\(.*\) segment \.itext/i; + regexDelphiLineNumbersStart = /line numbers for (.*)\((.*)\) segment \.text/i; + regexDelphiLineNumber = /^\s*(\d+)\s+([\da-f]+):([\da-f]+)/i; + regexDelphiLineNumbersStartIText = /line numbers for (.*)\((.*)\) segment \.itext/i; + currentLineNumbersFilename: string | null = null; + moduleToFilename: Map = new Map(); /** * Tries to match the given line to code segment information @@ -90,8 +92,45 @@ export class MapFileReaderDelphi extends MapFileReader { } } + override run() { + // First pass: read the map file + super.run(); + + // Second pass: fix unitName for segments using the module-to-filename mapping + this.fixSegmentUnitNames(); + } + + fixSegmentUnitNames() { + for (const segment of this.segments) { + // Extract module name from current unitName (remove .pas or .dpr extension) + const moduleName = segment.unitName?.replace(/\.(pas|dpr)$/i, '') || ''; + if (this.moduleToFilename.has(moduleName)) { + const correctFilename = this.moduleToFilename.get(moduleName)!; + console.log(`[MapFileDelphi] Fixing segment unitName: "${segment.unitName}" -> "${correctFilename}"`); + segment.unitName = correctFilename; + } + } + for (const segment of this.isegments) { + const moduleName = segment.unitName?.replace(/\.(pas|dpr)$/i, '') || ''; + if (this.moduleToFilename.has(moduleName)) { + const correctFilename = this.moduleToFilename.get(moduleName)!; + console.log(`[MapFileDelphi] Fixing isegment unitName: "${segment.unitName}" -> "${correctFilename}"`); + segment.unitName = correctFilename; + } + } + } + override isStartOfLineNumbers(line: string) { const matches = line.match(this.regexDelphiLineNumbersStart); + if (matches) { + // Extract module name and actual filename from the path in parentheses + const moduleName = matches[1]; + const fullPath = matches[2]; + const filename = fullPath.split('\\').pop() || fullPath.split('/').pop() || fullPath; + this.currentLineNumbersFilename = filename; + this.moduleToFilename.set(moduleName, filename); + console.log(`[MapFileDelphi] Found line numbers section for module "${moduleName}" -> file: ${filename}`); + } return !!matches; } @@ -105,10 +144,16 @@ export class MapFileReaderDelphi extends MapFileReader { for (const reference of references) { const matches = reference.match(this.regexDelphiLineNumber); if (matches) { - this.lineNumbers.push({ + const lineNumObj = { ...this.addressToObject(matches[2], matches[3]), lineNumber: Number.parseInt(matches[1], 10), - }); + }; + this.lineNumbers.push(lineNumObj); + + // Debug: log first few line numbers + if (this.lineNumbers.length <= 5) { + console.log(`[MapFileDelphi] Line ${lineNumObj.lineNumber} at address ${lineNumObj.addressInt.toString(16)} (segment ${lineNumObj.segment}:${matches[3]})`); + } hasLineNumbers = true; } diff --git a/lib/parsers/asm-parser.ts b/lib/parsers/asm-parser.ts index 5ab3c2f4017..c05877df698 100644 --- a/lib/parsers/asm-parser.ts +++ b/lib/parsers/asm-parser.ts @@ -625,6 +625,13 @@ export class AsmParser extends AsmRegex implements IAsmParser { if (filters.preProcessBinaryAsmLines) asmLines = filters.preProcessBinaryAsmLines(asmLines); + // Parse .file directives to build file number -> filename mapping + const files = this.parseFiles(asmLines); + const sourceContext: SourceHandlerContext = { + files: files, + dontMaskFilenames: dontMaskFilenames || false, + }; + for (const line of asmLines) { const labelsInLine: AsmResultLabel[] = []; @@ -653,6 +660,16 @@ export class AsmParser extends AsmRegex implements IAsmParser { continue; } + // Handle .file and .loc directives (DWARF debug info) + const sourceResult = this.sourceLineHandler.processSourceLine(line, sourceContext); + if (sourceResult.source !== undefined) { + source = sourceResult.source; + if (source && asm.length < 5) { + console.log(`[AsmParser] Parsed source directive: file="${source.file}" line=${source.line} mainsource=${source.mainsource}`); + } + continue; // Don't display the directive itself + } + match = line.match(this.labelRe); if (match) { func = match[2]; @@ -706,13 +723,17 @@ export class AsmParser extends AsmRegex implements IAsmParser { }, }); } - asm.push({ + const asmLine = { opcodes: opcodes, address: address, text: disassembly, source: source, labels: labelsInLine, - }); + }; + if (asm.length < 10 && source) { + console.log(`[AsmParser] Line ${asm.length}: "${disassembly.trim()}" -> source file="${source.file}" line=${source.line}`); + } + asm.push(asmLine); } match = line.match(this.relocationRe); diff --git a/lib/parsers/source-line-handler.ts b/lib/parsers/source-line-handler.ts index bb82b6e9a2c..15e8799f88c 100644 --- a/lib/parsers/source-line-handler.ts +++ b/lib/parsers/source-line-handler.ts @@ -56,7 +56,9 @@ export class SourceLineHandler { } private createSource(file: string, line: number, context: SourceHandlerContext, column?: number): AsmResultSource { - const isMainSource = this.stdInLooking.test(file); + // Check if this is main source: either matches stdInLooking pattern, or is a simple filename without path separators + const isSimpleFilename = !file.includes('/') && !file.includes('\\'); + const isMainSource = this.stdInLooking.test(file) || isSimpleFilename; const source: AsmResultSource = context.dontMaskFilenames ? { file, diff --git a/lib/pe32-support.ts b/lib/pe32-support.ts index ecaf2e23b9d..492ab27d26e 100644 --- a/lib/pe32-support.ts +++ b/lib/pe32-support.ts @@ -275,7 +275,17 @@ export class PELabelReconstructor { } } + // Debug: log first 10 address lookups + if (lineIdx < 10) { + console.log(`[PELabel] Looking up address ${address.toString(16)} (dec: ${address}), addressStr=${addressStr}`); + } + const lineInfo = this.mapFileReader.getLineInfoByAddress(undefined, address); + + if (lineIdx < 10) { + console.log(`[PELabel] Result: lineInfo=${lineInfo ? lineInfo.lineNumber : 'null'}, currentSegment=${currentSegment ? currentSegment.unitName : 'null'}, segmentChanged=${segmentChanged}`); + } + if (lineInfo && currentSegment && currentSegment.unitName) { this.asmLines.splice(lineIdx, 0, '/app/' + currentSegment.unitName + ':' + lineInfo.lineNumber); lineIdx++; From 8e029e3c0c1fdcd53917f46c100166d6cf6a47c1 Mon Sep 17 00:00:00 2001 From: Paul McGee Date: Tue, 25 Nov 2025 04:37:25 +0800 Subject: [PATCH 16/27] Remove debug logging from Delphi source highlighting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clean up all console.log statements used during development and remove unused variables. The feature is fully functional without the debug output. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- lib/compilers/pascal-win.ts | 31 +++---------------------------- lib/mapfiles/map-file-delphi.ts | 20 ++++---------------- lib/parsers/asm-parser.ts | 11 ++--------- lib/pe32-support.ts | 10 ---------- 4 files changed, 9 insertions(+), 63 deletions(-) diff --git a/lib/compilers/pascal-win.ts b/lib/compilers/pascal-win.ts index 76e62a4e378..0a5a4213e7d 100644 --- a/lib/compilers/pascal-win.ts +++ b/lib/compilers/pascal-win.ts @@ -212,20 +212,15 @@ export class PascalWinCompiler extends BaseCompiler { const reconstructor = new PELabelReconstructor(asmLines, false, mapFileReader, false); reconstructor.run('output'); - console.log(`[Delphi] Map file: ${this.mapFilename}`); - console.log(`[Delphi] Working directory: ${path.dirname(unwrap(this.mapFilename))}`); - // Convert source line markers from /app/filename:line format to .loc directives const fileMap = new Map(); let fileCounter = 1; const result: string[] = []; - let foundSourceLines = 0; let topLevelFileAdded = false; for (const line of reconstructor.asmLines) { const sourceMatch = line.match(/^\/app\/(.+):(\d+)$/); if (sourceMatch) { - foundSourceLines++; const filename = sourceMatch[1]; const lineNumber = sourceMatch[2]; @@ -235,16 +230,9 @@ export class PascalWinCompiler extends BaseCompiler { continue; } - // Log first few matches for debugging - if (foundSourceLines <= 5) { - console.log(`[Delphi] Source marker ${foundSourceLines}: file="${filename}" line=${lineNumber}`); - } - // Add top-level .file directive once at the very beginning (like FPC does) if (!topLevelFileAdded) { - const topLevelFile = `\t.file "${filename}"`; - result.unshift(topLevelFile); - console.log(`[Delphi] Added top-level .file directive: ${topLevelFile}`); + result.unshift(`\t.file "${filename}"`); topLevelFileAdded = true; } @@ -252,29 +240,16 @@ export class PascalWinCompiler extends BaseCompiler { if (!fileMap.has(filename)) { const fileNum = fileCounter++; fileMap.set(filename, fileNum); - const fileDirective = `\t.file ${fileNum} "${filename}"`; - result.push(fileDirective); - console.log(`[Delphi] Added numbered .file directive: ${fileDirective}`); + result.push(`\t.file ${fileNum} "${filename}"`); } const fileNum = fileMap.get(filename)!; - const locDirective = `\t.loc ${fileNum} ${lineNumber} 0`; - result.push(locDirective); - - // Log first few .loc directives - if (foundSourceLines <= 10) { - console.log(`[Delphi] .loc directive: ${locDirective}`); - } + result.push(`\t.loc ${fileNum} ${lineNumber} 0`); } else { result.push(line); } } - console.log(`[Delphi] Processed ${reconstructor.asmLines.length} lines, found ${foundSourceLines} source markers, converted to .loc directives`); - console.log(`[Delphi] First 20 lines of processed assembly:`); - for (let i = 0; i < Math.min(20, result.length); i++) { - console.log(`[Delphi] ${i}: ${result[i]}`); - } return result; }; diff --git a/lib/mapfiles/map-file-delphi.ts b/lib/mapfiles/map-file-delphi.ts index 114f1c3d961..a79cdc16a7e 100644 --- a/lib/mapfiles/map-file-delphi.ts +++ b/lib/mapfiles/map-file-delphi.ts @@ -105,17 +105,13 @@ export class MapFileReaderDelphi extends MapFileReader { // Extract module name from current unitName (remove .pas or .dpr extension) const moduleName = segment.unitName?.replace(/\.(pas|dpr)$/i, '') || ''; if (this.moduleToFilename.has(moduleName)) { - const correctFilename = this.moduleToFilename.get(moduleName)!; - console.log(`[MapFileDelphi] Fixing segment unitName: "${segment.unitName}" -> "${correctFilename}"`); - segment.unitName = correctFilename; + segment.unitName = this.moduleToFilename.get(moduleName)!; } } for (const segment of this.isegments) { const moduleName = segment.unitName?.replace(/\.(pas|dpr)$/i, '') || ''; if (this.moduleToFilename.has(moduleName)) { - const correctFilename = this.moduleToFilename.get(moduleName)!; - console.log(`[MapFileDelphi] Fixing isegment unitName: "${segment.unitName}" -> "${correctFilename}"`); - segment.unitName = correctFilename; + segment.unitName = this.moduleToFilename.get(moduleName)!; } } } @@ -129,7 +125,6 @@ export class MapFileReaderDelphi extends MapFileReader { const filename = fullPath.split('\\').pop() || fullPath.split('/').pop() || fullPath; this.currentLineNumbersFilename = filename; this.moduleToFilename.set(moduleName, filename); - console.log(`[MapFileDelphi] Found line numbers section for module "${moduleName}" -> file: ${filename}`); } return !!matches; } @@ -144,17 +139,10 @@ export class MapFileReaderDelphi extends MapFileReader { for (const reference of references) { const matches = reference.match(this.regexDelphiLineNumber); if (matches) { - const lineNumObj = { + this.lineNumbers.push({ ...this.addressToObject(matches[2], matches[3]), lineNumber: Number.parseInt(matches[1], 10), - }; - this.lineNumbers.push(lineNumObj); - - // Debug: log first few line numbers - if (this.lineNumbers.length <= 5) { - console.log(`[MapFileDelphi] Line ${lineNumObj.lineNumber} at address ${lineNumObj.addressInt.toString(16)} (segment ${lineNumObj.segment}:${matches[3]})`); - } - + }); hasLineNumbers = true; } } diff --git a/lib/parsers/asm-parser.ts b/lib/parsers/asm-parser.ts index c05877df698..b8c21905c5c 100644 --- a/lib/parsers/asm-parser.ts +++ b/lib/parsers/asm-parser.ts @@ -664,9 +664,6 @@ export class AsmParser extends AsmRegex implements IAsmParser { const sourceResult = this.sourceLineHandler.processSourceLine(line, sourceContext); if (sourceResult.source !== undefined) { source = sourceResult.source; - if (source && asm.length < 5) { - console.log(`[AsmParser] Parsed source directive: file="${source.file}" line=${source.line} mainsource=${source.mainsource}`); - } continue; // Don't display the directive itself } @@ -723,17 +720,13 @@ export class AsmParser extends AsmRegex implements IAsmParser { }, }); } - const asmLine = { + asm.push({ opcodes: opcodes, address: address, text: disassembly, source: source, labels: labelsInLine, - }; - if (asm.length < 10 && source) { - console.log(`[AsmParser] Line ${asm.length}: "${disassembly.trim()}" -> source file="${source.file}" line=${source.line}`); - } - asm.push(asmLine); + }); } match = line.match(this.relocationRe); diff --git a/lib/pe32-support.ts b/lib/pe32-support.ts index 492ab27d26e..ecaf2e23b9d 100644 --- a/lib/pe32-support.ts +++ b/lib/pe32-support.ts @@ -275,17 +275,7 @@ export class PELabelReconstructor { } } - // Debug: log first 10 address lookups - if (lineIdx < 10) { - console.log(`[PELabel] Looking up address ${address.toString(16)} (dec: ${address}), addressStr=${addressStr}`); - } - const lineInfo = this.mapFileReader.getLineInfoByAddress(undefined, address); - - if (lineIdx < 10) { - console.log(`[PELabel] Result: lineInfo=${lineInfo ? lineInfo.lineNumber : 'null'}, currentSegment=${currentSegment ? currentSegment.unitName : 'null'}, segmentChanged=${segmentChanged}`); - } - if (lineInfo && currentSegment && currentSegment.unitName) { this.asmLines.splice(lineIdx, 0, '/app/' + currentSegment.unitName + ':' + lineInfo.lineNumber); lineIdx++; From 9efe58e571cf74599f474c74910e82b8d382af97 Mon Sep 17 00:00:00 2001 From: Paul McGee Date: Tue, 25 Nov 2025 21:55:30 +0800 Subject: [PATCH 17/27] Add source-to-assembly highlighting for Delphi compilers Implements highlighting for Pascal program main code blocks. Supports both x86 and x64 Delphi compilers. Key changes: - Read Delphi map files to extract line number information - Convert /app/filename:line markers to .loc directives - Handle both .text (x64) and .itext (x86) code segments - Filter out system units and assembly before first user code Known limitations: - Delphi functions lack line number info in map files - Program/unit scenario highlighting not working Debug logging retained for troubleshooting. --- etc/config/pascal.local.properties | 1 + lib/compilers/pascal-win.ts | 26 ++++++++++++- lib/compilers/win32.ts | 4 +- lib/compilers/wine-vc.ts | 4 +- lib/mapfiles/map-file-delphi.ts | 41 ++++++++++++++++++-- lib/parsers/asm-parser.ts | 3 ++ lib/pe32-support.ts | 60 ++++++++++++++++++++++++++++-- 7 files changed, 126 insertions(+), 13 deletions(-) diff --git a/etc/config/pascal.local.properties b/etc/config/pascal.local.properties index 5870c02a854..b6a2a0521cf 100644 --- a/etc/config/pascal.local.properties +++ b/etc/config/pascal.local.properties @@ -3,6 +3,7 @@ compilers=&delphi:&delphi64:&fpc maxLinesOfAsm=1000 rpathFlag=-O defaultCompiler=delphi31_64 +delayCleanupTemp=true # Delphi 32-bit group group.delphi.compilers=delphi27:delphi28:delphi29:delphi31 diff --git a/lib/compilers/pascal-win.ts b/lib/compilers/pascal-win.ts index 0a5a4213e7d..283e7c2b8e5 100644 --- a/lib/compilers/pascal-win.ts +++ b/lib/compilers/pascal-win.ts @@ -36,7 +36,7 @@ import {unwrap} from '../assert.js'; import {BaseCompiler} from '../base-compiler.js'; import {CompilationEnvironment} from '../compilation-env.js'; import {MapFileReaderDelphi} from '../mapfiles/map-file-delphi.js'; -import {PELabelReconstructor} from '../pe32-support.js'; +import {PELabelReconstructor, PELabelReconstructorOptions} from '../pe32-support.js'; import * as utils from '../utils.js'; import * as pascalUtils from './pascal-utils.js'; @@ -107,6 +107,16 @@ export class PascalWinCompiler extends BaseCompiler { return this.exec(this.compiler.objdumper, args, {maxOutput: 1024 * 1024 * 1024}).then(objResult => { if (objResult.code === 0) { result.asm = objResult.stdout; + const lines = objResult.stdout.split('\n'); + console.log(`[Delphi] Objdump output: ${lines.length} lines`); + console.log(`[Delphi] First 5 lines with addresses:`); + let addressLineCount = 0; + for (let i = 0; i < Math.min(50, lines.length); i++) { + if (lines[i].match(/^\s*[0-9a-f]+:/)) { + console.log(`[Delphi] Line ${i}: ${lines[i]}`); + if (++addressLineCount >= 5) break; + } + } } else { result.asm = ''; } @@ -208,8 +218,13 @@ export class PascalWinCompiler extends BaseCompiler { filters.binary = true; filters.dontMaskFilenames = true; filters.preProcessBinaryAsmLines = (asmLines: string[]) => { + console.log(`[Delphi] Map filename: ${this.mapFilename}`); const mapFileReader = new MapFileReaderDelphi(unwrap(this.mapFilename)); - const reconstructor = new PELabelReconstructor(asmLines, false, mapFileReader, false); + const reconstructor = new PELabelReconstructor( + asmLines, + mapFileReader, + new Set([PELabelReconstructorOptions.DeleteBeforeFirstSegment]), + ); reconstructor.run('output'); // Convert source line markers from /app/filename:line format to .loc directives @@ -218,6 +233,7 @@ export class PascalWinCompiler extends BaseCompiler { const result: string[] = []; let topLevelFileAdded = false; + let sourceMarkerCount = 0; for (const line of reconstructor.asmLines) { const sourceMatch = line.match(/^\/app\/(.+):(\d+)$/); if (sourceMatch) { @@ -230,6 +246,11 @@ export class PascalWinCompiler extends BaseCompiler { continue; } + sourceMarkerCount++; + if (sourceMarkerCount <= 3) { + console.log(`[Delphi] Source marker ${sourceMarkerCount}: file="${filename}" line=${lineNumber}`); + } + // Add top-level .file directive once at the very beginning (like FPC does) if (!topLevelFileAdded) { result.unshift(`\t.file "${filename}"`); @@ -250,6 +271,7 @@ export class PascalWinCompiler extends BaseCompiler { } } + console.log(`[Delphi] Total source markers found: ${sourceMarkerCount}`); return result; }; diff --git a/lib/compilers/win32.ts b/lib/compilers/win32.ts index fed83ad15a2..b0d9a781ca4 100644 --- a/lib/compilers/win32.ts +++ b/lib/compilers/win32.ts @@ -40,7 +40,7 @@ import {copyNeededDlls} from '../binaries/win-utils.js'; import {CompilationEnvironment} from '../compilation-env.js'; import {MapFileReaderVS} from '../mapfiles/map-file-vs.js'; import {VcAsmParser} from '../parsers/asm-parser-vc.js'; -import {PELabelReconstructor} from '../pe32-support.js'; +import {PELabelReconstructor, PELabelReconstructorOptions} from '../pe32-support.js'; export class Win32Compiler extends BaseCompiler { static get key() { @@ -252,7 +252,7 @@ export class Win32Compiler extends BaseCompiler { const mapFileReader = new MapFileReaderVS(mapFilename); filters.preProcessBinaryAsmLines = asmLines => { - const reconstructor = new PELabelReconstructor(asmLines, false, mapFileReader); + const reconstructor = new PELabelReconstructor(asmLines, mapFileReader); reconstructor.run('output.s.obj'); return reconstructor.asmLines; diff --git a/lib/compilers/wine-vc.ts b/lib/compilers/wine-vc.ts index 10b88f0685e..b3ce298ae67 100644 --- a/lib/compilers/wine-vc.ts +++ b/lib/compilers/wine-vc.ts @@ -31,7 +31,7 @@ import {BaseCompiler} from '../base-compiler.js'; import {CompilationEnvironment} from '../compilation-env.js'; import {MapFileReaderVS} from '../mapfiles/map-file-vs.js'; import {VcAsmParser} from '../parsers/asm-parser-vc.js'; -import {PELabelReconstructor} from '../pe32-support.js'; +import {PELabelReconstructor, PELabelReconstructorOptions} from '../pe32-support.js'; import {VCParser} from './argument-parsers.js'; @@ -90,7 +90,7 @@ export class WineVcCompiler extends BaseCompiler { const mapFileReader = new MapFileReaderVS(mapFilename); filters.preProcessBinaryAsmLines = (asmLines: string[]) => { - const reconstructor = new PELabelReconstructor(asmLines, false, mapFileReader); + const reconstructor = new PELabelReconstructor(asmLines, mapFileReader); reconstructor.run('output.s.obj'); return reconstructor.asmLines; diff --git a/lib/mapfiles/map-file-delphi.ts b/lib/mapfiles/map-file-delphi.ts index a79cdc16a7e..342e0fcf730 100644 --- a/lib/mapfiles/map-file-delphi.ts +++ b/lib/mapfiles/map-file-delphi.ts @@ -93,9 +93,13 @@ export class MapFileReaderDelphi extends MapFileReader { } override run() { + console.log(`[MapFileDelphi] Starting map file read: ${this.mapFilename}`); + // First pass: read the map file super.run(); + console.log(`[MapFileDelphi] Map file read complete. Line numbers found: ${this.lineNumbers.length}`); + // Second pass: fix unitName for segments using the module-to-filename mapping this.fixSegmentUnitNames(); } @@ -116,8 +120,32 @@ export class MapFileReaderDelphi extends MapFileReader { } } + override getSegmentInfoByStartingAddress(segment: string | undefined, address: number) { + // Check regular segments first + let result = super.getSegmentInfoByStartingAddress(segment, address); + if (result) return result; + + // Also check isegments (for x86 .itext segments) + for (let idx = 0; idx < this.isegments.length; idx++) { + const info = this.isegments[idx]; + if (!segment && info.addressInt === address) { + return info; + } + if (info.segment === segment && info.addressWithoutOffset === address) { + return info; + } + } + + return undefined; + } + override isStartOfLineNumbers(line: string) { - const matches = line.match(this.regexDelphiLineNumbersStart); + // Check both .text and .itext segments + let matches = line.match(this.regexDelphiLineNumbersStart); + if (!matches) { + matches = line.match(this.regexDelphiLineNumbersStartIText); + } + if (matches) { // Extract module name and actual filename from the path in parentheses const moduleName = matches[1]; @@ -125,6 +153,7 @@ export class MapFileReaderDelphi extends MapFileReader { const filename = fullPath.split('\\').pop() || fullPath.split('/').pop() || fullPath; this.currentLineNumbersFilename = filename; this.moduleToFilename.set(moduleName, filename); + console.log(`[MapFileDelphi] Found line numbers for module "${moduleName}" -> file: ${filename}`); } return !!matches; } @@ -139,10 +168,16 @@ export class MapFileReaderDelphi extends MapFileReader { for (const reference of references) { const matches = reference.match(this.regexDelphiLineNumber); if (matches) { - this.lineNumbers.push({ + const lineNumObj = { ...this.addressToObject(matches[2], matches[3]), lineNumber: Number.parseInt(matches[1], 10), - }); + }; + this.lineNumbers.push(lineNumObj); + + if (this.lineNumbers.length <= 3) { + console.log(`[MapFileDelphi] Line ${lineNumObj.lineNumber} at address ${lineNumObj.addressInt.toString(16)} (segment ${lineNumObj.segment}:${matches[3]})`); + } + hasLineNumbers = true; } } diff --git a/lib/parsers/asm-parser.ts b/lib/parsers/asm-parser.ts index b8c21905c5c..7f614844a46 100644 --- a/lib/parsers/asm-parser.ts +++ b/lib/parsers/asm-parser.ts @@ -664,6 +664,9 @@ export class AsmParser extends AsmRegex implements IAsmParser { const sourceResult = this.sourceLineHandler.processSourceLine(line, sourceContext); if (sourceResult.source !== undefined) { source = sourceResult.source; + if (source && asm.length < 3) { + console.log(`[AsmParser] Parsed directive: file="${source.file}" line=${source.line} mainsource=${source.mainsource}`); + } continue; // Don't display the directive itself } diff --git a/lib/pe32-support.ts b/lib/pe32-support.ts index ecaf2e23b9d..b7d2afe6bb5 100644 --- a/lib/pe32-support.ts +++ b/lib/pe32-support.ts @@ -24,6 +24,15 @@ import {MapFileReader, Segment} from './mapfiles/map-file.js'; +export enum PELabelReconstructorOptions { + /** Reconstruct segment information from the map file */ + NeedsReconstruction, + /** Don't label addresses that aren't in the map file */ + DontLabelUnmappedAddresses, + /** Delete all assembly before the first user code segment */ + DeleteBeforeFirstSegment, +} + export class PELabelReconstructor { public readonly asmLines: string[]; private readonly addressesToLabel: string[]; @@ -35,15 +44,16 @@ export class PELabelReconstructor { private readonly callRegex: RegExp; private readonly int3Regex: RegExp; + private readonly deleteBeforeFirstSegment: boolean; + constructor( asmLines: string[], - dontLabelUnmappedAddresses: boolean, mapFileReader: MapFileReader, - needsReconstruction = true, + options: Set = new Set(), ) { this.asmLines = asmLines; this.addressesToLabel = []; - this.dontLabelUnmappedAddresses = dontLabelUnmappedAddresses; + this.dontLabelUnmappedAddresses = options.has(PELabelReconstructorOptions.DontLabelUnmappedAddresses); this.addressRegex = /^\s*([\da-f]*):/i; this.jumpRegex = /(\sj[a-z]*)(\s*)0x([\da-f]*)/i; @@ -51,7 +61,8 @@ export class PELabelReconstructor { this.int3Regex = /\tcc\s*\tint3\s*$/i; this.mapFileReader = mapFileReader; - this.needsReconstruction = needsReconstruction; + this.needsReconstruction = options.has(PELabelReconstructorOptions.NeedsReconstruction); + this.deleteBeforeFirstSegment = options.has(PELabelReconstructorOptions.DeleteBeforeFirstSegment); } /** @@ -62,6 +73,9 @@ export class PELabelReconstructor { this.mapFileReader.run(); //this.deleteEverythingBut(unitName); + if (this.deleteBeforeFirstSegment) { + this.deleteBeforeUserCode(); + } this.deleteSystemUnits(); this.shortenInt3s(); @@ -157,6 +171,39 @@ export class PELabelReconstructor { } } + deleteBeforeUserCode() { + // Find the first user code segment (not system units) + const systemUnits = new Set(['SysInit.pas', 'System.pas', 'SysUtils.pas', 'Classes.pas']); + let firstUserAddress: number | undefined; + + // For x86, prioritize isegments (actual code) over regular segments (may be data) + // Check isegments first + for (const info of this.mapFileReader.isegments) { + if (info.unitName && !systemUnits.has(info.unitName)) { + if (firstUserAddress === undefined || info.addressInt < firstUserAddress) { + firstUserAddress = info.addressInt; + } + } + } + + // Only check regular segments if no user isegments found + if (firstUserAddress === undefined) { + for (const info of this.mapFileReader.segments) { + if (info.unitName && !systemUnits.has(info.unitName)) { + if (firstUserAddress === undefined || info.addressInt < firstUserAddress) { + firstUserAddress = info.addressInt; + } + } + } + } + + // Delete everything before the first user code + if (firstUserAddress !== undefined) { + console.log(`[PELabel] Deleting from 0 to 0x${firstUserAddress.toString(16)}`); + this.deleteLinesBetweenAddresses(0, firstUserAddress); + } + } + deleteLinesBetweenAddresses(beginAddress: number, endAddress?: number) { let startIdx = -1; let linesRemoved = false; @@ -276,6 +323,11 @@ export class PELabelReconstructor { } const lineInfo = this.mapFileReader.getLineInfoByAddress(undefined, address); + + if (lineIdx < 3) { + console.log(`[PELabel] Address ${address.toString(16)}: lineInfo=${lineInfo ? lineInfo.lineNumber : 'null'}, segment=${currentSegment ? currentSegment.unitName : 'null'}`); + } + if (lineInfo && currentSegment && currentSegment.unitName) { this.asmLines.splice(lineIdx, 0, '/app/' + currentSegment.unitName + ':' + lineInfo.lineNumber); lineIdx++; From 3255c83dcf2d7a573565f3f70a3931a041b9548b Mon Sep 17 00:00:00 2001 From: Paul McGee Date: Thu, 27 Nov 2025 21:46:21 +0800 Subject: [PATCH 18/27] Addressing regex matches occuring in comments ## debugging --- lib/compilers/pascal-utils.ts | 14 ++++++++++++-- lib/compilers/pascal-win.ts | 5 +++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/compilers/pascal-utils.ts b/lib/compilers/pascal-utils.ts index 4ddc7c3221e..21d95951521 100644 --- a/lib/compilers/pascal-utils.ts +++ b/lib/compilers/pascal-utils.ts @@ -22,14 +22,24 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. +function stripComments(source: string): string { + // Remove // comments (single line) + let result = source.replace(/\/\/.*$/gm, ''); + // Remove { } comments (block) + result = result.replace(/\{[^}]*\}/g, ''); + // Remove (* *) comments (block) + result = result.replace(/\(\*[\s\S]*?\*\)/g, ''); + return result; +} + export function isProgram(source: string) { const re = /\s?program\s+([\w.-]*);/i; - return !!re.test(source); + return !!re.test(stripComments(source)); } export function isUnit(source: string) { const re = /\s?unit\s+([\w.-]*);/i; - return !!re.test(source); + return !!re.test(stripComments(source)); } export function getUnitname(source: string) { diff --git a/lib/compilers/pascal-win.ts b/lib/compilers/pascal-win.ts index 283e7c2b8e5..44765f41951 100644 --- a/lib/compilers/pascal-win.ts +++ b/lib/compilers/pascal-win.ts @@ -104,6 +104,8 @@ export class PascalWinCompiler extends BaseCompiler { let args = [...this.compiler.objdumperArgs, '-d', '-l', outputFilename]; if (intelAsm) args = args.concat(['-M', 'intel']); + console.log(`[Delphi] Running objdump on: ${outputFilename}`); + console.log(`[Delphi] Objdump command: ${this.compiler.objdumper} ${args.join(' ')}`); return this.exec(this.compiler.objdumper, args, {maxOutput: 1024 * 1024 * 1024}).then(objResult => { if (objResult.code === 0) { result.asm = objResult.stdout; @@ -118,6 +120,9 @@ export class PascalWinCompiler extends BaseCompiler { } } } else { + console.log(`[Delphi] Objdump failed with code ${objResult.code}`); + console.log(`[Delphi] Objdump stderr: ${objResult.stderr}`); + console.log(`[Delphi] Objdump stdout: ${objResult.stdout}`); result.asm = ''; } From f6ac5a963fa5688fb12c9124f7ab6c1768bc3447 Mon Sep 17 00:00:00 2001 From: Paul McGee Date: Fri, 28 Nov 2025 00:29:45 +0800 Subject: [PATCH 19/27] Improve Delphi source highlighting for x86 and unit compilation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes and enhancements: - Strip comments from source while preserving line numbers - Support unit-only compilation with automatic wrapper program generation - Add filename tracking to map file line numbers for multi-file filtering - Filter out wrapper program (prog.dpr) line numbers and segments in unit case - Fix x86 segment deletion to use minimum address across .text and .itext - Truncate unmapped assembly sections (finalization/init) to 5 lines max - Track wrapper program state to conditionally exclude prog.dpr segments Changes: - lib/compilers/pascal-utils.ts: Add comment stripping with line preservation - lib/compilers/pascal-win.ts: Add wrapper tracking, first-file filtering, truncation - lib/mapfiles/map-file-delphi.ts: Store filename with each line number entry - lib/pe32-support.ts: Fix deleteBeforeUserCode, add additionalExcludedUnits support All Pascal compilers (FPC/Delphi, x86/x64, program/unit) now have working source-to-assembly highlighting with appropriate filtering. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- lib/compilers/pascal-utils.ts | 29 ++++++++++--- lib/compilers/pascal-win.ts | 75 +++++++++++++++++++++++++++++++-- lib/mapfiles/map-file-delphi.ts | 1 + lib/pe32-support.ts | 27 ++++++------ 4 files changed, 110 insertions(+), 22 deletions(-) diff --git a/lib/compilers/pascal-utils.ts b/lib/compilers/pascal-utils.ts index 21d95951521..db18f7e8487 100644 --- a/lib/compilers/pascal-utils.ts +++ b/lib/compilers/pascal-utils.ts @@ -22,24 +22,41 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. -function stripComments(source: string): string { - // Remove // comments (single line) +function stripCommentsForDetection(source: string): string { + // For detection only - remove comments entirely let result = source.replace(/\/\/.*$/gm, ''); - // Remove { } comments (block) result = result.replace(/\{[^}]*\}/g, ''); - // Remove (* *) comments (block) result = result.replace(/\(\*[\s\S]*?\*\)/g, ''); return result; } +export function stripComments(source: string): string { + // Blank out comment content but preserve line numbers + // For // comments: keep the // but blank the rest of the line + let result = source.replace(/\/\/.*$/gm, '//'); + // For { } comments: keep delimiters, blank content + result = result.replace(/\{[^}]*\}/g, match => '{}'); + // For (* *) comments: keep delimiters, preserve newlines in content + result = result.replace(/\(\*[\s\S]*?\*\)/g, match => { + const lines = match.split('\n'); + if (lines.length === 1) { + return '(**)'; + } else { + // Multi-line: preserve newlines + return '(*' + '\n'.repeat(lines.length - 1) + '*)'; + } + }); + return result; +} + export function isProgram(source: string) { const re = /\s?program\s+([\w.-]*);/i; - return !!re.test(stripComments(source)); + return !!re.test(stripCommentsForDetection(source)); } export function isUnit(source: string) { const re = /\s?unit\s+([\w.-]*);/i; - return !!re.test(stripComments(source)); + return !!re.test(stripCommentsForDetection(source)); } export function getUnitname(source: string) { diff --git a/lib/compilers/pascal-win.ts b/lib/compilers/pascal-win.ts index 44765f41951..7c300f3b47a 100644 --- a/lib/compilers/pascal-win.ts +++ b/lib/compilers/pascal-win.ts @@ -49,6 +49,7 @@ export class PascalWinCompiler extends BaseCompiler { mapFilename: string | null; dprFilename: string; projectBaseName: string; + isWrapperProgram: boolean; constructor(info: PreliminaryCompilerInfo, env: CompilationEnvironment) { super(info, env); @@ -58,6 +59,7 @@ export class PascalWinCompiler extends BaseCompiler { this.compileFilename = 'output.pas'; this.dprFilename = 'prog.dpr'; this.projectBaseName = 'prog'; + this.isWrapperProgram = false; } override getSharedLibraryPathsAsArguments() { @@ -142,6 +144,9 @@ export class PascalWinCompiler extends BaseCompiler { } override async writeAllFiles(dirPath: string, source: string, files: FiledataPair[]) { + // Strip comment content to avoid highlighting commented code + const cleanedSource = pascalUtils.stripComments(source); + let inputFilename: string; if (pascalUtils.isProgram(source)) { // Use the program name from the source, like FPC does @@ -156,7 +161,7 @@ export class PascalWinCompiler extends BaseCompiler { } } - await fs.writeFile(inputFilename, source); + await fs.writeFile(inputFilename, cleanedSource); if (files && files.length > 0) { await this.writeMultipleFiles(files, dirPath); @@ -188,6 +193,7 @@ export class PascalWinCompiler extends BaseCompiler { // Input is already a .dpr program file, compile it directly (like FPC does) projectFile = inputFilename; projectBaseName = inputBasename.replace(/\.dpr$/i, ''); + this.isWrapperProgram = false; } else { // Input is a .pas unit file, create a dummy prog.dpr project that uses it const unitFilepath = inputBasename; @@ -195,6 +201,7 @@ export class PascalWinCompiler extends BaseCompiler { projectFile = path.join(tempPath, this.dprFilename); projectBaseName = 'prog'; await this.saveDummyProjectFile(projectFile, unitName, unitFilepath); + this.isWrapperProgram = true; } this.projectBaseName = projectBaseName; @@ -225,10 +232,13 @@ export class PascalWinCompiler extends BaseCompiler { filters.preProcessBinaryAsmLines = (asmLines: string[]) => { console.log(`[Delphi] Map filename: ${this.mapFilename}`); const mapFileReader = new MapFileReaderDelphi(unwrap(this.mapFilename)); + // If this is a wrapper program (unit case), exclude prog.dpr segments + const excludedUnits = this.isWrapperProgram ? ['prog.dpr'] : []; const reconstructor = new PELabelReconstructor( asmLines, mapFileReader, new Set([PELabelReconstructorOptions.DeleteBeforeFirstSegment]), + excludedUnits, ); reconstructor.run('output'); @@ -237,6 +247,7 @@ export class PascalWinCompiler extends BaseCompiler { let fileCounter = 1; const result: string[] = []; let topLevelFileAdded = false; + let firstFilename: string | null = null; let sourceMarkerCount = 0; for (const line of reconstructor.asmLines) { @@ -251,8 +262,18 @@ export class PascalWinCompiler extends BaseCompiler { continue; } + // Track the first file we encounter + if (firstFilename === null) { + firstFilename = filename; + } + + // Only use markers from the first file (skip wrapper prog.dpr if unit exists) + if (filename !== firstFilename) { + continue; + } + sourceMarkerCount++; - if (sourceMarkerCount <= 3) { + if (sourceMarkerCount <= 10) { console.log(`[Delphi] Source marker ${sourceMarkerCount}: file="${filename}" line=${lineNumber}`); } @@ -277,9 +298,57 @@ export class PascalWinCompiler extends BaseCompiler { } console.log(`[Delphi] Total source markers found: ${sourceMarkerCount}`); - return result; + + // Truncate unmapped sections to max 5 lines + return this.truncateUnmappedSections(result); }; return []; } + + /** + * Truncate sections with no source line mappings to max 5 lines + * This removes large finalization/initialization blocks that have no debug info + */ + truncateUnmappedSections(asmLines: string[]): string[] { + const maxUnmappedLines = 5; + const sourceMarkerRegex = /^\s*\.loc\s+/; + const addressRegex = /^\s*[\da-f]+:/i; + + let lineIdx = 0; + let unmappedCount = 0; + let unmappedStartIdx = -1; + + while (lineIdx < asmLines.length) { + const line = asmLines[lineIdx]; + + if (sourceMarkerRegex.test(line)) { + // Found a source marker - reset counter + if (unmappedCount > maxUnmappedLines && unmappedStartIdx !== -1) { + // Delete excess unmapped lines + const deleteCount = unmappedCount - maxUnmappedLines; + asmLines.splice(unmappedStartIdx + maxUnmappedLines, deleteCount); + lineIdx -= deleteCount; + } + unmappedCount = 0; + unmappedStartIdx = -1; + } else if (addressRegex.test(line)) { + // This is an assembly line with an address + if (unmappedStartIdx === -1) { + unmappedStartIdx = lineIdx; + } + unmappedCount++; + } + + lineIdx++; + } + + // Handle trailing unmapped section + if (unmappedCount > maxUnmappedLines && unmappedStartIdx !== -1) { + const deleteCount = unmappedCount - maxUnmappedLines; + asmLines.splice(unmappedStartIdx + maxUnmappedLines, deleteCount); + } + + return asmLines; + } } diff --git a/lib/mapfiles/map-file-delphi.ts b/lib/mapfiles/map-file-delphi.ts index 342e0fcf730..81edc3ba922 100644 --- a/lib/mapfiles/map-file-delphi.ts +++ b/lib/mapfiles/map-file-delphi.ts @@ -171,6 +171,7 @@ export class MapFileReaderDelphi extends MapFileReader { const lineNumObj = { ...this.addressToObject(matches[2], matches[3]), lineNumber: Number.parseInt(matches[1], 10), + filename: this.currentLineNumbersFilename, }; this.lineNumbers.push(lineNumObj); diff --git a/lib/pe32-support.ts b/lib/pe32-support.ts index b7d2afe6bb5..11b657dbef6 100644 --- a/lib/pe32-support.ts +++ b/lib/pe32-support.ts @@ -45,11 +45,13 @@ export class PELabelReconstructor { private readonly int3Regex: RegExp; private readonly deleteBeforeFirstSegment: boolean; + private readonly additionalExcludedUnits: string[]; constructor( asmLines: string[], mapFileReader: MapFileReader, options: Set = new Set(), + additionalExcludedUnits: string[] = [], ) { this.asmLines = asmLines; this.addressesToLabel = []; @@ -63,6 +65,7 @@ export class PELabelReconstructor { this.mapFileReader = mapFileReader; this.needsReconstruction = options.has(PELabelReconstructorOptions.NeedsReconstruction); this.deleteBeforeFirstSegment = options.has(PELabelReconstructorOptions.DeleteBeforeFirstSegment); + this.additionalExcludedUnits = additionalExcludedUnits; } /** @@ -152,7 +155,7 @@ export class PELabelReconstructor { } deleteSystemUnits() { - const systemUnits = new Set(['SysInit.pas', 'System.pas', 'SysUtils.pas', 'Classes.pas']); + const systemUnits = new Set(['SysInit.pas', 'System.pas', 'SysUtils.pas', 'Classes.pas', ...this.additionalExcludedUnits]); let idx; let info; @@ -176,9 +179,8 @@ export class PELabelReconstructor { const systemUnits = new Set(['SysInit.pas', 'System.pas', 'SysUtils.pas', 'Classes.pas']); let firstUserAddress: number | undefined; - // For x86, prioritize isegments (actual code) over regular segments (may be data) - // Check isegments first - for (const info of this.mapFileReader.isegments) { + // Check both regular segments and isegments, take the minimum address + for (const info of this.mapFileReader.segments) { if (info.unitName && !systemUnits.has(info.unitName)) { if (firstUserAddress === undefined || info.addressInt < firstUserAddress) { firstUserAddress = info.addressInt; @@ -186,13 +188,10 @@ export class PELabelReconstructor { } } - // Only check regular segments if no user isegments found - if (firstUserAddress === undefined) { - for (const info of this.mapFileReader.segments) { - if (info.unitName && !systemUnits.has(info.unitName)) { - if (firstUserAddress === undefined || info.addressInt < firstUserAddress) { - firstUserAddress = info.addressInt; - } + for (const info of this.mapFileReader.isegments) { + if (info.unitName && !systemUnits.has(info.unitName)) { + if (firstUserAddress === undefined || info.addressInt < firstUserAddress) { + firstUserAddress = info.addressInt; } } } @@ -325,11 +324,13 @@ export class PELabelReconstructor { const lineInfo = this.mapFileReader.getLineInfoByAddress(undefined, address); if (lineIdx < 3) { - console.log(`[PELabel] Address ${address.toString(16)}: lineInfo=${lineInfo ? lineInfo.lineNumber : 'null'}, segment=${currentSegment ? currentSegment.unitName : 'null'}`); + console.log(`[PELabel] Address ${address.toString(16)}: lineInfo=${lineInfo ? `${lineInfo.lineNumber} (${(lineInfo as any).filename || 'no filename'})` : 'null'}, segment=${currentSegment ? currentSegment.unitName : 'null'}`); } if (lineInfo && currentSegment && currentSegment.unitName) { - this.asmLines.splice(lineIdx, 0, '/app/' + currentSegment.unitName + ':' + lineInfo.lineNumber); + // Use filename from lineInfo if available (for Delphi), otherwise fall back to segment unitName + const sourceFile = (lineInfo as any).filename || currentSegment.unitName; + this.asmLines.splice(lineIdx, 0, '/app/' + sourceFile + ':' + lineInfo.lineNumber); lineIdx++; } else if (segmentChanged && currentSegment) { this.asmLines.splice(lineIdx, 0, '/app/' + currentSegment.unitName + ':0'); From ba5119a1c0d6e3c302cbeed55c12195bb98717ca Mon Sep 17 00:00:00 2001 From: Paul McGee Date: Fri, 28 Nov 2025 01:30:07 +0800 Subject: [PATCH 20/27] Enable demangling and Intel syntax for C++Builder compilers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add llvm-cxxfilt as demangler for C++Builder Clang-based compilers - Enable Intel syntax output (-masm=intel) for all C++Builder groups: - embclang32 (C++Builder x86) - embclang64 (C++Builder x64) - embclang64mod (C++Builder x64 modern) This improves readability of C++Builder assembly output with proper symbol names and Intel syntax formatting. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- etc/config/c++.local.properties | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/etc/config/c++.local.properties b/etc/config/c++.local.properties index 768116c87e3..2af44a97601 100644 --- a/etc/config/c++.local.properties +++ b/etc/config/c++.local.properties @@ -19,9 +19,9 @@ includePath=C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Too # replace with the result of `where undname.exe` from a developer command prompt -# Demangler disabled - undname.exe not found +# Using llvm-cxxfilt for Clang-based C++Builder compilers -demangler= +demangler=D:\\ghcup\\ghc\\9.6.6\\mingw\\bin\\llvm-cxxfilt.exe # the compiler you want compiler explorer to start up in @@ -40,14 +40,17 @@ defaultCompiler=bcc131_64 group.embclang32.compilers =bcc104_32:bcc11_32:bcc123_32:bcc131_32 group.embclang32.groupName =C++Builder x86 group.embclang32.options =-Wno-user-defined-literals -Wno-comment -I'C:\Program Files (x86)\Embarcadero\Studio\20.0\include\dinkumware64' -I'C:\Program Files (x86)\Embarcadero\Studio\20.0\include\windows\crtl' +group.embclang32.intelAsm =-masm=intel group.embclang64.compilers =bcc104_64:bcc11_64:bcc123_64:bcc131_64 group.embclang64.groupName =C++Builder x64 group.embclang64.options =-Wno-user-defined-literals -Wno-comment -I'C:\Program Files (x86)\Embarcadero\Studio\20.0\include\dinkumware64' -I'C:\Program Files (x86)\Embarcadero\Studio\20.0\include\windows\crtl' +group.embclang64.intelAsm =-masm=intel group.embclang64mod.compilers=bcc123_64mod:bcc131_64mod group.embclang64mod.groupName=C++Builder x64 modern group.embclang64mod.options =-Wno-user-defined-literals -Wno-comment -isystem "C:\Program Files (x86)\Embarcadero\Studio\23.0\include" -isystem "C:\Program Files (x86)\Embarcadero\Studio\23.0\include\x86_64-w64-mingw32\c++\v1" -isystem "C:\Program Files (x86)\Embarcadero\Studio\23.0\lib\clang\15.0.7\include" -isystem "C:\Program Files (x86)\Embarcadero\Studio\23.0\include\x86_64-w64-mingw32" +group.embclang64mod.intelAsm =-masm=intel # MS Clang compilers - not installed on this system #group.msclang.compilers =mscl32:mscl64 From 6fcaa503386dd8b26b2fbe809aa394e4f09263e5 Mon Sep 17 00:00:00 2001 From: Paul McGee Date: Fri, 28 Nov 2025 02:25:18 +0800 Subject: [PATCH 21/27] Clean up debug logging and fix duplicate compiler configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove all 18 console.log debug statements from production code - lib/compilers/pascal-win.ts: objdump logging, source marker logging - lib/mapfiles/map-file-delphi.ts: map file read logging - lib/parsers/asm-parser.ts: directive parsing logging - lib/pe32-support.ts: address deletion logging - Fix duplicate Delphi compiler definitions - Remove Delphi compiler config from pascal.local.properties - Keep Delphi compilers only in pascal-win.local.properties - pascal.local.properties now only configures FPC compilers - Resolves "Duplicate compiler id" errors for delphi27-31 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- etc/config/pascal.local.properties | 274 +++-- lib/compilers/pascal-win.ts | 684 ++++++------- lib/mapfiles/map-file-delphi.ts | 367 ++++--- lib/parsers/asm-parser.ts | 1527 ++++++++++++++-------------- lib/pe32-support.ts | 683 ++++++------- 5 files changed, 1728 insertions(+), 1807 deletions(-) diff --git a/etc/config/pascal.local.properties b/etc/config/pascal.local.properties index b6a2a0521cf..251ee75482c 100644 --- a/etc/config/pascal.local.properties +++ b/etc/config/pascal.local.properties @@ -1,156 +1,118 @@ -# Delphi and FPC compilers for Windows -compilers=&delphi:&delphi64:&fpc -maxLinesOfAsm=1000 -rpathFlag=-O -defaultCompiler=delphi31_64 -delayCleanupTemp=true - -# Delphi 32-bit group -group.delphi.compilers=delphi27:delphi28:delphi29:delphi31 -group.delphi.compilerType=pascal-win -group.delphi.demangler= -group.delphi.objdumper=C:\\Program Files (x86)\\Embarcadero\\Dev-Cpp\\TDM-GCC-64\\bin\\objdump.exe -group.delphi.versionFlags=| grep "Version" - -# Delphi 64-bit group -group.delphi64.compilers=delphi27_64:delphi28_64:delphi29_64:delphi31_64 -group.delphi64.compilerType=pascal-win -group.delphi64.demangler= -group.delphi64.objdumper=C:\\Program Files (x86)\\Embarcadero\\Dev-Cpp\\TDM-GCC-64\\bin\\objdump.exe -group.delphi64.versionFlags=| grep "Version" - -# Individual compiler definitions -compiler.delphi27.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\20.0\\Bin\\DCC32.EXE -compiler.delphi27.name=x86 Delphi 10.4.2 Sydney - -compiler.delphi27_64.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\20.0\\Bin\\DCC64.EXE -compiler.delphi27_64.name=x64 Delphi 10.4.2 Sydney - -compiler.delphi28.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\22.0\\Bin\\DCC32.EXE -compiler.delphi28.name=x86 Delphi 11.3 Alexandria - -compiler.delphi28_64.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\22.0\\Bin\\DCC64.EXE -compiler.delphi28_64.name=x64 Delphi 11.3 Alexandria - -compiler.delphi29.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\23.0\\Bin\\DCC32.EXE -compiler.delphi29.name=x86 Delphi 12.3 Athens - -compiler.delphi29_64.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\23.0\\Bin\\DCC64.EXE -compiler.delphi29_64.name=x64 Delphi 12.3 Athens - -compiler.delphi31.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\37.0\\Bin\\DCC32.EXE -compiler.delphi31.name=x86 Delphi 13.1 Florence - -compiler.delphi31_64.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\37.0\\Bin\\DCC64.EXE -compiler.delphi31_64.name=x64 Delphi 13.1 Florence - -# FPC (Free Pascal Compiler) group -group.fpc.compilers=fpc300:fpc320:fpc322:fpc331 -group.fpc.compilerType=pascal -group.fpc.isSemVer=true -group.fpc.baseName=FPC -group.fpc.versionFlag=-iV -group.fpc.supportsBinary=true -group.fpc.supportsExecute=true -group.fpc.objdumper=C:\\Program Files (x86)\\Embarcadero\\Dev-Cpp\\TDM-GCC-64\\bin\\objdump.exe - -# FPC 3.0.0 -compiler.fpc300.exe=D:\\fpc\\3.0.0\\fpc\\bin\\x86_64-win64\\fpc.exe -compiler.fpc300.semver=3.0.0 -compiler.fpc300.name=FPC 3.0.0 - -# FPC 3.2.0 -compiler.fpc320.exe=D:\\fpc\\3.2.0\\fpc\\bin\\x86_64-win64\\fpc.exe -compiler.fpc320.semver=3.2.0 -compiler.fpc320.name=FPC 3.2.0 - -# FPC 3.2.2 -compiler.fpc322.exe=D:\\fpc\\3.2.2\\fpc\\bin\\x86_64-win64\\fpc.exe -compiler.fpc322.semver=3.2.2 -compiler.fpc322.name=FPC 3.2.2 - -# FPC 3.3.1 -compiler.fpc331.exe=D:\\fpc\\3.3.1\\fpc\\bin\\x86_64-win64\\fpc.exe -compiler.fpc331.semver=3.3.1 -compiler.fpc331.name=FPC 3.3.1 - - - - -################################# -# Delphi - Configured in pascal-win.local.properties -#group.delphi.compilers=delphi27:delphi28:delphi29:delphi31 -#group.delphi.compilerType=pascal-win -#group.delphi.demangler= -#group.delphi.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe -#group.delphi.versionFlags=| grep "Version" -# -#group.delphi64.compilers=delphi27_64:delphi28_64:delphi29_64:delphi31_64 -#group.delphi64.compilerType=pascal-win -#group.delphi64.demangler= -#group.delphi64.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe -#group.delphi64.versionFlags=| grep "Version" - -#compiler.delphi21.exe =C:\Program Files (x86)\Embarcadero\Studio\15.0\Bin\DCC32.EXE -#compiler.delphi21.name =x86 Delphi XE7 - -#compiler.delphi22.exe =C:\Program Files (x86)\Embarcadero\Studio\16.0\Bin\DCC32.EXE -#compiler.delphi22.name =x86 Delphi XE8 - -#compiler.delphi23.exe =C:\Program Files (x86)\Embarcadero\Studio\17.0\bin\DCC32.exe -#compiler.delphi23.name =x86 Delphi 10 Seattle - -#compiler.delphi23_64.exe =C:\Program Files (x86)\Embarcadero\Studio\17.0\bin\DCC64.exe -#compiler.delphi23_64.name=x64 Delphi 10 Seattle - -#compiler.delphi24.exe =c:\Program Files (x86)\Embarcadero\Studio\18.0\Bin\DCC32.EXE -#ompiler.delphi24.name =x86 Delphi 10.1 Berlin - -#compiler.delphi24_64.exe =c:\Program Files (x86)\Embarcadero\Studio\18.0\Bin\DCC64.EXE -#compiler.delphi24_64.name=x64 Delphi 10.1 Berlin - -# Delphi 10.4.2 Sydney (Studio 20.0) -#compiler.delphi27.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC32.EXE -#compiler.delphi27.name =x86 Delphi 10.4.2 Sydney -# -#compiler.delphi27_64.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC64.EXE -#compiler.delphi27_64.name=x64 Delphi 10.4.2 Sydney - -# Delphi 11 Alexandria (Studio 22.0) -#compiler.delphi28.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\Bin\DCC32.EXE -#compiler.delphi28.name =x86 Delphi 11 Alexandria -# -#compiler.delphi28_64.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\Bin\DCC64.EXE -#compiler.delphi28_64.name=x64 Delphi 11 Alexandria - -# Delphi 12.3 Athens (Studio 23.0) -#compiler.delphi29.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\Bin\DCC32.EXE -#compiler.delphi29.name =x86 Delphi 12.3 Athens -# -#compiler.delphi29_64.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\Bin\DCC64.EXE -#compiler.delphi29_64.name=x64 Delphi 12.3 Athens - -# Delphi 13.1 (Studio 37.0) -#compiler.delphi31.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\Bin\DCC32.EXE -#compiler.delphi31.name =x86 Delphi 13.1 -# -#compiler.delphi31_64.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\Bin\DCC64.EXE -#compiler.delphi31_64.name=x64 Delphi 13.1 - - - - - - -################################# -################################# -# Installed libs (See c++.amazon.properties for a scheme of libs group) -libs= - -################################# -################################# -# Installed tools - -#tools=llvm-mcatrunk:pahole - - +# FPC compilers for Windows +# Delphi compilers are configured in pascal-win.local.properties +compilers=&fpc +maxLinesOfAsm=1000 +rpathFlag=-O +defaultCompiler=fpc331 +delayCleanupTemp=true + +# FPC (Free Pascal Compiler) group +group.fpc.compilers=fpc300:fpc320:fpc322:fpc331 +group.fpc.compilerType=pascal +group.fpc.isSemVer=true +group.fpc.baseName=FPC +group.fpc.versionFlag=-iV +group.fpc.supportsBinary=true +group.fpc.supportsExecute=true +group.fpc.objdumper=C:\\Program Files (x86)\\Embarcadero\\Dev-Cpp\\TDM-GCC-64\\bin\\objdump.exe + +# FPC 3.0.0 +compiler.fpc300.exe=D:\\fpc\\3.0.0\\fpc\\bin\\x86_64-win64\\fpc.exe +compiler.fpc300.semver=3.0.0 +compiler.fpc300.name=FPC 3.0.0 + +# FPC 3.2.0 +compiler.fpc320.exe=D:\\fpc\\3.2.0\\fpc\\bin\\x86_64-win64\\fpc.exe +compiler.fpc320.semver=3.2.0 +compiler.fpc320.name=FPC 3.2.0 + +# FPC 3.2.2 +compiler.fpc322.exe=D:\\fpc\\3.2.2\\fpc\\bin\\x86_64-win64\\fpc.exe +compiler.fpc322.semver=3.2.2 +compiler.fpc322.name=FPC 3.2.2 + +# FPC 3.3.1 +compiler.fpc331.exe=D:\\fpc\\3.3.1\\fpc\\bin\\x86_64-win64\\fpc.exe +compiler.fpc331.semver=3.3.1 +compiler.fpc331.name=FPC 3.3.1 + + + + +################################# +# Delphi - Configured in pascal-win.local.properties +#group.delphi.compilers=delphi27:delphi28:delphi29:delphi31 +#group.delphi.compilerType=pascal-win +#group.delphi.demangler= +#group.delphi.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe +#group.delphi.versionFlags=| grep "Version" +# +#group.delphi64.compilers=delphi27_64:delphi28_64:delphi29_64:delphi31_64 +#group.delphi64.compilerType=pascal-win +#group.delphi64.demangler= +#group.delphi64.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe +#group.delphi64.versionFlags=| grep "Version" + +#compiler.delphi21.exe =C:\Program Files (x86)\Embarcadero\Studio\15.0\Bin\DCC32.EXE +#compiler.delphi21.name =x86 Delphi XE7 + +#compiler.delphi22.exe =C:\Program Files (x86)\Embarcadero\Studio\16.0\Bin\DCC32.EXE +#compiler.delphi22.name =x86 Delphi XE8 + +#compiler.delphi23.exe =C:\Program Files (x86)\Embarcadero\Studio\17.0\bin\DCC32.exe +#compiler.delphi23.name =x86 Delphi 10 Seattle + +#compiler.delphi23_64.exe =C:\Program Files (x86)\Embarcadero\Studio\17.0\bin\DCC64.exe +#compiler.delphi23_64.name=x64 Delphi 10 Seattle + +#compiler.delphi24.exe =c:\Program Files (x86)\Embarcadero\Studio\18.0\Bin\DCC32.EXE +#ompiler.delphi24.name =x86 Delphi 10.1 Berlin + +#compiler.delphi24_64.exe =c:\Program Files (x86)\Embarcadero\Studio\18.0\Bin\DCC64.EXE +#compiler.delphi24_64.name=x64 Delphi 10.1 Berlin + +# Delphi 10.4.2 Sydney (Studio 20.0) +#compiler.delphi27.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC32.EXE +#compiler.delphi27.name =x86 Delphi 10.4.2 Sydney +# +#compiler.delphi27_64.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC64.EXE +#compiler.delphi27_64.name=x64 Delphi 10.4.2 Sydney + +# Delphi 11 Alexandria (Studio 22.0) +#compiler.delphi28.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\Bin\DCC32.EXE +#compiler.delphi28.name =x86 Delphi 11 Alexandria +# +#compiler.delphi28_64.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\Bin\DCC64.EXE +#compiler.delphi28_64.name=x64 Delphi 11 Alexandria + +# Delphi 12.3 Athens (Studio 23.0) +#compiler.delphi29.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\Bin\DCC32.EXE +#compiler.delphi29.name =x86 Delphi 12.3 Athens +# +#compiler.delphi29_64.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\Bin\DCC64.EXE +#compiler.delphi29_64.name=x64 Delphi 12.3 Athens + +# Delphi 13.1 (Studio 37.0) +#compiler.delphi31.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\Bin\DCC32.EXE +#compiler.delphi31.name =x86 Delphi 13.1 +# +#compiler.delphi31_64.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\Bin\DCC64.EXE +#compiler.delphi31_64.name=x64 Delphi 13.1 + + + + + + +################################# +################################# +# Installed libs (See c++.amazon.properties for a scheme of libs group) +libs= + +################################# +################################# +# Installed tools + +#tools=llvm-mcatrunk:pahole + + diff --git a/lib/compilers/pascal-win.ts b/lib/compilers/pascal-win.ts index 7c300f3b47a..4994c2a2051 100644 --- a/lib/compilers/pascal-win.ts +++ b/lib/compilers/pascal-win.ts @@ -1,354 +1,330 @@ -// Copyright (c) 2017, Compiler Explorer Authors -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. - -import fs from 'node:fs/promises'; -import path from 'node:path'; - -import type { - ExecutionOptions, - ExecutionOptionsWithEnv, - FiledataPair, -} from '../../types/compilation/compilation.interfaces.js'; -import type {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js'; -import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js'; -import {unwrap} from '../assert.js'; -import {BaseCompiler} from '../base-compiler.js'; -import {CompilationEnvironment} from '../compilation-env.js'; -import {MapFileReaderDelphi} from '../mapfiles/map-file-delphi.js'; -import {PELabelReconstructor, PELabelReconstructorOptions} from '../pe32-support.js'; -import * as utils from '../utils.js'; - -import * as pascalUtils from './pascal-utils.js'; - -export class PascalWinCompiler extends BaseCompiler { - static get key() { - return 'pascal-win'; - } - - mapFilename: string | null; - dprFilename: string; - projectBaseName: string; - isWrapperProgram: boolean; - - constructor(info: PreliminaryCompilerInfo, env: CompilationEnvironment) { - super(info, env); - info.supportsFiltersInBinary = true; - - this.mapFilename = null; - this.compileFilename = 'output.pas'; - this.dprFilename = 'prog.dpr'; - this.projectBaseName = 'prog'; - this.isWrapperProgram = false; - } - - override getSharedLibraryPathsAsArguments() { - return []; - } - - override exec(command: string, args: string[], options: ExecutionOptions) { - if (process.platform === 'linux' || process.platform === 'darwin') { - const wine = this.env.ceProps('wine'); - - args = args.slice(0); - if (command.toLowerCase().endsWith('.exe')) { - args.unshift(command); - command = wine; - } - } - - return super.exec(command, args, options); - } - - override getExecutableFilename(dirPath: string) { - return path.join(dirPath, this.projectBaseName + '.exe'); - } - - override getOutputFilename(dirPath: string) { - return path.join(dirPath, this.projectBaseName + '.exe'); - } - - override filename(fn: string) { - if (process.platform === 'linux' || process.platform === 'darwin') { - return 'Z:' + fn; - } - return super.filename(fn); - } - - override async objdump(outputFilename: string, result, maxSize: number, intelAsm: boolean) { - const dirPath = path.dirname(outputFilename); - const execBinary = this.getExecutableFilename(dirPath); - if (await utils.fileExists(execBinary)) { - outputFilename = execBinary; - } else { - outputFilename = this.getOutputFilename(path.dirname(outputFilename)); - } - - let args = [...this.compiler.objdumperArgs, '-d', '-l', outputFilename]; - if (intelAsm) args = args.concat(['-M', 'intel']); - console.log(`[Delphi] Running objdump on: ${outputFilename}`); - console.log(`[Delphi] Objdump command: ${this.compiler.objdumper} ${args.join(' ')}`); - return this.exec(this.compiler.objdumper, args, {maxOutput: 1024 * 1024 * 1024}).then(objResult => { - if (objResult.code === 0) { - result.asm = objResult.stdout; - const lines = objResult.stdout.split('\n'); - console.log(`[Delphi] Objdump output: ${lines.length} lines`); - console.log(`[Delphi] First 5 lines with addresses:`); - let addressLineCount = 0; - for (let i = 0; i < Math.min(50, lines.length); i++) { - if (lines[i].match(/^\s*[0-9a-f]+:/)) { - console.log(`[Delphi] Line ${i}: ${lines[i]}`); - if (++addressLineCount >= 5) break; - } - } - } else { - console.log(`[Delphi] Objdump failed with code ${objResult.code}`); - console.log(`[Delphi] Objdump stderr: ${objResult.stderr}`); - console.log(`[Delphi] Objdump stdout: ${objResult.stdout}`); - result.asm = ''; - } - - return result; - }); - } - - async saveDummyProjectFile(filename: string, unitName: string, unitPath: string) { - // biome-ignore format: keep as-is for readability - await fs.writeFile( - filename, - 'program prog;\n' + - 'uses ' + unitName + ' in \'' + unitPath + '\';\n' + - 'begin\n' + - 'end.\n', - ); - } - - override async writeAllFiles(dirPath: string, source: string, files: FiledataPair[]) { - // Strip comment content to avoid highlighting commented code - const cleanedSource = pascalUtils.stripComments(source); - - let inputFilename: string; - if (pascalUtils.isProgram(source)) { - // Use the program name from the source, like FPC does - const progName = pascalUtils.getProgName(source); - inputFilename = path.join(dirPath, progName + '.dpr'); - } else { - const unitName = pascalUtils.getUnitname(source); - if (unitName) { - inputFilename = path.join(dirPath, unitName + '.pas'); - } else { - inputFilename = path.join(dirPath, this.compileFilename); - } - } - - await fs.writeFile(inputFilename, cleanedSource); - - if (files && files.length > 0) { - await this.writeMultipleFiles(files, dirPath); - } - - return { - inputFilename, - }; - } - - override async runCompiler( - compiler: string, - options: string[], - inputFilename: string, - execOptions: ExecutionOptionsWithEnv, - ) { - if (!execOptions) { - execOptions = this.getDefaultExecOptions(); - } - - const tempPath = path.dirname(inputFilename); - const inputBasename = path.basename(inputFilename); - const isDprFile = inputBasename.toLowerCase().endsWith('.dpr'); - - let projectFile: string; - let projectBaseName: string; - - if (isDprFile) { - // Input is already a .dpr program file, compile it directly (like FPC does) - projectFile = inputFilename; - projectBaseName = inputBasename.replace(/\.dpr$/i, ''); - this.isWrapperProgram = false; - } else { - // Input is a .pas unit file, create a dummy prog.dpr project that uses it - const unitFilepath = inputBasename; - const unitName = unitFilepath.replace(/\.pas$/i, ''); - projectFile = path.join(tempPath, this.dprFilename); - projectBaseName = 'prog'; - await this.saveDummyProjectFile(projectFile, unitName, unitFilepath); - this.isWrapperProgram = true; - } - - this.projectBaseName = projectBaseName; - this.mapFilename = path.join(tempPath, projectBaseName + '.map'); - - inputFilename = inputFilename.replaceAll('/', '\\'); - - options.pop(); - - options.unshift('-CC', '-W', '-H', '-GD', '-$D+', '-$L+', '-$O-', '-$W+', '-$C-', '-V', '-B'); - - options.push(projectFile); - execOptions.customCwd = tempPath; - - return this.exec(compiler, options, execOptions).then(result => { - return { - ...result, - inputFilename, - stdout: utils.parseOutput(result.stdout, inputFilename), - stderr: utils.parseOutput(result.stderr, inputFilename), - }; - }); - } - - override optionsForFilter(filters: ParseFiltersAndOutputOptions) { - filters.binary = true; - filters.dontMaskFilenames = true; - filters.preProcessBinaryAsmLines = (asmLines: string[]) => { - console.log(`[Delphi] Map filename: ${this.mapFilename}`); - const mapFileReader = new MapFileReaderDelphi(unwrap(this.mapFilename)); - // If this is a wrapper program (unit case), exclude prog.dpr segments - const excludedUnits = this.isWrapperProgram ? ['prog.dpr'] : []; - const reconstructor = new PELabelReconstructor( - asmLines, - mapFileReader, - new Set([PELabelReconstructorOptions.DeleteBeforeFirstSegment]), - excludedUnits, - ); - reconstructor.run('output'); - - // Convert source line markers from /app/filename:line format to .loc directives - const fileMap = new Map(); - let fileCounter = 1; - const result: string[] = []; - let topLevelFileAdded = false; - let firstFilename: string | null = null; - - let sourceMarkerCount = 0; - for (const line of reconstructor.asmLines) { - const sourceMatch = line.match(/^\/app\/(.+):(\d+)$/); - if (sourceMatch) { - const filename = sourceMatch[1]; - const lineNumber = sourceMatch[2]; - - // Skip line 0 markers - they indicate no line info available - // Let the previous source line continue instead of breaking highlighting - if (lineNumber === '0') { - continue; - } - - // Track the first file we encounter - if (firstFilename === null) { - firstFilename = filename; - } - - // Only use markers from the first file (skip wrapper prog.dpr if unit exists) - if (filename !== firstFilename) { - continue; - } - - sourceMarkerCount++; - if (sourceMarkerCount <= 10) { - console.log(`[Delphi] Source marker ${sourceMarkerCount}: file="${filename}" line=${lineNumber}`); - } - - // Add top-level .file directive once at the very beginning (like FPC does) - if (!topLevelFileAdded) { - result.unshift(`\t.file "${filename}"`); - topLevelFileAdded = true; - } - - // Get or assign file number for DWARF debug info - if (!fileMap.has(filename)) { - const fileNum = fileCounter++; - fileMap.set(filename, fileNum); - result.push(`\t.file ${fileNum} "${filename}"`); - } - - const fileNum = fileMap.get(filename)!; - result.push(`\t.loc ${fileNum} ${lineNumber} 0`); - } else { - result.push(line); - } - } - - console.log(`[Delphi] Total source markers found: ${sourceMarkerCount}`); - - // Truncate unmapped sections to max 5 lines - return this.truncateUnmappedSections(result); - }; - - return []; - } - - /** - * Truncate sections with no source line mappings to max 5 lines - * This removes large finalization/initialization blocks that have no debug info - */ - truncateUnmappedSections(asmLines: string[]): string[] { - const maxUnmappedLines = 5; - const sourceMarkerRegex = /^\s*\.loc\s+/; - const addressRegex = /^\s*[\da-f]+:/i; - - let lineIdx = 0; - let unmappedCount = 0; - let unmappedStartIdx = -1; - - while (lineIdx < asmLines.length) { - const line = asmLines[lineIdx]; - - if (sourceMarkerRegex.test(line)) { - // Found a source marker - reset counter - if (unmappedCount > maxUnmappedLines && unmappedStartIdx !== -1) { - // Delete excess unmapped lines - const deleteCount = unmappedCount - maxUnmappedLines; - asmLines.splice(unmappedStartIdx + maxUnmappedLines, deleteCount); - lineIdx -= deleteCount; - } - unmappedCount = 0; - unmappedStartIdx = -1; - } else if (addressRegex.test(line)) { - // This is an assembly line with an address - if (unmappedStartIdx === -1) { - unmappedStartIdx = lineIdx; - } - unmappedCount++; - } - - lineIdx++; - } - - // Handle trailing unmapped section - if (unmappedCount > maxUnmappedLines && unmappedStartIdx !== -1) { - const deleteCount = unmappedCount - maxUnmappedLines; - asmLines.splice(unmappedStartIdx + maxUnmappedLines, deleteCount); - } - - return asmLines; - } -} +// Copyright (c) 2017, Compiler Explorer Authors +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import fs from 'node:fs/promises'; +import path from 'node:path'; + +import type { + ExecutionOptions, + ExecutionOptionsWithEnv, + FiledataPair, +} from '../../types/compilation/compilation.interfaces.js'; +import type {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js'; +import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js'; +import {unwrap} from '../assert.js'; +import {BaseCompiler} from '../base-compiler.js'; +import {CompilationEnvironment} from '../compilation-env.js'; +import {MapFileReaderDelphi} from '../mapfiles/map-file-delphi.js'; +import {PELabelReconstructor, PELabelReconstructorOptions} from '../pe32-support.js'; +import * as utils from '../utils.js'; + +import * as pascalUtils from './pascal-utils.js'; + +export class PascalWinCompiler extends BaseCompiler { + static get key() { + return 'pascal-win'; + } + + mapFilename: string | null; + dprFilename: string; + projectBaseName: string; + isWrapperProgram: boolean; + + constructor(info: PreliminaryCompilerInfo, env: CompilationEnvironment) { + super(info, env); + info.supportsFiltersInBinary = true; + + this.mapFilename = null; + this.compileFilename = 'output.pas'; + this.dprFilename = 'prog.dpr'; + this.projectBaseName = 'prog'; + this.isWrapperProgram = false; + } + + override getSharedLibraryPathsAsArguments() { + return []; + } + + override exec(command: string, args: string[], options: ExecutionOptions) { + if (process.platform === 'linux' || process.platform === 'darwin') { + const wine = this.env.ceProps('wine'); + + args = args.slice(0); + if (command.toLowerCase().endsWith('.exe')) { + args.unshift(command); + command = wine; + } + } + + return super.exec(command, args, options); + } + + override getExecutableFilename(dirPath: string) { + return path.join(dirPath, this.projectBaseName + '.exe'); + } + + override getOutputFilename(dirPath: string) { + return path.join(dirPath, this.projectBaseName + '.exe'); + } + + override filename(fn: string) { + if (process.platform === 'linux' || process.platform === 'darwin') { + return 'Z:' + fn; + } + return super.filename(fn); + } + + override async objdump(outputFilename: string, result, maxSize: number, intelAsm: boolean) { + const dirPath = path.dirname(outputFilename); + const execBinary = this.getExecutableFilename(dirPath); + if (await utils.fileExists(execBinary)) { + outputFilename = execBinary; + } else { + outputFilename = this.getOutputFilename(path.dirname(outputFilename)); + } + + let args = [...this.compiler.objdumperArgs, '-d', '-l', outputFilename]; + if (intelAsm) args = args.concat(['-M', 'intel']); + return this.exec(this.compiler.objdumper, args, {maxOutput: 1024 * 1024 * 1024}).then(objResult => { + if (objResult.code === 0) { + result.asm = objResult.stdout; + } else { + result.asm = ''; + } + + return result; + }); + } + + async saveDummyProjectFile(filename: string, unitName: string, unitPath: string) { + // biome-ignore format: keep as-is for readability + await fs.writeFile( + filename, + 'program prog;\n' + + 'uses ' + unitName + ' in \'' + unitPath + '\';\n' + + 'begin\n' + + 'end.\n', + ); + } + + override async writeAllFiles(dirPath: string, source: string, files: FiledataPair[]) { + // Strip comment content to avoid highlighting commented code + const cleanedSource = pascalUtils.stripComments(source); + + let inputFilename: string; + if (pascalUtils.isProgram(source)) { + // Use the program name from the source, like FPC does + const progName = pascalUtils.getProgName(source); + inputFilename = path.join(dirPath, progName + '.dpr'); + } else { + const unitName = pascalUtils.getUnitname(source); + if (unitName) { + inputFilename = path.join(dirPath, unitName + '.pas'); + } else { + inputFilename = path.join(dirPath, this.compileFilename); + } + } + + await fs.writeFile(inputFilename, cleanedSource); + + if (files && files.length > 0) { + await this.writeMultipleFiles(files, dirPath); + } + + return { + inputFilename, + }; + } + + override async runCompiler( + compiler: string, + options: string[], + inputFilename: string, + execOptions: ExecutionOptionsWithEnv, + ) { + if (!execOptions) { + execOptions = this.getDefaultExecOptions(); + } + + const tempPath = path.dirname(inputFilename); + const inputBasename = path.basename(inputFilename); + const isDprFile = inputBasename.toLowerCase().endsWith('.dpr'); + + let projectFile: string; + let projectBaseName: string; + + if (isDprFile) { + // Input is already a .dpr program file, compile it directly (like FPC does) + projectFile = inputFilename; + projectBaseName = inputBasename.replace(/\.dpr$/i, ''); + this.isWrapperProgram = false; + } else { + // Input is a .pas unit file, create a dummy prog.dpr project that uses it + const unitFilepath = inputBasename; + const unitName = unitFilepath.replace(/\.pas$/i, ''); + projectFile = path.join(tempPath, this.dprFilename); + projectBaseName = 'prog'; + await this.saveDummyProjectFile(projectFile, unitName, unitFilepath); + this.isWrapperProgram = true; + } + + this.projectBaseName = projectBaseName; + this.mapFilename = path.join(tempPath, projectBaseName + '.map'); + + inputFilename = inputFilename.replaceAll('/', '\\'); + + options.pop(); + + options.unshift('-CC', '-W', '-H', '-GD', '-$D+', '-$L+', '-$O-', '-$W+', '-$C-', '-V', '-B'); + + options.push(projectFile); + execOptions.customCwd = tempPath; + + return this.exec(compiler, options, execOptions).then(result => { + return { + ...result, + inputFilename, + stdout: utils.parseOutput(result.stdout, inputFilename), + stderr: utils.parseOutput(result.stderr, inputFilename), + }; + }); + } + + override optionsForFilter(filters: ParseFiltersAndOutputOptions) { + filters.binary = true; + filters.dontMaskFilenames = true; + filters.preProcessBinaryAsmLines = (asmLines: string[]) => { + const mapFileReader = new MapFileReaderDelphi(unwrap(this.mapFilename)); + // If this is a wrapper program (unit case), exclude prog.dpr segments + const excludedUnits = this.isWrapperProgram ? ['prog.dpr'] : []; + const reconstructor = new PELabelReconstructor( + asmLines, + mapFileReader, + new Set([PELabelReconstructorOptions.DeleteBeforeFirstSegment]), + excludedUnits, + ); + reconstructor.run('output'); + + // Convert source line markers from /app/filename:line format to .loc directives + const fileMap = new Map(); + let fileCounter = 1; + const result: string[] = []; + let topLevelFileAdded = false; + let firstFilename: string | null = null; + + for (const line of reconstructor.asmLines) { + const sourceMatch = line.match(/^\/app\/(.+):(\d+)$/); + if (sourceMatch) { + const filename = sourceMatch[1]; + const lineNumber = sourceMatch[2]; + + // Skip line 0 markers - they indicate no line info available + // Let the previous source line continue instead of breaking highlighting + if (lineNumber === '0') { + continue; + } + + // Track the first file we encounter + if (firstFilename === null) { + firstFilename = filename; + } + + // Only use markers from the first file (skip wrapper prog.dpr if unit exists) + if (filename !== firstFilename) { + continue; + } + + // Add top-level .file directive once at the very beginning (like FPC does) + if (!topLevelFileAdded) { + result.unshift(`\t.file "${filename}"`); + topLevelFileAdded = true; + } + + // Get or assign file number for DWARF debug info + if (!fileMap.has(filename)) { + const fileNum = fileCounter++; + fileMap.set(filename, fileNum); + result.push(`\t.file ${fileNum} "${filename}"`); + } + + const fileNum = fileMap.get(filename)!; + result.push(`\t.loc ${fileNum} ${lineNumber} 0`); + } else { + result.push(line); + } + } + + // Truncate unmapped sections to max 5 lines + return this.truncateUnmappedSections(result); + }; + + return []; + } + + /** + * Truncate sections with no source line mappings to max 5 lines + * This removes large finalization/initialization blocks that have no debug info + */ + truncateUnmappedSections(asmLines: string[]): string[] { + const maxUnmappedLines = 5; + const sourceMarkerRegex = /^\s*\.loc\s+/; + const addressRegex = /^\s*[\da-f]+:/i; + + let lineIdx = 0; + let unmappedCount = 0; + let unmappedStartIdx = -1; + + while (lineIdx < asmLines.length) { + const line = asmLines[lineIdx]; + + if (sourceMarkerRegex.test(line)) { + // Found a source marker - reset counter + if (unmappedCount > maxUnmappedLines && unmappedStartIdx !== -1) { + // Delete excess unmapped lines + const deleteCount = unmappedCount - maxUnmappedLines; + asmLines.splice(unmappedStartIdx + maxUnmappedLines, deleteCount); + lineIdx -= deleteCount; + } + unmappedCount = 0; + unmappedStartIdx = -1; + } else if (addressRegex.test(line)) { + // This is an assembly line with an address + if (unmappedStartIdx === -1) { + unmappedStartIdx = lineIdx; + } + unmappedCount++; + } + + lineIdx++; + } + + // Handle trailing unmapped section + if (unmappedCount > maxUnmappedLines && unmappedStartIdx !== -1) { + const deleteCount = unmappedCount - maxUnmappedLines; + asmLines.splice(unmappedStartIdx + maxUnmappedLines, deleteCount); + } + + return asmLines; + } +} diff --git a/lib/mapfiles/map-file-delphi.ts b/lib/mapfiles/map-file-delphi.ts index 81edc3ba922..35b341cb2fa 100644 --- a/lib/mapfiles/map-file-delphi.ts +++ b/lib/mapfiles/map-file-delphi.ts @@ -1,188 +1,179 @@ -// Copyright (c) 2017, Compiler Explorer Authors -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. - -import {MapFileReader} from './map-file.js'; - -export class MapFileReaderDelphi extends MapFileReader { - regexDelphiCodeSegmentOffset = /^\s([\da-f]*):([\da-f]*)\s*([\da-f]*)h\s*(\.[$a-z]*)\s*([a-z]*)$/i; - regexDelphiCodeSegment = /^\s([\da-f]*):([\da-f]*)\s*([\da-f]*)\s*c=code\s*s=.text\s*g=.*m=([\w.]*)\s.*/i; - regexDelphiICodeSegment = /^\s([\da-f]*):([\da-f]*)\s*([\da-f]*)\s*c=icode\s*s=.itext\s*g=.*m=([\w.]*)\s.*/i; - regexDelphiNames = /^\s([\da-f]*):([\da-f]*)\s*([\w$.<>@{}]*)$/i; - regexDelphiLineNumbersStart = /line numbers for (.*)\((.*)\) segment \.text/i; - regexDelphiLineNumber = /^\s*(\d+)\s+([\da-f]+):([\da-f]+)/i; - regexDelphiLineNumbersStartIText = /line numbers for (.*)\((.*)\) segment \.itext/i; - currentLineNumbersFilename: string | null = null; - moduleToFilename: Map = new Map(); - - /** - * Tries to match the given line to code segment information - * Matches in order: - * 1. segment offset info - * 2. code segment delphi map - * 3. icode segment delphi map - * 4. code segment vs map - */ - override tryReadingCodeSegmentInfo(line: string) { - let matches = line.match(this.regexDelphiCodeSegmentOffset); - if (matches && !matches[4].includes('$') && Number.parseInt(matches[2], 16) >= this.preferredLoadAddress) { - const addressWithOffset = Number.parseInt(matches[2], 16); - this.segmentOffsets.push({ - segment: matches[1], - addressInt: addressWithOffset, - address: addressWithOffset.toString(16), - segmentLength: Number.parseInt(matches[3], 16), - }); - } else { - matches = line.match(this.regexDelphiCodeSegment); - if (matches) { - this.segments.push({ - ...this.addressToObject(matches[1], matches[2]), - id: this.segments.length + 1, - segmentLength: Number.parseInt(matches[3], 16), - unitName: matches[4] === 'prog' ? 'prog.dpr' : matches[4] + '.pas', - }); - } else { - matches = line.match(this.regexDelphiICodeSegment); - if (matches) { - this.isegments.push({ - ...this.addressToObject(matches[1], matches[2]), - id: this.isegments.length + 1, - segmentLength: Number.parseInt(matches[3], 16), - unitName: matches[4] === 'prog' ? 'prog.dpr' : matches[4] + '.pas', - }); - } - } - } - } - - /** - * Try to match information about the address where a symbol is - */ - override tryReadingNamedAddress(line: string) { - const matches = line.match(this.regexDelphiNames); - if (matches) { - if (!this.getSymbolInfoByName(matches[3])) { - this.namedAddresses.push({ - ...this.addressToObject(matches[1], matches[2]), - displayName: matches[3], - segmentLength: 0, - }); - } - } - } - - override run() { - console.log(`[MapFileDelphi] Starting map file read: ${this.mapFilename}`); - - // First pass: read the map file - super.run(); - - console.log(`[MapFileDelphi] Map file read complete. Line numbers found: ${this.lineNumbers.length}`); - - // Second pass: fix unitName for segments using the module-to-filename mapping - this.fixSegmentUnitNames(); - } - - fixSegmentUnitNames() { - for (const segment of this.segments) { - // Extract module name from current unitName (remove .pas or .dpr extension) - const moduleName = segment.unitName?.replace(/\.(pas|dpr)$/i, '') || ''; - if (this.moduleToFilename.has(moduleName)) { - segment.unitName = this.moduleToFilename.get(moduleName)!; - } - } - for (const segment of this.isegments) { - const moduleName = segment.unitName?.replace(/\.(pas|dpr)$/i, '') || ''; - if (this.moduleToFilename.has(moduleName)) { - segment.unitName = this.moduleToFilename.get(moduleName)!; - } - } - } - - override getSegmentInfoByStartingAddress(segment: string | undefined, address: number) { - // Check regular segments first - let result = super.getSegmentInfoByStartingAddress(segment, address); - if (result) return result; - - // Also check isegments (for x86 .itext segments) - for (let idx = 0; idx < this.isegments.length; idx++) { - const info = this.isegments[idx]; - if (!segment && info.addressInt === address) { - return info; - } - if (info.segment === segment && info.addressWithoutOffset === address) { - return info; - } - } - - return undefined; - } - - override isStartOfLineNumbers(line: string) { - // Check both .text and .itext segments - let matches = line.match(this.regexDelphiLineNumbersStart); - if (!matches) { - matches = line.match(this.regexDelphiLineNumbersStartIText); - } - - if (matches) { - // Extract module name and actual filename from the path in parentheses - const moduleName = matches[1]; - const fullPath = matches[2]; - const filename = fullPath.split('\\').pop() || fullPath.split('/').pop() || fullPath; - this.currentLineNumbersFilename = filename; - this.moduleToFilename.set(moduleName, filename); - console.log(`[MapFileDelphi] Found line numbers for module "${moduleName}" -> file: ${filename}`); - } - return !!matches; - } - - /** - * Retreives line number references from supplied Map line - */ - override tryReadingLineNumbers(line: string) { - let hasLineNumbers = false; - - const references = line.split(' '); // 4 spaces - for (const reference of references) { - const matches = reference.match(this.regexDelphiLineNumber); - if (matches) { - const lineNumObj = { - ...this.addressToObject(matches[2], matches[3]), - lineNumber: Number.parseInt(matches[1], 10), - filename: this.currentLineNumbersFilename, - }; - this.lineNumbers.push(lineNumObj); - - if (this.lineNumbers.length <= 3) { - console.log(`[MapFileDelphi] Line ${lineNumObj.lineNumber} at address ${lineNumObj.addressInt.toString(16)} (segment ${lineNumObj.segment}:${matches[3]})`); - } - - hasLineNumbers = true; - } - } - - return hasLineNumbers; - } -} +// Copyright (c) 2017, Compiler Explorer Authors +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import {MapFileReader} from './map-file.js'; + +export class MapFileReaderDelphi extends MapFileReader { + regexDelphiCodeSegmentOffset = /^\s([\da-f]*):([\da-f]*)\s*([\da-f]*)h\s*(\.[$a-z]*)\s*([a-z]*)$/i; + regexDelphiCodeSegment = /^\s([\da-f]*):([\da-f]*)\s*([\da-f]*)\s*c=code\s*s=.text\s*g=.*m=([\w.]*)\s.*/i; + regexDelphiICodeSegment = /^\s([\da-f]*):([\da-f]*)\s*([\da-f]*)\s*c=icode\s*s=.itext\s*g=.*m=([\w.]*)\s.*/i; + regexDelphiNames = /^\s([\da-f]*):([\da-f]*)\s*([\w$.<>@{}]*)$/i; + regexDelphiLineNumbersStart = /line numbers for (.*)\((.*)\) segment \.text/i; + regexDelphiLineNumber = /^\s*(\d+)\s+([\da-f]+):([\da-f]+)/i; + regexDelphiLineNumbersStartIText = /line numbers for (.*)\((.*)\) segment \.itext/i; + currentLineNumbersFilename: string | null = null; + moduleToFilename: Map = new Map(); + + /** + * Tries to match the given line to code segment information + * Matches in order: + * 1. segment offset info + * 2. code segment delphi map + * 3. icode segment delphi map + * 4. code segment vs map + */ + override tryReadingCodeSegmentInfo(line: string) { + let matches = line.match(this.regexDelphiCodeSegmentOffset); + if (matches && !matches[4].includes('$') && Number.parseInt(matches[2], 16) >= this.preferredLoadAddress) { + const addressWithOffset = Number.parseInt(matches[2], 16); + this.segmentOffsets.push({ + segment: matches[1], + addressInt: addressWithOffset, + address: addressWithOffset.toString(16), + segmentLength: Number.parseInt(matches[3], 16), + }); + } else { + matches = line.match(this.regexDelphiCodeSegment); + if (matches) { + this.segments.push({ + ...this.addressToObject(matches[1], matches[2]), + id: this.segments.length + 1, + segmentLength: Number.parseInt(matches[3], 16), + unitName: matches[4] === 'prog' ? 'prog.dpr' : matches[4] + '.pas', + }); + } else { + matches = line.match(this.regexDelphiICodeSegment); + if (matches) { + this.isegments.push({ + ...this.addressToObject(matches[1], matches[2]), + id: this.isegments.length + 1, + segmentLength: Number.parseInt(matches[3], 16), + unitName: matches[4] === 'prog' ? 'prog.dpr' : matches[4] + '.pas', + }); + } + } + } + } + + /** + * Try to match information about the address where a symbol is + */ + override tryReadingNamedAddress(line: string) { + const matches = line.match(this.regexDelphiNames); + if (matches) { + if (!this.getSymbolInfoByName(matches[3])) { + this.namedAddresses.push({ + ...this.addressToObject(matches[1], matches[2]), + displayName: matches[3], + segmentLength: 0, + }); + } + } + } + + override run() { + // First pass: read the map file + super.run(); + + // Second pass: fix unitName for segments using the module-to-filename mapping + this.fixSegmentUnitNames(); + } + + fixSegmentUnitNames() { + for (const segment of this.segments) { + // Extract module name from current unitName (remove .pas or .dpr extension) + const moduleName = segment.unitName?.replace(/\.(pas|dpr)$/i, '') || ''; + if (this.moduleToFilename.has(moduleName)) { + segment.unitName = this.moduleToFilename.get(moduleName)!; + } + } + for (const segment of this.isegments) { + const moduleName = segment.unitName?.replace(/\.(pas|dpr)$/i, '') || ''; + if (this.moduleToFilename.has(moduleName)) { + segment.unitName = this.moduleToFilename.get(moduleName)!; + } + } + } + + override getSegmentInfoByStartingAddress(segment: string | undefined, address: number) { + // Check regular segments first + let result = super.getSegmentInfoByStartingAddress(segment, address); + if (result) return result; + + // Also check isegments (for x86 .itext segments) + for (let idx = 0; idx < this.isegments.length; idx++) { + const info = this.isegments[idx]; + if (!segment && info.addressInt === address) { + return info; + } + if (info.segment === segment && info.addressWithoutOffset === address) { + return info; + } + } + + return undefined; + } + + override isStartOfLineNumbers(line: string) { + // Check both .text and .itext segments + let matches = line.match(this.regexDelphiLineNumbersStart); + if (!matches) { + matches = line.match(this.regexDelphiLineNumbersStartIText); + } + + if (matches) { + // Extract module name and actual filename from the path in parentheses + const moduleName = matches[1]; + const fullPath = matches[2]; + const filename = fullPath.split('\\').pop() || fullPath.split('/').pop() || fullPath; + this.currentLineNumbersFilename = filename; + this.moduleToFilename.set(moduleName, filename); + } + return !!matches; + } + + /** + * Retreives line number references from supplied Map line + */ + override tryReadingLineNumbers(line: string) { + let hasLineNumbers = false; + + const references = line.split(' '); // 4 spaces + for (const reference of references) { + const matches = reference.match(this.regexDelphiLineNumber); + if (matches) { + const lineNumObj = { + ...this.addressToObject(matches[2], matches[3]), + lineNumber: Number.parseInt(matches[1], 10), + filename: this.currentLineNumbersFilename, + }; + this.lineNumbers.push(lineNumObj); + + hasLineNumbers = true; + } + } + + return hasLineNumbers; + } +} diff --git a/lib/parsers/asm-parser.ts b/lib/parsers/asm-parser.ts index 7f614844a46..41e5f80dc8c 100644 --- a/lib/parsers/asm-parser.ts +++ b/lib/parsers/asm-parser.ts @@ -1,765 +1,762 @@ -// Copyright (c) 2015, Compiler Explorer Authors -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. - -import {isString} from '../../shared/common-utils.js'; -import { - AsmResultLabel, - AsmResultSource, - ParsedAsmResult, - ParsedAsmResultLine, -} from '../../types/asmresult/asmresult.interfaces.js'; -import {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js'; -import {assert} from '../assert.js'; -import {PropertyGetter} from '../properties.interfaces.js'; -import * as utils from '../utils.js'; - -import {IAsmParser} from './asm-parser.interfaces.js'; -import {AsmRegex} from './asmregex.js'; -import {LabelContext, LabelProcessor} from './label-processor.js'; -import {ParsingState} from './parsing-state.js'; -import {SourceHandlerContext, SourceLineHandler} from './source-line-handler.js'; - -function maybeAddBlank(asm: ParsedAsmResultLine[]) { - const lastBlank = asm.length === 0 || asm[asm.length - 1].text === ''; - if (!lastBlank) asm.push({text: '', source: null, labels: []}); -} - -export type ParsingContext = { - files: Record; - source: AsmResultSource | undefined | null; - dontMaskFilenames: boolean; - prevLabel: string; - prevLabelIsUserFunction: boolean; -}; - -export class AsmParser extends AsmRegex implements IAsmParser { - protected sourceLineHandler: SourceLineHandler; - protected labelProcessor: LabelProcessor; - protected parsingState: ParsingState; - - protected maxAsmLines: number; - - protected labelFindNonMips: RegExp; - protected labelFindMips: RegExp; - protected mipsLabelDefinition: RegExp; - protected dataDefn: RegExp; - protected fileFind: RegExp; - protected hasOpcodeRe: RegExp; - protected instructionRe: RegExp; - protected identifierFindRe: RegExp; - protected hasNvccOpcodeRe: RegExp; - protected definesFunction: RegExp; - protected definesGlobal: RegExp; - protected definesWeak: RegExp; - protected definesAlias: RegExp; - protected indentedLabelDef: RegExp; - protected assignmentDef: RegExp; - protected setDef: RegExp; - protected directive: RegExp; - protected startAppBlock: RegExp; - protected endAppBlock: RegExp; - protected startAsmNesting: RegExp; - protected endAsmNesting: RegExp; - protected cudaBeginDef: RegExp; - protected cudaEndDef: RegExp; - protected binaryHideFuncRe: RegExp | null; - protected asmOpcodeRe: RegExp; - protected relocationRe: RegExp; - protected relocDataSymNameRe: RegExp; - protected lineRe: RegExp; - protected labelRe: RegExp; - protected destRe: RegExp; - protected commentRe: RegExp; - protected instOpcodeRe: RegExp; - protected commentOnly: RegExp; - protected commentOnlyNvcc: RegExp; - protected sourceTag: RegExp; - protected sourceD2Tag: RegExp; - protected sourceCVTag: RegExp; - protected source6502Dbg: RegExp; - protected source6502DbgEnd: RegExp; - protected sourceStab: RegExp; - protected stdInLooking: RegExp; - protected endBlock: RegExp; - protected blockComments: RegExp; - - private updateParsingState(line: string, context: ParsingContext) { - if (this.startAppBlock.test(line.trim()) || this.startAsmNesting.test(line.trim())) { - this.parsingState.enterCustomAssembly(); - } else if (this.endAppBlock.test(line.trim()) || this.endAsmNesting.test(line.trim())) { - this.parsingState.exitCustomAssembly(); - } else { - this.parsingState.setVLIWPacket(this.checkVLIWpacket(line, this.parsingState.inVLIWpacket)); - } - - this.handleSource(context, line); - this.handleStabs(context, line); - this.handle6502(context, line); - - this.parsingState.updateSource(context.source); - - if (this.endBlock.test(line) || (this.parsingState.inNvccCode && /}/.test(line))) { - context.source = null; - context.prevLabel = ''; - this.parsingState.resetToBlockEnd(); - } - } - - private shouldSkipDirective( - line: string, - filters: ParseFiltersAndOutputOptions, - context: ParsingContext, - match: RegExpMatchArray | null, - ): boolean { - if (this.parsingState.inNvccDef) { - if (this.cudaEndDef.test(line)) this.parsingState.exitNvccDef(); - return false; - } - - if (!match && filters.directives) { - // Check for directives only if it wasn't a label; the regexp would otherwise misinterpret labels as directives. - if (this.dataDefn.test(line) && context.prevLabel) { - // We're defining data that's being used somewhere. - return false; - } - // .inst generates an opcode, so does not count as a directive, nor does an alias definition that's used. - if ( - this.directive.test(line) && - !this.instOpcodeRe.test(line) && - !this.definesAlias.test(line) && - !this.setDef.test(line) - ) { - return true; - } - } - - return false; - } - - private processLabelDefinition( - line: string, - filters: ParseFiltersAndOutputOptions, - context: ParsingContext, - asmLines: string[], - labelsUsed: Set, - labelDefinitions: Record, - asmLength: number, - ): {match: RegExpMatchArray | null; skipLine: boolean} { - let match = line.match(this.labelDef); - if (!match) match = line.match(this.assignmentDef); - let isSetDef = false; - if (!match) { - match = line.match(this.setDef); - isSetDef = !!match; - } - if (!match) { - match = line.match(this.cudaBeginDef); - if (match) { - this.parsingState.enterNvccDef(); - } - } - - if (!match) { - return {match: null, skipLine: false}; - } - - // It's a label definition. g-as shows local labels as eg: "1: call mcount". We characterize such a label - // as "the label-matching part doesn't equal the whole line" and treat it as used. As a special case, - // consider assignments of the form "symbol = ." to be labels. - if (!labelsUsed.has(match[1]) && match[0] === line && (match[2] === undefined || match[2].trim() === '.')) { - // It's an unused label. - if (filters.labels) { - context.prevLabel = ''; - return {match, skipLine: true}; - } - } else { - // A used label. - labelDefinitions[match[1]] = asmLength + 1; - - if (isSetDef) { - // `.set` does not start a new function - return {match: null, skipLine: false}; - } - - context.prevLabel = match[1]; - - if (!this.parsingState.inNvccDef && !this.parsingState.inNvccCode && filters.libraryCode) { - context.prevLabelIsUserFunction = this.isUserFunctionByLookingAhead( - context, - asmLines, - this.parsingState.getCurrentLineIndex(), - ); - } - } - - return {match, skipLine: false}; - } - - private processAllLines( - filters: ParseFiltersAndOutputOptions, - context: ParsingContext, - asmLines: string[], - labelsUsed: Set, - ): {asm: ParsedAsmResultLine[]; labelDefinitions: Record} { - const asm: ParsedAsmResultLine[] = []; - const labelDefinitions: Record = {}; - for (let line of this.parsingState) { - if (line.trim() === '') { - maybeAddBlank(asm); - continue; - } - - this.updateParsingState(line, context); - - if (this.shouldSkipLibraryCode(filters, context, asm, labelDefinitions)) { - continue; - } - - if (this.shouldSkipCommentOnlyLine(filters, line)) { - continue; - } - - if (this.parsingState.isInCustomAssembly()) line = this.fixLabelIndentation(line); - - const labelResult = this.processLabelDefinition( - line, - filters, - context, - asmLines, - labelsUsed, - labelDefinitions, - asm.length, - ); - const match = labelResult.match; - if (labelResult.skipLine) { - continue; - } - - if (this.shouldSkipDirective(line, filters, context, match)) { - continue; - } - - line = utils.expandTabs(line); - const text = AsmRegex.filterAsmLine(line, filters); - - const labelsInLine = match ? [] : this.getUsedLabelsInLine(text); - - asm.push({ - text: text, - source: this.hasOpcode(line, this.parsingState.inNvccCode, this.parsingState.inVLIWpacket) - ? context.source || null - : null, - labels: labelsInLine, - }); - } - - return {asm, labelDefinitions}; - } - - private shouldSkipCommentOnlyLine(filters: ParseFiltersAndOutputOptions, line: string): boolean { - if (this.labelDef.test(line)) { - return false; - } - return Boolean( - filters.commentOnly && - ((this.commentOnly.test(line) && !this.parsingState.inNvccCode) || - (this.commentOnlyNvcc.test(line) && this.parsingState.inNvccCode)), - ); - } - - private shouldSkipLibraryCode( - filters: ParseFiltersAndOutputOptions, - context: ParsingContext, - asm: ParsedAsmResultLine[], - labelDefinitions: Record, - ): boolean { - // Only filter library code if user enabled it AND we're not currently in a user function - const doLibraryFilterCheck = filters.libraryCode && !context.prevLabelIsUserFunction; - - // Don't skip if any of these conditions indicate this is user code or filtering is disabled - if ( - !doLibraryFilterCheck || // Library filtering disabled or we're in user function - this.parsingState.lastOwnSource || // We recently processed user source code - !context.source || // No source information available - context.source.file === null || // Main source file (user code) - context.source.mainsource // Explicitly marked as main source - ) { - // We're in user code, so future labels might need removal if we transition to library code - this.parsingState.setMayRemovePreviousLabel(true); - return false; - } - - // We're in library code that should be filtered. Handle "orphaned labels" that precede filtered code. - // When we start filtering library code, we might have just output a label that will now be orphaned. - if (this.parsingState.shouldRemovePreviousLabel() && asm.length > 0) { - const lastLine = asm[asm.length - 1]; - const labelDef = lastLine.text ? lastLine.text.match(this.labelDef) : null; - - if (labelDef) { - // Last line was a label - it's now orphaned, so remove it retroactively - asm.pop(); - this.parsingState.setKeepInlineCode(false); - delete labelDefinitions[labelDef[1]]; - } else { - // Last line wasn't a label - there's user code mixed in, so keep showing library code - this.parsingState.setKeepInlineCode(true); - } - // Don't try to remove labels again until we transition back to user code - this.parsingState.setMayRemovePreviousLabel(false); - } - - // Skip this line unless we determined there's user code mixed in (keepInlineCode=true) - return !this.parsingState.shouldKeepInlineCode(); - } - - constructor(compilerProps?: PropertyGetter) { - super(); - - this.sourceLineHandler = new SourceLineHandler(); - this.labelProcessor = new LabelProcessor(); - this.parsingState = new ParsingState({}, null, '', false, false, []); - - this.labelFindNonMips = /[.A-Z_a-z][\w$.]*|"[.A-Z_a-z][\w$.]*"/g; - // MIPS labels can start with a $ sign, but other assemblers use $ to mean literal. - this.labelFindMips = /[$.A-Z_a-z][\w$.]*|"[$.A-Z_a-z][\w$.]*"/g; - this.mipsLabelDefinition = /^\$[\w$.]+:/; - this.dataDefn = - /^\s*\.(ascii|asciz|base64|[1248]?byte|dc(?:\.[abdlswx])?|dcb(?:\.[bdlswx])?|ds(?:\.[bdlpswx])?|double|dword|fill|float|half|hword|int|long|octa|quad|short|single|skip|space|string(?:8|16|32|64)?|value|word|xword|zero)/; - this.fileFind = /^\s*\.(?:cv_)?file\s+(\d+)\s+"([^"]+)"(\s+"([^"]+)")?.*/; - // Opcode expression here matches LLVM-style opcodes of the form `%blah = opcode` - this.hasOpcodeRe = /^\s*(%[$.A-Z_a-z][\w$.]*\s*=\s*)?[A-Za-z]/; - this.instructionRe = /^\s*[A-Za-z]+/; - this.identifierFindRe = /((?!\$\.)[$.@A-Z_a-z"][\w$.]*"?)(?:@\w+)*/g; - this.hasNvccOpcodeRe = /^\s*[@A-Za-z|]/; - this.definesFunction = /^\s*\.(type.*,\s*[#%@]function|proc\s+[.A-Z_a-z][\w$.]*:.*)$/; - this.definesGlobal = /^\s*\.(?:globa?l|GLB|export)\s*([.A-Z_a-z][\w$.]*|"[.A-Z_a-z][\w$.]*")/; - this.definesWeak = /^\s*\.(?:weakext|weak)\s*([.A-Z_a-z][\w$.]*|"[.A-Z_a-z][\w$.]*")/; - this.definesAlias = /^\s*\.set\s*((?:[.A-Z_a-z][\w$.]*|"[.A-Z_a-z][\w$.]*")\s*),\s*\.\s*(\+\s*0)?$/; - this.indentedLabelDef = /^\s*([$.A-Z_a-z][\w$.]*|"[$.A-Z_a-z][\w$.]*"):/; - this.assignmentDef = /^\s*([$.A-Z_a-z][\w$.]*)\s*=\s*(.*)/; - // ".set label, label" where "label" is `this.labelFindNonMips` - this.setDef = - /^\s*\.set\s+([.A-Z_a-z][\w$.]*|"[.A-Z_a-z][\w$.]*"),\s*(?:[.A-Z_a-z][\w$.]*|"[.A-Z_a-z][\w$.]*")\s*$/; - this.directive = /^\s*\..*$/; - // These four regexes when phrased as /\s*#APP.*/ etc exhibit costly polynomial backtracking. Instead use ^$ and - // test with regex.test(line.trim()), more robust anyway - this.startAppBlock = /^#APP.*$/; - this.endAppBlock = /^#NO_APP.*$/; - this.startAsmNesting = /^# Begin ASM.*$/; - this.endAsmNesting = /^# End ASM.*$/; - this.cudaBeginDef = /\.(entry|func)\s+(?:\([^)]*\)\s*)?([$.A-Z_a-z][\w$.]*)\($/; - this.cudaEndDef = /^\s*\)\s*$/; - - this.binaryHideFuncRe = null; - this.maxAsmLines = 5000; - if (compilerProps) { - const binaryHideFuncReValue = compilerProps('binaryHideFuncRe'); - if (binaryHideFuncReValue) { - assert(isString(binaryHideFuncReValue)); - this.binaryHideFuncRe = new RegExp(binaryHideFuncReValue); - } - - this.maxAsmLines = compilerProps('maxLinesOfAsm', this.maxAsmLines); - } - - this.asmOpcodeRe = /^\s*(?
[\da-f]+):\s*(?([\da-f]{2} ?)+)\s*(?.*)/; - this.relocationRe = /^\s*(?
[\da-f]+):\s*(?(R_[\dA-Z_]+))\s*(?.*)/; - this.relocDataSymNameRe = /^(?[^\d-+][\w.]*)?\s*(?.*)$/; - if (process.platform === 'win32') { - this.lineRe = /^([A-Z]:\/[^:]+):(?\d+).*/; - } else { - this.lineRe = /^(\/[^:]+):(?\d+).*/; - } - - // labelRe is made very greedy as it's also used with demangled objdump output (eg. it can have c++ template with <>). - this.labelRe = /^([\da-f]+)\s+<(.+)>:$/; - this.destRe = /\s([\da-f]+)\s+<([^+>]+)(\+0x[\da-f]+)?>$/; - this.commentRe = /[#;]/; - this.instOpcodeRe = /(\.inst\.?\w?)\s*(.*)/; - - // Lines matching the following pattern are considered comments: - // - starts with '#', '@', '//' or a single ';' (non repeated) - // - starts with ';;' and the first non-whitespace before end of line is not # - this.commentOnly = /^\s*(((#|@|\/\/).*)|(\/\*.*\*\/)|(;\s*)|(;[^;].*)|(;;\s*[^\s#].*))$/; - this.commentOnlyNvcc = /^\s*(((#|;|\/\/).*)|(\/\*.*\*\/))$/; - this.sourceTag = /^\s*\.loc\s+(\d+)\s+(\d+)\s+(.*)/; - this.sourceD2Tag = /^\s*\.d2line\s+(\d+),?\s*(\d*).*/; - this.sourceCVTag = /^\s*\.cv_loc\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+).*/; - this.source6502Dbg = /^\s*\.dbg\s+line,\s*"([^"]+)",\s*(\d+)/; - this.source6502DbgEnd = /^\s*\.dbg\s+line[^,]/; - this.sourceStab = /^\s*\.stabn\s+(\d+),0,(\d+),.*/; - this.stdInLooking = /|^-$|example\.[^/]+$|/; - this.endBlock = /\.(cfi_endproc|data|text|section)/; - this.blockComments = /^[\t ]*\/\*(\*(?!\/)|[^*])*\*\/\s*/gm; - } - - checkVLIWpacket(_line: string, inVLIWpacket: boolean) { - return inVLIWpacket; - } - - hasOpcode(line: string, inNvccCode = false, _inVLIWpacket = false) { - // Remove any leading label definition... - const match = line.match(this.labelDef); - if (match) { - line = line.substring(match[0].length); - } - // Strip any comments - line = line.split(this.commentRe, 1)[0]; - // .inst generates an opcode, so also counts - if (this.instOpcodeRe.test(line)) return true; - // Detect assignment, that's not an opcode... - if (this.assignmentDef.test(line)) return false; - if (this.setDef.test(line)) return false; - if (inNvccCode) { - return this.hasNvccOpcodeRe.test(line); - } - return this.hasOpcodeRe.test(line); - } - - private createLabelContext(): LabelContext { - return { - hasOpcode: this.hasOpcode.bind(this), - checkVLIWpacket: this.checkVLIWpacket.bind(this), - labelDef: this.labelDef, - dataDefn: this.dataDefn, - commentRe: this.commentRe, - instructionRe: this.instructionRe, - identifierFindRe: this.identifierFindRe, - definesGlobal: this.definesGlobal, - definesWeak: this.definesWeak, - definesAlias: this.definesAlias, - definesFunction: this.definesFunction, - cudaBeginDef: this.cudaBeginDef, - startAppBlock: this.startAppBlock, - endAppBlock: this.endAppBlock, - startAsmNesting: this.startAsmNesting, - endAsmNesting: this.endAsmNesting, - mipsLabelDefinition: this.mipsLabelDefinition, - labelFindNonMips: this.labelFindNonMips, - labelFindMips: this.labelFindMips, - fixLabelIndentation: this.fixLabelIndentation.bind(this), - }; - } - - findUsedLabels(asmLines: string[], filterDirectives?: boolean): Set { - return this.labelProcessor.findUsedLabels(asmLines, filterDirectives || false, this.createLabelContext()); - } - - parseFiles(asmLines: string[]) { - const files: Record = {}; - for (const line of asmLines) { - const match = line.match(this.fileFind); - if (!match) continue; - - const lineNum = Number.parseInt(match[1], 10); - if (match[4] && !line.includes('.cv_file')) { - // Clang-style file directive '.file X "dir" "filename"' - if (match[4].startsWith('/')) { - files[lineNum] = match[4]; - } else { - files[lineNum] = match[2] + '/' + match[4]; - } - } else { - files[lineNum] = match[2]; - } - } - return files; - } - - removeLabelsWithoutDefinition(asm: ParsedAsmResultLine[], labelDefinitions: Record) { - this.labelProcessor.removeLabelsWithoutDefinition(asm, labelDefinitions); - } - - getUsedLabelsInLine(line: string): AsmResultLabel[] { - return this.labelProcessor.getUsedLabelsInLine(line, this.createLabelContext()); - } - - protected isUserFunctionByLookingAhead(context: ParsingContext, asmLines: string[], idxFrom: number): boolean { - const funcContext: ParsingContext = { - files: context.files, - source: undefined, - dontMaskFilenames: true, - prevLabelIsUserFunction: false, - prevLabel: '', - }; - - for (let idx = idxFrom; idx < asmLines.length; idx++) { - const line = asmLines[idx]; - - const endprocMatch = line.match(this.endBlock); - if (endprocMatch) return false; - - this.handleSource(funcContext, line); - this.handleStabs(funcContext, line); - this.handle6502(funcContext, line); - - if (funcContext.source?.mainsource) return true; - } - - return false; - } - - protected handleSource(context: ParsingContext, line: string) { - const sourceContext: SourceHandlerContext = { - files: context.files, - dontMaskFilenames: context.dontMaskFilenames, - }; - - const result = this.sourceLineHandler.processSourceLine(line, sourceContext); - if (result.source !== undefined) context.source = result.source; - if (result.resetPrevLabel) context.prevLabel = ''; - } - - protected handleStabs(context: ParsingContext, line: string) { - const sourceContext: SourceHandlerContext = { - files: context.files, - dontMaskFilenames: context.dontMaskFilenames, - }; - - const result = this.sourceLineHandler.processSourceLine(line, sourceContext); - if (result.source !== undefined) context.source = result.source; - if (result.resetPrevLabel) context.prevLabel = ''; - } - - protected handle6502(context: ParsingContext, line: string) { - const sourceContext: SourceHandlerContext = { - files: context.files, - dontMaskFilenames: context.dontMaskFilenames, - }; - - const result = this.sourceLineHandler.processSourceLine(line, sourceContext); - if (result.source !== undefined) context.source = result.source; - if (result.resetPrevLabel) context.prevLabel = ''; - } - - processAsm(asmResult: string, filters: ParseFiltersAndOutputOptions): ParsedAsmResult { - if (filters.binary || filters.binaryObject) return this.processBinaryAsm(asmResult, filters); - - const startTime = process.hrtime.bigint(); - - if (filters.commentOnly) { - // Remove any block comments that start and end on a line if we're removing comment-only lines. - asmResult = asmResult.replace(this.blockComments, ''); - } - - let asmLines = utils.splitLines(asmResult); - const startingLineCount = asmLines.length; - if (filters.preProcessLines) asmLines = filters.preProcessLines(asmLines); - - const labelsUsed = this.findUsedLabels(asmLines, filters.directives); - - const files = this.parseFiles(asmLines); - this.parsingState = new ParsingState(files, null, '', false, filters.dontMaskFilenames || false, asmLines); - - const context: ParsingContext = { - files: files, - source: null, - prevLabel: '', - prevLabelIsUserFunction: false, - dontMaskFilenames: filters.dontMaskFilenames || false, - }; - - const {asm, labelDefinitions} = this.processAllLines(filters, context, asmLines, labelsUsed); - - this.removeLabelsWithoutDefinition(asm, labelDefinitions); - - const endTime = process.hrtime.bigint(); - return { - asm: asm, - labelDefinitions: labelDefinitions, - parsingTime: utils.deltaTimeNanoToMili(startTime, endTime), - filteredCount: startingLineCount - asm.length, - }; - } - - fixLabelIndentation(line: string) { - const match = line.match(this.indentedLabelDef); - return match ? line.replace(/^\s+/, '') : line; - } - - isUserFunction(func: string) { - if (this.binaryHideFuncRe === null) return true; - - return !this.binaryHideFuncRe.test(func); - } - - processBinaryAsm(asmResult: string, filters: ParseFiltersAndOutputOptions): ParsedAsmResult { - const startTime = process.hrtime.bigint(); - const asm: ParsedAsmResultLine[] = []; - const labelDefinitions: Record = {}; - const dontMaskFilenames = filters.dontMaskFilenames; - - let asmLines = utils.splitLines(asmResult); - const startingLineCount = asmLines.length; - let source: AsmResultSource | undefined | null = null; - let func: string | null = null; - let mayRemovePreviousLabel = true; - - // Handle "error" documents. - if (asmLines.length === 1 && asmLines[0][0] === '<') { - return { - asm: [{text: asmLines[0], source: null}], - }; - } - - if (filters.preProcessBinaryAsmLines) asmLines = filters.preProcessBinaryAsmLines(asmLines); - - // Parse .file directives to build file number -> filename mapping - const files = this.parseFiles(asmLines); - const sourceContext: SourceHandlerContext = { - files: files, - dontMaskFilenames: dontMaskFilenames || false, - }; - - for (const line of asmLines) { - const labelsInLine: AsmResultLabel[] = []; - - if (asm.length >= this.maxAsmLines) { - if (asm.length === this.maxAsmLines) { - asm.push({ - text: '[truncated; too many lines]', - source: null, - labels: labelsInLine, - }); - } - continue; - } - let match = line.match(this.lineRe); - if (match) { - assert(match.groups); - if (dontMaskFilenames) { - source = { - file: utils.maskRootdir(match[1]), - line: Number.parseInt(match.groups.line, 10), - mainsource: true, - }; - } else { - source = {file: null, line: Number.parseInt(match.groups.line, 10), mainsource: true}; - } - continue; - } - - // Handle .file and .loc directives (DWARF debug info) - const sourceResult = this.sourceLineHandler.processSourceLine(line, sourceContext); - if (sourceResult.source !== undefined) { - source = sourceResult.source; - if (source && asm.length < 3) { - console.log(`[AsmParser] Parsed directive: file="${source.file}" line=${source.line} mainsource=${source.mainsource}`); - } - continue; // Don't display the directive itself - } - - match = line.match(this.labelRe); - if (match) { - func = match[2]; - if (func && this.isUserFunction(func)) { - asm.push({ - text: func + ':', - source: null, - labels: labelsInLine, - }); - labelDefinitions[func] = asm.length; - if (process.platform === 'win32') source = null; - } - continue; - } - - if (func && line === `${func}():`) continue; - - if (!func || !this.isUserFunction(func)) continue; - - // note: normally the source.file will be null if it's code from example.ext but with - // filters.dontMaskFilenames it will be filled with the actual filename instead we can test - // source.mainsource in that situation - const isMainsource = source && (source.file === null || source.mainsource); - if (filters.libraryCode && !isMainsource) { - if (mayRemovePreviousLabel && asm.length > 0) { - const lastLine = asm[asm.length - 1]; - if (lastLine.text && this.labelDef.test(lastLine.text)) { - asm.pop(); - } - mayRemovePreviousLabel = false; - } - continue; - } - mayRemovePreviousLabel = true; - - match = line.match(this.asmOpcodeRe); - if (match) { - assert(match.groups); - const address = Number.parseInt(match.groups.address, 16); - const opcodes = (match.groups.opcodes || '').split(' ').filter(x => !!x); - const disassembly = ' ' + AsmRegex.filterAsmLine(match.groups.disasm, filters); - const destMatch = line.match(this.destRe); - if (destMatch) { - const labelName = destMatch[2]; - const startCol = disassembly.indexOf(labelName) + 1; - labelsInLine.push({ - name: labelName, - range: { - startCol: startCol, - endCol: startCol + labelName.length, - }, - }); - } - asm.push({ - opcodes: opcodes, - address: address, - text: disassembly, - source: source, - labels: labelsInLine, - }); - } - - match = line.match(this.relocationRe); - if (match) { - assert(match.groups); - const address = Number.parseInt(match.groups.address, 16); - const relocname = match.groups.relocname; - const relocdata = match.groups.relocdata; - // value/addend matched but not used yet. - // const match_value = relocdata.match(this.relocDataSymNameRe); - asm.push({ - text: ` ${relocname} ${relocdata}`, - address: address, - }); - } - } - - this.removeLabelsWithoutDefinition(asm, labelDefinitions); - - const endTime = process.hrtime.bigint(); - - return { - asm: asm, - labelDefinitions: labelDefinitions, - parsingTime: utils.deltaTimeNanoToMili(startTime, endTime), - filteredCount: startingLineCount - asm.length, - }; - } - - process(asm: string, filters: ParseFiltersAndOutputOptions) { - return this.processAsm(asm, filters); - } -} +// Copyright (c) 2015, Compiler Explorer Authors +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import {isString} from '../../shared/common-utils.js'; +import { + AsmResultLabel, + AsmResultSource, + ParsedAsmResult, + ParsedAsmResultLine, +} from '../../types/asmresult/asmresult.interfaces.js'; +import {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js'; +import {assert} from '../assert.js'; +import {PropertyGetter} from '../properties.interfaces.js'; +import * as utils from '../utils.js'; + +import {IAsmParser} from './asm-parser.interfaces.js'; +import {AsmRegex} from './asmregex.js'; +import {LabelContext, LabelProcessor} from './label-processor.js'; +import {ParsingState} from './parsing-state.js'; +import {SourceHandlerContext, SourceLineHandler} from './source-line-handler.js'; + +function maybeAddBlank(asm: ParsedAsmResultLine[]) { + const lastBlank = asm.length === 0 || asm[asm.length - 1].text === ''; + if (!lastBlank) asm.push({text: '', source: null, labels: []}); +} + +export type ParsingContext = { + files: Record; + source: AsmResultSource | undefined | null; + dontMaskFilenames: boolean; + prevLabel: string; + prevLabelIsUserFunction: boolean; +}; + +export class AsmParser extends AsmRegex implements IAsmParser { + protected sourceLineHandler: SourceLineHandler; + protected labelProcessor: LabelProcessor; + protected parsingState: ParsingState; + + protected maxAsmLines: number; + + protected labelFindNonMips: RegExp; + protected labelFindMips: RegExp; + protected mipsLabelDefinition: RegExp; + protected dataDefn: RegExp; + protected fileFind: RegExp; + protected hasOpcodeRe: RegExp; + protected instructionRe: RegExp; + protected identifierFindRe: RegExp; + protected hasNvccOpcodeRe: RegExp; + protected definesFunction: RegExp; + protected definesGlobal: RegExp; + protected definesWeak: RegExp; + protected definesAlias: RegExp; + protected indentedLabelDef: RegExp; + protected assignmentDef: RegExp; + protected setDef: RegExp; + protected directive: RegExp; + protected startAppBlock: RegExp; + protected endAppBlock: RegExp; + protected startAsmNesting: RegExp; + protected endAsmNesting: RegExp; + protected cudaBeginDef: RegExp; + protected cudaEndDef: RegExp; + protected binaryHideFuncRe: RegExp | null; + protected asmOpcodeRe: RegExp; + protected relocationRe: RegExp; + protected relocDataSymNameRe: RegExp; + protected lineRe: RegExp; + protected labelRe: RegExp; + protected destRe: RegExp; + protected commentRe: RegExp; + protected instOpcodeRe: RegExp; + protected commentOnly: RegExp; + protected commentOnlyNvcc: RegExp; + protected sourceTag: RegExp; + protected sourceD2Tag: RegExp; + protected sourceCVTag: RegExp; + protected source6502Dbg: RegExp; + protected source6502DbgEnd: RegExp; + protected sourceStab: RegExp; + protected stdInLooking: RegExp; + protected endBlock: RegExp; + protected blockComments: RegExp; + + private updateParsingState(line: string, context: ParsingContext) { + if (this.startAppBlock.test(line.trim()) || this.startAsmNesting.test(line.trim())) { + this.parsingState.enterCustomAssembly(); + } else if (this.endAppBlock.test(line.trim()) || this.endAsmNesting.test(line.trim())) { + this.parsingState.exitCustomAssembly(); + } else { + this.parsingState.setVLIWPacket(this.checkVLIWpacket(line, this.parsingState.inVLIWpacket)); + } + + this.handleSource(context, line); + this.handleStabs(context, line); + this.handle6502(context, line); + + this.parsingState.updateSource(context.source); + + if (this.endBlock.test(line) || (this.parsingState.inNvccCode && /}/.test(line))) { + context.source = null; + context.prevLabel = ''; + this.parsingState.resetToBlockEnd(); + } + } + + private shouldSkipDirective( + line: string, + filters: ParseFiltersAndOutputOptions, + context: ParsingContext, + match: RegExpMatchArray | null, + ): boolean { + if (this.parsingState.inNvccDef) { + if (this.cudaEndDef.test(line)) this.parsingState.exitNvccDef(); + return false; + } + + if (!match && filters.directives) { + // Check for directives only if it wasn't a label; the regexp would otherwise misinterpret labels as directives. + if (this.dataDefn.test(line) && context.prevLabel) { + // We're defining data that's being used somewhere. + return false; + } + // .inst generates an opcode, so does not count as a directive, nor does an alias definition that's used. + if ( + this.directive.test(line) && + !this.instOpcodeRe.test(line) && + !this.definesAlias.test(line) && + !this.setDef.test(line) + ) { + return true; + } + } + + return false; + } + + private processLabelDefinition( + line: string, + filters: ParseFiltersAndOutputOptions, + context: ParsingContext, + asmLines: string[], + labelsUsed: Set, + labelDefinitions: Record, + asmLength: number, + ): {match: RegExpMatchArray | null; skipLine: boolean} { + let match = line.match(this.labelDef); + if (!match) match = line.match(this.assignmentDef); + let isSetDef = false; + if (!match) { + match = line.match(this.setDef); + isSetDef = !!match; + } + if (!match) { + match = line.match(this.cudaBeginDef); + if (match) { + this.parsingState.enterNvccDef(); + } + } + + if (!match) { + return {match: null, skipLine: false}; + } + + // It's a label definition. g-as shows local labels as eg: "1: call mcount". We characterize such a label + // as "the label-matching part doesn't equal the whole line" and treat it as used. As a special case, + // consider assignments of the form "symbol = ." to be labels. + if (!labelsUsed.has(match[1]) && match[0] === line && (match[2] === undefined || match[2].trim() === '.')) { + // It's an unused label. + if (filters.labels) { + context.prevLabel = ''; + return {match, skipLine: true}; + } + } else { + // A used label. + labelDefinitions[match[1]] = asmLength + 1; + + if (isSetDef) { + // `.set` does not start a new function + return {match: null, skipLine: false}; + } + + context.prevLabel = match[1]; + + if (!this.parsingState.inNvccDef && !this.parsingState.inNvccCode && filters.libraryCode) { + context.prevLabelIsUserFunction = this.isUserFunctionByLookingAhead( + context, + asmLines, + this.parsingState.getCurrentLineIndex(), + ); + } + } + + return {match, skipLine: false}; + } + + private processAllLines( + filters: ParseFiltersAndOutputOptions, + context: ParsingContext, + asmLines: string[], + labelsUsed: Set, + ): {asm: ParsedAsmResultLine[]; labelDefinitions: Record} { + const asm: ParsedAsmResultLine[] = []; + const labelDefinitions: Record = {}; + for (let line of this.parsingState) { + if (line.trim() === '') { + maybeAddBlank(asm); + continue; + } + + this.updateParsingState(line, context); + + if (this.shouldSkipLibraryCode(filters, context, asm, labelDefinitions)) { + continue; + } + + if (this.shouldSkipCommentOnlyLine(filters, line)) { + continue; + } + + if (this.parsingState.isInCustomAssembly()) line = this.fixLabelIndentation(line); + + const labelResult = this.processLabelDefinition( + line, + filters, + context, + asmLines, + labelsUsed, + labelDefinitions, + asm.length, + ); + const match = labelResult.match; + if (labelResult.skipLine) { + continue; + } + + if (this.shouldSkipDirective(line, filters, context, match)) { + continue; + } + + line = utils.expandTabs(line); + const text = AsmRegex.filterAsmLine(line, filters); + + const labelsInLine = match ? [] : this.getUsedLabelsInLine(text); + + asm.push({ + text: text, + source: this.hasOpcode(line, this.parsingState.inNvccCode, this.parsingState.inVLIWpacket) + ? context.source || null + : null, + labels: labelsInLine, + }); + } + + return {asm, labelDefinitions}; + } + + private shouldSkipCommentOnlyLine(filters: ParseFiltersAndOutputOptions, line: string): boolean { + if (this.labelDef.test(line)) { + return false; + } + return Boolean( + filters.commentOnly && + ((this.commentOnly.test(line) && !this.parsingState.inNvccCode) || + (this.commentOnlyNvcc.test(line) && this.parsingState.inNvccCode)), + ); + } + + private shouldSkipLibraryCode( + filters: ParseFiltersAndOutputOptions, + context: ParsingContext, + asm: ParsedAsmResultLine[], + labelDefinitions: Record, + ): boolean { + // Only filter library code if user enabled it AND we're not currently in a user function + const doLibraryFilterCheck = filters.libraryCode && !context.prevLabelIsUserFunction; + + // Don't skip if any of these conditions indicate this is user code or filtering is disabled + if ( + !doLibraryFilterCheck || // Library filtering disabled or we're in user function + this.parsingState.lastOwnSource || // We recently processed user source code + !context.source || // No source information available + context.source.file === null || // Main source file (user code) + context.source.mainsource // Explicitly marked as main source + ) { + // We're in user code, so future labels might need removal if we transition to library code + this.parsingState.setMayRemovePreviousLabel(true); + return false; + } + + // We're in library code that should be filtered. Handle "orphaned labels" that precede filtered code. + // When we start filtering library code, we might have just output a label that will now be orphaned. + if (this.parsingState.shouldRemovePreviousLabel() && asm.length > 0) { + const lastLine = asm[asm.length - 1]; + const labelDef = lastLine.text ? lastLine.text.match(this.labelDef) : null; + + if (labelDef) { + // Last line was a label - it's now orphaned, so remove it retroactively + asm.pop(); + this.parsingState.setKeepInlineCode(false); + delete labelDefinitions[labelDef[1]]; + } else { + // Last line wasn't a label - there's user code mixed in, so keep showing library code + this.parsingState.setKeepInlineCode(true); + } + // Don't try to remove labels again until we transition back to user code + this.parsingState.setMayRemovePreviousLabel(false); + } + + // Skip this line unless we determined there's user code mixed in (keepInlineCode=true) + return !this.parsingState.shouldKeepInlineCode(); + } + + constructor(compilerProps?: PropertyGetter) { + super(); + + this.sourceLineHandler = new SourceLineHandler(); + this.labelProcessor = new LabelProcessor(); + this.parsingState = new ParsingState({}, null, '', false, false, []); + + this.labelFindNonMips = /[.A-Z_a-z][\w$.]*|"[.A-Z_a-z][\w$.]*"/g; + // MIPS labels can start with a $ sign, but other assemblers use $ to mean literal. + this.labelFindMips = /[$.A-Z_a-z][\w$.]*|"[$.A-Z_a-z][\w$.]*"/g; + this.mipsLabelDefinition = /^\$[\w$.]+:/; + this.dataDefn = + /^\s*\.(ascii|asciz|base64|[1248]?byte|dc(?:\.[abdlswx])?|dcb(?:\.[bdlswx])?|ds(?:\.[bdlpswx])?|double|dword|fill|float|half|hword|int|long|octa|quad|short|single|skip|space|string(?:8|16|32|64)?|value|word|xword|zero)/; + this.fileFind = /^\s*\.(?:cv_)?file\s+(\d+)\s+"([^"]+)"(\s+"([^"]+)")?.*/; + // Opcode expression here matches LLVM-style opcodes of the form `%blah = opcode` + this.hasOpcodeRe = /^\s*(%[$.A-Z_a-z][\w$.]*\s*=\s*)?[A-Za-z]/; + this.instructionRe = /^\s*[A-Za-z]+/; + this.identifierFindRe = /((?!\$\.)[$.@A-Z_a-z"][\w$.]*"?)(?:@\w+)*/g; + this.hasNvccOpcodeRe = /^\s*[@A-Za-z|]/; + this.definesFunction = /^\s*\.(type.*,\s*[#%@]function|proc\s+[.A-Z_a-z][\w$.]*:.*)$/; + this.definesGlobal = /^\s*\.(?:globa?l|GLB|export)\s*([.A-Z_a-z][\w$.]*|"[.A-Z_a-z][\w$.]*")/; + this.definesWeak = /^\s*\.(?:weakext|weak)\s*([.A-Z_a-z][\w$.]*|"[.A-Z_a-z][\w$.]*")/; + this.definesAlias = /^\s*\.set\s*((?:[.A-Z_a-z][\w$.]*|"[.A-Z_a-z][\w$.]*")\s*),\s*\.\s*(\+\s*0)?$/; + this.indentedLabelDef = /^\s*([$.A-Z_a-z][\w$.]*|"[$.A-Z_a-z][\w$.]*"):/; + this.assignmentDef = /^\s*([$.A-Z_a-z][\w$.]*)\s*=\s*(.*)/; + // ".set label, label" where "label" is `this.labelFindNonMips` + this.setDef = + /^\s*\.set\s+([.A-Z_a-z][\w$.]*|"[.A-Z_a-z][\w$.]*"),\s*(?:[.A-Z_a-z][\w$.]*|"[.A-Z_a-z][\w$.]*")\s*$/; + this.directive = /^\s*\..*$/; + // These four regexes when phrased as /\s*#APP.*/ etc exhibit costly polynomial backtracking. Instead use ^$ and + // test with regex.test(line.trim()), more robust anyway + this.startAppBlock = /^#APP.*$/; + this.endAppBlock = /^#NO_APP.*$/; + this.startAsmNesting = /^# Begin ASM.*$/; + this.endAsmNesting = /^# End ASM.*$/; + this.cudaBeginDef = /\.(entry|func)\s+(?:\([^)]*\)\s*)?([$.A-Z_a-z][\w$.]*)\($/; + this.cudaEndDef = /^\s*\)\s*$/; + + this.binaryHideFuncRe = null; + this.maxAsmLines = 5000; + if (compilerProps) { + const binaryHideFuncReValue = compilerProps('binaryHideFuncRe'); + if (binaryHideFuncReValue) { + assert(isString(binaryHideFuncReValue)); + this.binaryHideFuncRe = new RegExp(binaryHideFuncReValue); + } + + this.maxAsmLines = compilerProps('maxLinesOfAsm', this.maxAsmLines); + } + + this.asmOpcodeRe = /^\s*(?
[\da-f]+):\s*(?([\da-f]{2} ?)+)\s*(?.*)/; + this.relocationRe = /^\s*(?
[\da-f]+):\s*(?(R_[\dA-Z_]+))\s*(?.*)/; + this.relocDataSymNameRe = /^(?[^\d-+][\w.]*)?\s*(?.*)$/; + if (process.platform === 'win32') { + this.lineRe = /^([A-Z]:\/[^:]+):(?\d+).*/; + } else { + this.lineRe = /^(\/[^:]+):(?\d+).*/; + } + + // labelRe is made very greedy as it's also used with demangled objdump output (eg. it can have c++ template with <>). + this.labelRe = /^([\da-f]+)\s+<(.+)>:$/; + this.destRe = /\s([\da-f]+)\s+<([^+>]+)(\+0x[\da-f]+)?>$/; + this.commentRe = /[#;]/; + this.instOpcodeRe = /(\.inst\.?\w?)\s*(.*)/; + + // Lines matching the following pattern are considered comments: + // - starts with '#', '@', '//' or a single ';' (non repeated) + // - starts with ';;' and the first non-whitespace before end of line is not # + this.commentOnly = /^\s*(((#|@|\/\/).*)|(\/\*.*\*\/)|(;\s*)|(;[^;].*)|(;;\s*[^\s#].*))$/; + this.commentOnlyNvcc = /^\s*(((#|;|\/\/).*)|(\/\*.*\*\/))$/; + this.sourceTag = /^\s*\.loc\s+(\d+)\s+(\d+)\s+(.*)/; + this.sourceD2Tag = /^\s*\.d2line\s+(\d+),?\s*(\d*).*/; + this.sourceCVTag = /^\s*\.cv_loc\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+).*/; + this.source6502Dbg = /^\s*\.dbg\s+line,\s*"([^"]+)",\s*(\d+)/; + this.source6502DbgEnd = /^\s*\.dbg\s+line[^,]/; + this.sourceStab = /^\s*\.stabn\s+(\d+),0,(\d+),.*/; + this.stdInLooking = /|^-$|example\.[^/]+$|/; + this.endBlock = /\.(cfi_endproc|data|text|section)/; + this.blockComments = /^[\t ]*\/\*(\*(?!\/)|[^*])*\*\/\s*/gm; + } + + checkVLIWpacket(_line: string, inVLIWpacket: boolean) { + return inVLIWpacket; + } + + hasOpcode(line: string, inNvccCode = false, _inVLIWpacket = false) { + // Remove any leading label definition... + const match = line.match(this.labelDef); + if (match) { + line = line.substring(match[0].length); + } + // Strip any comments + line = line.split(this.commentRe, 1)[0]; + // .inst generates an opcode, so also counts + if (this.instOpcodeRe.test(line)) return true; + // Detect assignment, that's not an opcode... + if (this.assignmentDef.test(line)) return false; + if (this.setDef.test(line)) return false; + if (inNvccCode) { + return this.hasNvccOpcodeRe.test(line); + } + return this.hasOpcodeRe.test(line); + } + + private createLabelContext(): LabelContext { + return { + hasOpcode: this.hasOpcode.bind(this), + checkVLIWpacket: this.checkVLIWpacket.bind(this), + labelDef: this.labelDef, + dataDefn: this.dataDefn, + commentRe: this.commentRe, + instructionRe: this.instructionRe, + identifierFindRe: this.identifierFindRe, + definesGlobal: this.definesGlobal, + definesWeak: this.definesWeak, + definesAlias: this.definesAlias, + definesFunction: this.definesFunction, + cudaBeginDef: this.cudaBeginDef, + startAppBlock: this.startAppBlock, + endAppBlock: this.endAppBlock, + startAsmNesting: this.startAsmNesting, + endAsmNesting: this.endAsmNesting, + mipsLabelDefinition: this.mipsLabelDefinition, + labelFindNonMips: this.labelFindNonMips, + labelFindMips: this.labelFindMips, + fixLabelIndentation: this.fixLabelIndentation.bind(this), + }; + } + + findUsedLabels(asmLines: string[], filterDirectives?: boolean): Set { + return this.labelProcessor.findUsedLabels(asmLines, filterDirectives || false, this.createLabelContext()); + } + + parseFiles(asmLines: string[]) { + const files: Record = {}; + for (const line of asmLines) { + const match = line.match(this.fileFind); + if (!match) continue; + + const lineNum = Number.parseInt(match[1], 10); + if (match[4] && !line.includes('.cv_file')) { + // Clang-style file directive '.file X "dir" "filename"' + if (match[4].startsWith('/')) { + files[lineNum] = match[4]; + } else { + files[lineNum] = match[2] + '/' + match[4]; + } + } else { + files[lineNum] = match[2]; + } + } + return files; + } + + removeLabelsWithoutDefinition(asm: ParsedAsmResultLine[], labelDefinitions: Record) { + this.labelProcessor.removeLabelsWithoutDefinition(asm, labelDefinitions); + } + + getUsedLabelsInLine(line: string): AsmResultLabel[] { + return this.labelProcessor.getUsedLabelsInLine(line, this.createLabelContext()); + } + + protected isUserFunctionByLookingAhead(context: ParsingContext, asmLines: string[], idxFrom: number): boolean { + const funcContext: ParsingContext = { + files: context.files, + source: undefined, + dontMaskFilenames: true, + prevLabelIsUserFunction: false, + prevLabel: '', + }; + + for (let idx = idxFrom; idx < asmLines.length; idx++) { + const line = asmLines[idx]; + + const endprocMatch = line.match(this.endBlock); + if (endprocMatch) return false; + + this.handleSource(funcContext, line); + this.handleStabs(funcContext, line); + this.handle6502(funcContext, line); + + if (funcContext.source?.mainsource) return true; + } + + return false; + } + + protected handleSource(context: ParsingContext, line: string) { + const sourceContext: SourceHandlerContext = { + files: context.files, + dontMaskFilenames: context.dontMaskFilenames, + }; + + const result = this.sourceLineHandler.processSourceLine(line, sourceContext); + if (result.source !== undefined) context.source = result.source; + if (result.resetPrevLabel) context.prevLabel = ''; + } + + protected handleStabs(context: ParsingContext, line: string) { + const sourceContext: SourceHandlerContext = { + files: context.files, + dontMaskFilenames: context.dontMaskFilenames, + }; + + const result = this.sourceLineHandler.processSourceLine(line, sourceContext); + if (result.source !== undefined) context.source = result.source; + if (result.resetPrevLabel) context.prevLabel = ''; + } + + protected handle6502(context: ParsingContext, line: string) { + const sourceContext: SourceHandlerContext = { + files: context.files, + dontMaskFilenames: context.dontMaskFilenames, + }; + + const result = this.sourceLineHandler.processSourceLine(line, sourceContext); + if (result.source !== undefined) context.source = result.source; + if (result.resetPrevLabel) context.prevLabel = ''; + } + + processAsm(asmResult: string, filters: ParseFiltersAndOutputOptions): ParsedAsmResult { + if (filters.binary || filters.binaryObject) return this.processBinaryAsm(asmResult, filters); + + const startTime = process.hrtime.bigint(); + + if (filters.commentOnly) { + // Remove any block comments that start and end on a line if we're removing comment-only lines. + asmResult = asmResult.replace(this.blockComments, ''); + } + + let asmLines = utils.splitLines(asmResult); + const startingLineCount = asmLines.length; + if (filters.preProcessLines) asmLines = filters.preProcessLines(asmLines); + + const labelsUsed = this.findUsedLabels(asmLines, filters.directives); + + const files = this.parseFiles(asmLines); + this.parsingState = new ParsingState(files, null, '', false, filters.dontMaskFilenames || false, asmLines); + + const context: ParsingContext = { + files: files, + source: null, + prevLabel: '', + prevLabelIsUserFunction: false, + dontMaskFilenames: filters.dontMaskFilenames || false, + }; + + const {asm, labelDefinitions} = this.processAllLines(filters, context, asmLines, labelsUsed); + + this.removeLabelsWithoutDefinition(asm, labelDefinitions); + + const endTime = process.hrtime.bigint(); + return { + asm: asm, + labelDefinitions: labelDefinitions, + parsingTime: utils.deltaTimeNanoToMili(startTime, endTime), + filteredCount: startingLineCount - asm.length, + }; + } + + fixLabelIndentation(line: string) { + const match = line.match(this.indentedLabelDef); + return match ? line.replace(/^\s+/, '') : line; + } + + isUserFunction(func: string) { + if (this.binaryHideFuncRe === null) return true; + + return !this.binaryHideFuncRe.test(func); + } + + processBinaryAsm(asmResult: string, filters: ParseFiltersAndOutputOptions): ParsedAsmResult { + const startTime = process.hrtime.bigint(); + const asm: ParsedAsmResultLine[] = []; + const labelDefinitions: Record = {}; + const dontMaskFilenames = filters.dontMaskFilenames; + + let asmLines = utils.splitLines(asmResult); + const startingLineCount = asmLines.length; + let source: AsmResultSource | undefined | null = null; + let func: string | null = null; + let mayRemovePreviousLabel = true; + + // Handle "error" documents. + if (asmLines.length === 1 && asmLines[0][0] === '<') { + return { + asm: [{text: asmLines[0], source: null}], + }; + } + + if (filters.preProcessBinaryAsmLines) asmLines = filters.preProcessBinaryAsmLines(asmLines); + + // Parse .file directives to build file number -> filename mapping + const files = this.parseFiles(asmLines); + const sourceContext: SourceHandlerContext = { + files: files, + dontMaskFilenames: dontMaskFilenames || false, + }; + + for (const line of asmLines) { + const labelsInLine: AsmResultLabel[] = []; + + if (asm.length >= this.maxAsmLines) { + if (asm.length === this.maxAsmLines) { + asm.push({ + text: '[truncated; too many lines]', + source: null, + labels: labelsInLine, + }); + } + continue; + } + let match = line.match(this.lineRe); + if (match) { + assert(match.groups); + if (dontMaskFilenames) { + source = { + file: utils.maskRootdir(match[1]), + line: Number.parseInt(match.groups.line, 10), + mainsource: true, + }; + } else { + source = {file: null, line: Number.parseInt(match.groups.line, 10), mainsource: true}; + } + continue; + } + + // Handle .file and .loc directives (DWARF debug info) + const sourceResult = this.sourceLineHandler.processSourceLine(line, sourceContext); + if (sourceResult.source !== undefined) { + source = sourceResult.source; + continue; // Don't display the directive itself + } + + match = line.match(this.labelRe); + if (match) { + func = match[2]; + if (func && this.isUserFunction(func)) { + asm.push({ + text: func + ':', + source: null, + labels: labelsInLine, + }); + labelDefinitions[func] = asm.length; + if (process.platform === 'win32') source = null; + } + continue; + } + + if (func && line === `${func}():`) continue; + + if (!func || !this.isUserFunction(func)) continue; + + // note: normally the source.file will be null if it's code from example.ext but with + // filters.dontMaskFilenames it will be filled with the actual filename instead we can test + // source.mainsource in that situation + const isMainsource = source && (source.file === null || source.mainsource); + if (filters.libraryCode && !isMainsource) { + if (mayRemovePreviousLabel && asm.length > 0) { + const lastLine = asm[asm.length - 1]; + if (lastLine.text && this.labelDef.test(lastLine.text)) { + asm.pop(); + } + mayRemovePreviousLabel = false; + } + continue; + } + mayRemovePreviousLabel = true; + + match = line.match(this.asmOpcodeRe); + if (match) { + assert(match.groups); + const address = Number.parseInt(match.groups.address, 16); + const opcodes = (match.groups.opcodes || '').split(' ').filter(x => !!x); + const disassembly = ' ' + AsmRegex.filterAsmLine(match.groups.disasm, filters); + const destMatch = line.match(this.destRe); + if (destMatch) { + const labelName = destMatch[2]; + const startCol = disassembly.indexOf(labelName) + 1; + labelsInLine.push({ + name: labelName, + range: { + startCol: startCol, + endCol: startCol + labelName.length, + }, + }); + } + asm.push({ + opcodes: opcodes, + address: address, + text: disassembly, + source: source, + labels: labelsInLine, + }); + } + + match = line.match(this.relocationRe); + if (match) { + assert(match.groups); + const address = Number.parseInt(match.groups.address, 16); + const relocname = match.groups.relocname; + const relocdata = match.groups.relocdata; + // value/addend matched but not used yet. + // const match_value = relocdata.match(this.relocDataSymNameRe); + asm.push({ + text: ` ${relocname} ${relocdata}`, + address: address, + }); + } + } + + this.removeLabelsWithoutDefinition(asm, labelDefinitions); + + const endTime = process.hrtime.bigint(); + + return { + asm: asm, + labelDefinitions: labelDefinitions, + parsingTime: utils.deltaTimeNanoToMili(startTime, endTime), + filteredCount: startingLineCount - asm.length, + }; + } + + process(asm: string, filters: ParseFiltersAndOutputOptions) { + return this.processAsm(asm, filters); + } +} diff --git a/lib/pe32-support.ts b/lib/pe32-support.ts index 11b657dbef6..89c3fe244fc 100644 --- a/lib/pe32-support.ts +++ b/lib/pe32-support.ts @@ -1,344 +1,339 @@ -// Copyright (c) 2018, Compiler Explorer Authors -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. - -import {MapFileReader, Segment} from './mapfiles/map-file.js'; - -export enum PELabelReconstructorOptions { - /** Reconstruct segment information from the map file */ - NeedsReconstruction, - /** Don't label addresses that aren't in the map file */ - DontLabelUnmappedAddresses, - /** Delete all assembly before the first user code segment */ - DeleteBeforeFirstSegment, -} - -export class PELabelReconstructor { - public readonly asmLines: string[]; - private readonly addressesToLabel: string[]; - private readonly dontLabelUnmappedAddresses: boolean; - private readonly needsReconstruction: boolean; - private readonly mapFileReader: MapFileReader; - private readonly addressRegex: RegExp; - private readonly jumpRegex: RegExp; - private readonly callRegex: RegExp; - private readonly int3Regex: RegExp; - - private readonly deleteBeforeFirstSegment: boolean; - private readonly additionalExcludedUnits: string[]; - - constructor( - asmLines: string[], - mapFileReader: MapFileReader, - options: Set = new Set(), - additionalExcludedUnits: string[] = [], - ) { - this.asmLines = asmLines; - this.addressesToLabel = []; - this.dontLabelUnmappedAddresses = options.has(PELabelReconstructorOptions.DontLabelUnmappedAddresses); - - this.addressRegex = /^\s*([\da-f]*):/i; - this.jumpRegex = /(\sj[a-z]*)(\s*)0x([\da-f]*)/i; - this.callRegex = /(\scall)(\s*)0x([\da-f]*)/i; - this.int3Regex = /\tcc\s*\tint3\s*$/i; - - this.mapFileReader = mapFileReader; - this.needsReconstruction = options.has(PELabelReconstructorOptions.NeedsReconstruction); - this.deleteBeforeFirstSegment = options.has(PELabelReconstructorOptions.DeleteBeforeFirstSegment); - this.additionalExcludedUnits = additionalExcludedUnits; - } - - /** - * Start reconstructing labels using the mapfile and remove unneccessary assembly - * - */ - run(_unitName?: string) { - this.mapFileReader.run(); - - //this.deleteEverythingBut(unitName); - if (this.deleteBeforeFirstSegment) { - this.deleteBeforeUserCode(); - } - this.deleteSystemUnits(); - this.shortenInt3s(); - - this.collectJumpsAndCalls(); - this.insertLabels(); - } - - /** - * Remove any alignment NOP/int3 opcodes and replace them by a single line "..." - */ - shortenInt3s() { - let lineIdx = 0; - let inInt3 = false; - - while (lineIdx < this.asmLines.length) { - const line = this.asmLines[lineIdx]; - - if (this.int3Regex.test(line)) { - if (inInt3) { - this.asmLines.splice(lineIdx, 1); - lineIdx--; - } else { - inInt3 = true; - this.asmLines[lineIdx] = '...'; - } - } else { - inInt3 = false; - } - - lineIdx++; - } - } - - /** - * Remove any assembly or data that isn't part of the given unit - */ - deleteEverythingBut(unitName: string) { - if (this.needsReconstruction) { - const unitAddressSpaces = this.mapFileReader.getReconstructedUnitAddressSpace(unitName); - - for (let idx = 0; idx < this.mapFileReader.reconstructedSegments.length; idx++) { - const info = this.mapFileReader.reconstructedSegments[idx]; - if (info.unitName !== unitName) { - if (info.segmentLength > 0) { - if ( - !this.mapFileReader.isWithinAddressSpace( - unitAddressSpaces, - info.addressInt, - info.segmentLength, - ) - ) { - this.deleteLinesBetweenAddresses(info.addressInt, info.addressInt + info.segmentLength); - } - } - } - } - } else { - let idx; - let info; - for (idx = 0; idx < this.mapFileReader.segments.length; idx++) { - info = this.mapFileReader.segments[idx]; - if (info.unitName !== unitName) { - this.deleteLinesBetweenAddresses(info.addressInt, info.addressInt + info.segmentLength); - } - } - - for (idx = 0; idx < this.mapFileReader.isegments.length; idx++) { - info = this.mapFileReader.isegments[idx]; - if (info.unitName !== unitName) { - this.deleteLinesBetweenAddresses(info.addressInt, info.addressInt + info.segmentLength); - } - } - } - } - - deleteSystemUnits() { - const systemUnits = new Set(['SysInit.pas', 'System.pas', 'SysUtils.pas', 'Classes.pas', ...this.additionalExcludedUnits]); - - let idx; - let info; - for (idx = 0; idx < this.mapFileReader.segments.length; idx++) { - info = this.mapFileReader.segments[idx]; - if (info.unitName && systemUnits.has(info.unitName)) { - this.deleteLinesBetweenAddresses(info.addressInt, info.addressInt + info.segmentLength); - } - } - - for (idx = 0; idx < this.mapFileReader.isegments.length; idx++) { - info = this.mapFileReader.isegments[idx]; - if (info.unitName && systemUnits.has(info.unitName)) { - this.deleteLinesBetweenAddresses(info.addressInt, info.addressInt + info.segmentLength); - } - } - } - - deleteBeforeUserCode() { - // Find the first user code segment (not system units) - const systemUnits = new Set(['SysInit.pas', 'System.pas', 'SysUtils.pas', 'Classes.pas']); - let firstUserAddress: number | undefined; - - // Check both regular segments and isegments, take the minimum address - for (const info of this.mapFileReader.segments) { - if (info.unitName && !systemUnits.has(info.unitName)) { - if (firstUserAddress === undefined || info.addressInt < firstUserAddress) { - firstUserAddress = info.addressInt; - } - } - } - - for (const info of this.mapFileReader.isegments) { - if (info.unitName && !systemUnits.has(info.unitName)) { - if (firstUserAddress === undefined || info.addressInt < firstUserAddress) { - firstUserAddress = info.addressInt; - } - } - } - - // Delete everything before the first user code - if (firstUserAddress !== undefined) { - console.log(`[PELabel] Deleting from 0 to 0x${firstUserAddress.toString(16)}`); - this.deleteLinesBetweenAddresses(0, firstUserAddress); - } - } - - deleteLinesBetweenAddresses(beginAddress: number, endAddress?: number) { - let startIdx = -1; - let linesRemoved = false; - let lineIdx = 0; - - while (lineIdx < this.asmLines.length) { - const line = this.asmLines[lineIdx]; - - const matches = line.match(this.addressRegex); - if (matches) { - const lineAddr = Number.parseInt(matches[1], 16); - if (startIdx === -1 && lineAddr >= beginAddress) { - startIdx = lineIdx; - if (line.endsWith(':') || line.endsWith('<.text>:') || line.endsWith('<.itext>:')) { - startIdx++; - } - } else if (endAddress && lineAddr >= endAddress) { - this.asmLines.splice(startIdx, lineIdx - startIdx - 1); - linesRemoved = true; - break; - } - } - - lineIdx++; - } - - if (!linesRemoved && startIdx !== -1) { - this.asmLines.splice(startIdx, this.asmLines.length - startIdx); - } - } - - /** - * Replaces an address used in a jmp or call instruction by its label. - * Does not replace an address if it has an offset. - */ - addAddressAsLabelAndReplaceLine(lineIdx: number, regex: RegExp) { - const line = this.asmLines[lineIdx]; - const matches = line.match(regex); - if (matches) { - const address = matches[3]; - if (!address.includes('+') && !address.includes('-')) { - let labelName = 'L' + address; - const namedAddr = this.mapFileReader.getSymbolAt(undefined, Number.parseInt(address, 16)); - if (namedAddr?.displayName) { - labelName = namedAddr.displayName; - } - - if (!this.dontLabelUnmappedAddresses || namedAddr) { - this.addressesToLabel.push(address); - - this.asmLines[lineIdx] = line.replace(regex, ' ' + matches[1] + matches[2] + labelName); - } - } - } - } - - /** - * Collects addresses that are referred to by the assembly, through jump and call instructions - */ - collectJumpsAndCalls() { - for (let lineIdx = 0; lineIdx < this.asmLines.length; lineIdx++) { - this.addAddressAsLabelAndReplaceLine(lineIdx, this.jumpRegex); - this.addAddressAsLabelAndReplaceLine(lineIdx, this.callRegex); - } - } - - /** - * Injects labels into the assembly where addresses are referred to - * if an address doesn't have a mapped name, it is called - */ - insertLabels() { - let currentSegment: Segment | undefined; - let segmentChanged = false; - - let lineIdx = 0; - while (lineIdx < this.asmLines.length) { - const line = this.asmLines[lineIdx]; - - const matches = line.match(this.addressRegex); - if (matches) { - const addressStr = matches[1]; - const address = Number.parseInt(addressStr, 16); - - const segmentInfo = this.mapFileReader.getSegmentInfoByStartingAddress(undefined, address); - if (segmentInfo) { - currentSegment = segmentInfo; - segmentChanged = true; - } - - let namedAddr: Segment | undefined; - let labelLine: string | undefined; - - const isReferenced = this.addressesToLabel.indexOf(addressStr); - if (isReferenced === -1) { - // we might have missed the reference to this address, - // but if it's listed as a symbol, we should still label it. - // todo: the call might be in <.itext>, should we include that part of the assembly? - namedAddr = this.mapFileReader.getSymbolAt(undefined, address); - if (namedAddr) { - labelLine = matches[1] + ' <' + namedAddr.displayName + '>:'; - - this.asmLines.splice(lineIdx, 0, labelLine); - lineIdx++; - } - } else { - labelLine = matches[1] + ' :'; - - namedAddr = this.mapFileReader.getSymbolAt(undefined, address); - if (namedAddr) { - labelLine = matches[1] + ' <' + namedAddr.displayName + '>:'; - } - - if (!this.dontLabelUnmappedAddresses || namedAddr) { - this.asmLines.splice(lineIdx, 0, labelLine); - lineIdx++; - } - } - - const lineInfo = this.mapFileReader.getLineInfoByAddress(undefined, address); - - if (lineIdx < 3) { - console.log(`[PELabel] Address ${address.toString(16)}: lineInfo=${lineInfo ? `${lineInfo.lineNumber} (${(lineInfo as any).filename || 'no filename'})` : 'null'}, segment=${currentSegment ? currentSegment.unitName : 'null'}`); - } - - if (lineInfo && currentSegment && currentSegment.unitName) { - // Use filename from lineInfo if available (for Delphi), otherwise fall back to segment unitName - const sourceFile = (lineInfo as any).filename || currentSegment.unitName; - this.asmLines.splice(lineIdx, 0, '/app/' + sourceFile + ':' + lineInfo.lineNumber); - lineIdx++; - } else if (segmentChanged && currentSegment) { - this.asmLines.splice(lineIdx, 0, '/app/' + currentSegment.unitName + ':0'); - lineIdx++; - } - } - - lineIdx++; - } - } -} +// Copyright (c) 2018, Compiler Explorer Authors +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import {MapFileReader, Segment} from './mapfiles/map-file.js'; + +export enum PELabelReconstructorOptions { + /** Reconstruct segment information from the map file */ + NeedsReconstruction, + /** Don't label addresses that aren't in the map file */ + DontLabelUnmappedAddresses, + /** Delete all assembly before the first user code segment */ + DeleteBeforeFirstSegment, +} + +export class PELabelReconstructor { + public readonly asmLines: string[]; + private readonly addressesToLabel: string[]; + private readonly dontLabelUnmappedAddresses: boolean; + private readonly needsReconstruction: boolean; + private readonly mapFileReader: MapFileReader; + private readonly addressRegex: RegExp; + private readonly jumpRegex: RegExp; + private readonly callRegex: RegExp; + private readonly int3Regex: RegExp; + + private readonly deleteBeforeFirstSegment: boolean; + private readonly additionalExcludedUnits: string[]; + + constructor( + asmLines: string[], + mapFileReader: MapFileReader, + options: Set = new Set(), + additionalExcludedUnits: string[] = [], + ) { + this.asmLines = asmLines; + this.addressesToLabel = []; + this.dontLabelUnmappedAddresses = options.has(PELabelReconstructorOptions.DontLabelUnmappedAddresses); + + this.addressRegex = /^\s*([\da-f]*):/i; + this.jumpRegex = /(\sj[a-z]*)(\s*)0x([\da-f]*)/i; + this.callRegex = /(\scall)(\s*)0x([\da-f]*)/i; + this.int3Regex = /\tcc\s*\tint3\s*$/i; + + this.mapFileReader = mapFileReader; + this.needsReconstruction = options.has(PELabelReconstructorOptions.NeedsReconstruction); + this.deleteBeforeFirstSegment = options.has(PELabelReconstructorOptions.DeleteBeforeFirstSegment); + this.additionalExcludedUnits = additionalExcludedUnits; + } + + /** + * Start reconstructing labels using the mapfile and remove unneccessary assembly + * + */ + run(_unitName?: string) { + this.mapFileReader.run(); + + //this.deleteEverythingBut(unitName); + if (this.deleteBeforeFirstSegment) { + this.deleteBeforeUserCode(); + } + this.deleteSystemUnits(); + this.shortenInt3s(); + + this.collectJumpsAndCalls(); + this.insertLabels(); + } + + /** + * Remove any alignment NOP/int3 opcodes and replace them by a single line "..." + */ + shortenInt3s() { + let lineIdx = 0; + let inInt3 = false; + + while (lineIdx < this.asmLines.length) { + const line = this.asmLines[lineIdx]; + + if (this.int3Regex.test(line)) { + if (inInt3) { + this.asmLines.splice(lineIdx, 1); + lineIdx--; + } else { + inInt3 = true; + this.asmLines[lineIdx] = '...'; + } + } else { + inInt3 = false; + } + + lineIdx++; + } + } + + /** + * Remove any assembly or data that isn't part of the given unit + */ + deleteEverythingBut(unitName: string) { + if (this.needsReconstruction) { + const unitAddressSpaces = this.mapFileReader.getReconstructedUnitAddressSpace(unitName); + + for (let idx = 0; idx < this.mapFileReader.reconstructedSegments.length; idx++) { + const info = this.mapFileReader.reconstructedSegments[idx]; + if (info.unitName !== unitName) { + if (info.segmentLength > 0) { + if ( + !this.mapFileReader.isWithinAddressSpace( + unitAddressSpaces, + info.addressInt, + info.segmentLength, + ) + ) { + this.deleteLinesBetweenAddresses(info.addressInt, info.addressInt + info.segmentLength); + } + } + } + } + } else { + let idx; + let info; + for (idx = 0; idx < this.mapFileReader.segments.length; idx++) { + info = this.mapFileReader.segments[idx]; + if (info.unitName !== unitName) { + this.deleteLinesBetweenAddresses(info.addressInt, info.addressInt + info.segmentLength); + } + } + + for (idx = 0; idx < this.mapFileReader.isegments.length; idx++) { + info = this.mapFileReader.isegments[idx]; + if (info.unitName !== unitName) { + this.deleteLinesBetweenAddresses(info.addressInt, info.addressInt + info.segmentLength); + } + } + } + } + + deleteSystemUnits() { + const systemUnits = new Set(['SysInit.pas', 'System.pas', 'SysUtils.pas', 'Classes.pas', ...this.additionalExcludedUnits]); + + let idx; + let info; + for (idx = 0; idx < this.mapFileReader.segments.length; idx++) { + info = this.mapFileReader.segments[idx]; + if (info.unitName && systemUnits.has(info.unitName)) { + this.deleteLinesBetweenAddresses(info.addressInt, info.addressInt + info.segmentLength); + } + } + + for (idx = 0; idx < this.mapFileReader.isegments.length; idx++) { + info = this.mapFileReader.isegments[idx]; + if (info.unitName && systemUnits.has(info.unitName)) { + this.deleteLinesBetweenAddresses(info.addressInt, info.addressInt + info.segmentLength); + } + } + } + + deleteBeforeUserCode() { + // Find the first user code segment (not system units) + const systemUnits = new Set(['SysInit.pas', 'System.pas', 'SysUtils.pas', 'Classes.pas']); + let firstUserAddress: number | undefined; + + // Check both regular segments and isegments, take the minimum address + for (const info of this.mapFileReader.segments) { + if (info.unitName && !systemUnits.has(info.unitName)) { + if (firstUserAddress === undefined || info.addressInt < firstUserAddress) { + firstUserAddress = info.addressInt; + } + } + } + + for (const info of this.mapFileReader.isegments) { + if (info.unitName && !systemUnits.has(info.unitName)) { + if (firstUserAddress === undefined || info.addressInt < firstUserAddress) { + firstUserAddress = info.addressInt; + } + } + } + + // Delete everything before the first user code + if (firstUserAddress !== undefined) { + this.deleteLinesBetweenAddresses(0, firstUserAddress); + } + } + + deleteLinesBetweenAddresses(beginAddress: number, endAddress?: number) { + let startIdx = -1; + let linesRemoved = false; + let lineIdx = 0; + + while (lineIdx < this.asmLines.length) { + const line = this.asmLines[lineIdx]; + + const matches = line.match(this.addressRegex); + if (matches) { + const lineAddr = Number.parseInt(matches[1], 16); + if (startIdx === -1 && lineAddr >= beginAddress) { + startIdx = lineIdx; + if (line.endsWith(':') || line.endsWith('<.text>:') || line.endsWith('<.itext>:')) { + startIdx++; + } + } else if (endAddress && lineAddr >= endAddress) { + this.asmLines.splice(startIdx, lineIdx - startIdx - 1); + linesRemoved = true; + break; + } + } + + lineIdx++; + } + + if (!linesRemoved && startIdx !== -1) { + this.asmLines.splice(startIdx, this.asmLines.length - startIdx); + } + } + + /** + * Replaces an address used in a jmp or call instruction by its label. + * Does not replace an address if it has an offset. + */ + addAddressAsLabelAndReplaceLine(lineIdx: number, regex: RegExp) { + const line = this.asmLines[lineIdx]; + const matches = line.match(regex); + if (matches) { + const address = matches[3]; + if (!address.includes('+') && !address.includes('-')) { + let labelName = 'L' + address; + const namedAddr = this.mapFileReader.getSymbolAt(undefined, Number.parseInt(address, 16)); + if (namedAddr?.displayName) { + labelName = namedAddr.displayName; + } + + if (!this.dontLabelUnmappedAddresses || namedAddr) { + this.addressesToLabel.push(address); + + this.asmLines[lineIdx] = line.replace(regex, ' ' + matches[1] + matches[2] + labelName); + } + } + } + } + + /** + * Collects addresses that are referred to by the assembly, through jump and call instructions + */ + collectJumpsAndCalls() { + for (let lineIdx = 0; lineIdx < this.asmLines.length; lineIdx++) { + this.addAddressAsLabelAndReplaceLine(lineIdx, this.jumpRegex); + this.addAddressAsLabelAndReplaceLine(lineIdx, this.callRegex); + } + } + + /** + * Injects labels into the assembly where addresses are referred to + * if an address doesn't have a mapped name, it is called + */ + insertLabels() { + let currentSegment: Segment | undefined; + let segmentChanged = false; + + let lineIdx = 0; + while (lineIdx < this.asmLines.length) { + const line = this.asmLines[lineIdx]; + + const matches = line.match(this.addressRegex); + if (matches) { + const addressStr = matches[1]; + const address = Number.parseInt(addressStr, 16); + + const segmentInfo = this.mapFileReader.getSegmentInfoByStartingAddress(undefined, address); + if (segmentInfo) { + currentSegment = segmentInfo; + segmentChanged = true; + } + + let namedAddr: Segment | undefined; + let labelLine: string | undefined; + + const isReferenced = this.addressesToLabel.indexOf(addressStr); + if (isReferenced === -1) { + // we might have missed the reference to this address, + // but if it's listed as a symbol, we should still label it. + // todo: the call might be in <.itext>, should we include that part of the assembly? + namedAddr = this.mapFileReader.getSymbolAt(undefined, address); + if (namedAddr) { + labelLine = matches[1] + ' <' + namedAddr.displayName + '>:'; + + this.asmLines.splice(lineIdx, 0, labelLine); + lineIdx++; + } + } else { + labelLine = matches[1] + ' :'; + + namedAddr = this.mapFileReader.getSymbolAt(undefined, address); + if (namedAddr) { + labelLine = matches[1] + ' <' + namedAddr.displayName + '>:'; + } + + if (!this.dontLabelUnmappedAddresses || namedAddr) { + this.asmLines.splice(lineIdx, 0, labelLine); + lineIdx++; + } + } + + const lineInfo = this.mapFileReader.getLineInfoByAddress(undefined, address); + + if (lineInfo && currentSegment && currentSegment.unitName) { + // Use filename from lineInfo if available (for Delphi), otherwise fall back to segment unitName + const sourceFile = (lineInfo as any).filename || currentSegment.unitName; + this.asmLines.splice(lineIdx, 0, '/app/' + sourceFile + ':' + lineInfo.lineNumber); + lineIdx++; + } else if (segmentChanged && currentSegment) { + this.asmLines.splice(lineIdx, 0, '/app/' + currentSegment.unitName + ':0'); + lineIdx++; + } + } + + lineIdx++; + } + } +} From 4fab01143ef063c96b6f94423fd2d95bbb23debe Mon Sep 17 00:00:00 2001 From: Paul McGee Date: Fri, 28 Nov 2025 02:46:35 +0800 Subject: [PATCH 22/27] Consolidate Pascal configuration and improve prog.dpr filtering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Consolidate all Pascal compiler config into single pascal.local.properties - Delete pascal-win.local.properties (duplicate definitions) - Follow C++ pattern: one config file for multiple compiler types - Eliminates "Duplicate compiler id" errors - Improve wrapper program filtering logic - Replace order-dependent "firstFilename" approach with explicit check - Filter prog.dpr markers only when using wrapper program - No longer relies on file encounter order in map files - Clearer intent: if (this.isWrapperProgram && filename === 'prog.dpr') 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- ...0\272UsersUserDocumentsce_branch_diff.txt" | 4291 +++++++++++++++++ etc/config/pascal-win.local.properties | 76 - etc/config/pascal.local.properties | 274 +- lib/compilers/pascal-win.ts | 10 +- 4 files changed, 4449 insertions(+), 202 deletions(-) create mode 100644 "C\357\200\272UsersUserDocumentsce_branch_diff.txt" delete mode 100644 etc/config/pascal-win.local.properties diff --git "a/C\357\200\272UsersUserDocumentsce_branch_diff.txt" "b/C\357\200\272UsersUserDocumentsce_branch_diff.txt" new file mode 100644 index 00000000000..b9281896280 --- /dev/null +++ "b/C\357\200\272UsersUserDocumentsce_branch_diff.txt" @@ -0,0 +1,4291 @@ +diff --git a/MIGRATION-FROM-2021.md b/MIGRATION-FROM-2021.md +new file mode 100644 +index 000000000..dc5c53178 +--- /dev/null ++++ b/MIGRATION-FROM-2021.md +@@ -0,0 +1,285 @@ ++# Migration from CE-for-Win-Pascal (2021) to CE-for-Win-Pascal-2025 ++ ++## Summary of Changes ++ ++Your original `CE-for-Win-Pascal` branch from 2021 has been modernized to `CE-for-Win-Pascal-2025`. ++ ++### What Was Migrated ++ ++✅ **Preserved**: ++- All your compiler configurations (FPC, Delphi, C++Builder) ++- Windows-specific paths and settings ++- Minimal language selection (C++, Pascal + Rust, Python) ++- Local deployment customizations ++ ++✅ **Improved**: ++- JavaScript → TypeScript (better type safety) ++- Pascal program/unit detection (now automatic!) ++- 4+ years of bug fixes and improvements ++- Modern build tooling ++ ++### What Changed ++ ++| Aspect | 2021 Branch | 2025 Branch | ++|--------|-------------|-------------| ++| **Language** | JavaScript | TypeScript | ++| **Pascal Detection** | Hardcoded `output.dpr` | Smart detection via `pascalUtils.isProgram()` | ++| **Languages File** | `lib/languages.js` | `lib/languages.ts` (minimal) | ++| **Compiler Configs** | `.local.properties` | Same (copied forward) | ++| **Build System** | Webpack 4 | Webpack 5 | ++ ++## Your Original Changes (2021) ++ ++### What You Modified ++ ++1. **lib/compilers/pascal.js** ++ - Changed executable from `prog` to `output` ++ - Changed project file to `output.dpr` ++ ++ **Status**: ✅ **No longer needed** - Modern code has better implementation! ++ ++2. **lib/languages.js** ++ - Removed most languages ++ - Kept only C++, Pascal ++ ++ **Status**: ✅ **Migrated** to `lib/languages.ts` with C++, Pascal, Rust, Python ++ ++3. **Configuration Files** ++ - `etc/config/pascal.local.properties` ++ - `etc/config/pascal-win.local.properties` ++ - `etc/config/c++.local.properties` ++ ++ **Status**: ✅ **Copied forward** - Ready to update paths ++ ++4. **Documentation** ++ - `Delphi & C++Builder Specifics.md` ++ - README modifications ++ ++ **Status**: ✅ **Replaced** with `WINDOWS-DEPLOYMENT.md` ++ ++## Modern Implementation Benefits ++ ++### Pascal Program Detection (2025) ++ ++The new code is **smarter** than your 2021 changes: ++ ++**Old way (2021)**: ++```javascript ++// Hardcoded ++getExecutableFilename(dirPath) { ++ return path.join(dirPath, 'output'); ++} ++``` ++ ++**New way (2025)**: ++```typescript ++getExecutableFilename(dirPath: string, outputFilebase: string, key?: CacheKey) { ++ const source = (key && (key as CacheKey).source) || ''; ++ if (key && pascalUtils.isProgram(source)) { ++ return path.join(dirPath, pascalUtils.getProgName(source)); // Extracts from source! ++ } ++ return path.join(dirPath, 'prog'); ++} ++``` ++ ++**Benefit**: Automatically extracts program name from your source code! ++ ++```pascal ++program MyCalculator; // Executable will be named "MyCalculator" ++``` ++ ++## Migration Steps ++ ++### 1. Update Compiler Paths ++ ++Your compiler paths from 2021 may have changed. Edit: ++ ++**`etc/config/pascal.local.properties`**: ++```properties ++# Update these paths to match your current installations ++compiler.fpc331.exe=C:\fpcupdeluxe\fpc\bin\x86_64-win64\fpc.exe ++compiler.delphi27.exe=C:\Program Files (x86)\Embarcadero\Studio\21.0\Bin\DCC32.EXE ++``` ++ ++### 2. Update Delphi Versions ++ ++You had Delphi 10.2, 10.3, 10.4 configured. Update to your current versions: ++ ++```properties ++# Example: Add Delphi 11 Alexandria ++compiler.delphi28.exe=C:\Program Files (x86)\Embarcadero\Studio\22.0\Bin\DCC32.EXE ++compiler.delphi28.name=x86 Delphi 11 Alexandria ++ ++compiler.delphi28_64.exe=C:\Program Files (x86)\Embarcadero\Studio\22.0\Bin\DCC64.EXE ++compiler.delphi28_64.name=x64 Delphi 11 Alexandria ++ ++# Add to group ++group.delphi.compilers=delphi25:delphi26:delphi27:delphi28 ++group.delphi64.compilers=delphi25_64:delphi26_64:delphi27_64:delphi28_64 ++``` ++ ++### 3. Test the Build ++ ++```bash ++npm install ++npm run webpack ++npm start ++``` ++ ++Browse to http://localhost:10240/ ++ ++### 4. Verify Compilers ++ ++1. Select **Pascal** language ++2. Try each compiler version ++3. Test both Programs and Units ++4. Verify assembly output works ++ ++## What You DON'T Need to Do ++ ++❌ **Don't** manually edit `lib/compilers/pascal.ts` - It's already better! ++❌ **Don't** worry about TypeScript - It works like JavaScript ++❌ **Don't** modify core files - Only edit `.local.properties` ++ ++## Recommended: Delete Old Branch ++ ++Once you've verified the new branch works: ++ ++```bash ++# The old branch is backed up in a tag ++git tag # Verify CE-for-Win-Pascal-backup-20251122 exists ++ ++# Safe to delete old branch ++git branch -D CE-for-Win-Pascal ++ ++# Keep only the new one ++git branch -m CE-for-Win-Pascal-2025 CE-for-Win-Pascal ++``` ++ ++## Comparison: Old vs New ++ ++### File Count ++ ++| Category | 2021 Branch | 2025 Branch | ++|----------|-------------|-------------| ++| Modified Files | 15+ files | 3 files | ++| Custom Code | 200+ lines | 90 lines | ++| Merge Commits | 10 | 0 | ++ ++The new branch is **cleaner** and **easier to maintain**! ++ ++### Technical Debt ++ ++**2021 Branch**: ++- 4,627 commits behind main ++- JavaScript (no type safety) ++- Hardcoded values ++- Manual merges needed ++ ++**2025 Branch**: ++- ✅ Up to date with main ++- ✅ TypeScript (full type safety) ++- ✅ Smart detection ++- ✅ Clean rebase possible ++ ++## Adding More Languages ++ ++If you want to add more languages, edit `lib/languages.ts`: ++ ++```typescript ++const definitions: Record = { ++ 'c++': { ... }, ++ pascal: { ... }, ++ rust: { ... }, ++ python: { ... }, ++ ++ // Add more here - copy from lib/languages.ts.full-backup ++ d: { ++ name: 'D', ++ monaco: 'd', ++ extensions: ['.d'], ++ alias: [], ++ logoFilename: 'd.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++}; ++``` ++ ++## FAQ ++ ++### Q: Why recreate instead of rebase? ++ ++**A**: With 4,627 commits divergence and JS→TS migration, clean recreation was: ++- Faster (hours vs days) ++- Safer (no conflict resolution needed) ++- Cleaner (no merge commits) ++- Better (got improvements for free) ++ ++### Q: Did I lose any custom features? ++ ++**A**: No! Your custom features are **better** in the new code: ++- Pascal program support: Now automatic ++- Compiler configs: All copied forward ++- Language filtering: Preserved and improved ++ ++### Q: Can I still update from main? ++ ++**A**: Yes! Much easier now: ++```bash ++git merge origin/main ++# Only conflicts will be in lib/languages.ts - just keep your minimal version ++``` ++ ++### Q: What if I need the old branch? ++ ++**A**: It's tagged: ++```bash ++git checkout CE-for-Win-Pascal-backup-20251122 ++``` ++ ++## Next Steps ++ ++1. ✅ Update compiler paths in `.local.properties` files ++2. ✅ Test build with `npm install && npm start` ++3. ✅ Verify all compilers work ++4. ✅ Read `WINDOWS-DEPLOYMENT.md` for detailed docs ++5. ✅ Consider deleting old branch once verified ++ ++## Success Indicators ++ ++You'll know migration succeeded when: ++ ++- ✅ Server starts on http://localhost:10240/ ++- ✅ You see only 4 languages (C++, Pascal, Rust, Python) ++- ✅ Your compilers appear in dropdown ++- ✅ Compilation works ++- ✅ Assembly output displays ++ ++## Rollback Plan ++ ++If anything goes wrong: ++ ++```bash ++# Go back to old branch ++git checkout CE-for-Win-Pascal-backup-20251122 ++ ++# Or restore old config ++git checkout CE-for-Win-Pascal-backup-20251122 -- etc/config/ ++``` ++ ++## Support ++ ++Need help? Check: ++1. This migration guide ++2. `WINDOWS-DEPLOYMENT.md` - Full documentation ++3. Original CE docs - Most still apply ++4. Git tag - Backup of old branch ++ ++--- ++ ++**Migration Date**: November 22, 2025 ++**From**: CE-for-Win-Pascal (2021, JavaScript) ++**To**: CE-for-Win-Pascal-2025 (TypeScript) +diff --git a/README.md b/README.md +index a6eae1523..7c54d7218 100644 +--- a/README.md ++++ b/README.md +@@ -1,134 +1,108 @@ + [![Build Status](https://github.com/compiler-explorer/compiler-explorer/workflows/Compiler%20Explorer/badge.svg)](https://github.com/compiler-explorer/compiler-explorer/actions?query=workflow%3A%22Compiler+Explorer%22) + [![codecov](https://codecov.io/gh/compiler-explorer/compiler-explorer/branch/main/graph/badge.svg)](https://codecov.io/gh/compiler-explorer/compiler-explorer) + +-[![logo](public/logos/assembly.png)](https://godbolt.org/) + +-# Compiler Explorer +- +-Compiler Explorer is an interactive compiler exploration website. Edit code in C, C++, C#, F#, Rust, Go, D, Haskell, Swift, Pascal, +-[ispc](https://ispc.github.io/), Python, Java, or any of the other +-[30+ supported languages](https://godbolt.org/api/languages), and see how that code looks after being +-compiled in real time. ++![image](https://user-images.githubusercontent.com/11953157/120695427-f6101e00-c4dd-11eb-87b5-082fe000c01f.png) + +-[Bug Report](https://github.com/compiler-explorer/compiler-explorer/issues/new?assignees=&labels=bug&projects=&template=bug_report.yml&title=%5BBUG%5D%3A+) +-· +-[Compiler Request](https://github.com/compiler-explorer/compiler-explorer/issues/new?assignees=&labels=request%2Cnew-compilers&projects=&template=compiler_request.yml&title=%5BCOMPILER+REQUEST%5D%3A+) +-· +-[Feature Request](https://github.com/compiler-explorer/compiler-explorer/issues/new?assignees=&labels=request&projects=&template=feature_request.yml&title=%5BREQUEST%5D%3A+) +-· +-[Language Request](https://github.com/compiler-explorer/compiler-explorer/issues/new?assignees=&labels=request%2Cnew-language&projects=&template=language_request.yml&title=%5BLANGUAGE+REQUEST%5D%3A+) +-· +-[Library Request](https://github.com/compiler-explorer/compiler-explorer/issues/new?assignees=&labels=request%2Cnew-libs&projects=&template=library_request.yml&title=%5BLIB+REQUEST%5D%3A+) +-· [Report Vulnerability](https://github.com/compiler-explorer/compiler-explorer/security/advisories/new) + +-# Overview + +-Multiple compilers are supported for each language, many different tools and visualizations are available, and the UI +-layout is configurable (thanks to [GoldenLayout](https://www.golden-layout.com/)). ++# Compiler Explorer ++# - for DELPHI, Free Pascal, and C++ BUILDER. And Rust! + +-Try out at [godbolt.org](https://godbolt.org), or [run your own local instance](#running-a-local-instance). An overview +-of what the site lets you achieve, why it's useful, and how to use it is +-[available here](docs/WhatIsCompilerExplorer.md), or in [this talk](https://www.youtube.com/watch?v=_9sGKcvT-TA). ++[See **_Windows install_** guideline for Delphi & fpc **_here_**](docs/DelphiCppBuilderSpecifics.md) + +-**Compiler Explorer** follows a [Code of Conduct](CODE_OF_CONDUCT.md) which aims to foster an open and welcoming +-environment. ++--- + +-**Compiler Explorer** was started in 2012 to show how C++ constructs are translated to assembly code. It started as a +-`tmux` session with `vi` running in one pane and `watch gcc -S foo.cc -o -` running in the other. ++**Compiler Explorer** is an interactive compiler exploration website. Edit C, C++, Rust, Go, D, Haskell, Swift, Pascal, [ispc](https://ispc.github.io/) or other language code, and see how that code looks after being compiled in real time. ++ Multiple compilers are supported, many different tools and visualisations are available, and the UI layout ++ is configurable (thanks to [GoldenLayout](https://www.golden-layout.com/)). + +-Since then, it has become a public website serving over +-[3,000,000 compilations per week](https://stats.compiler-explorer.com). ++Try out at [godbolt.org](https://godbolt.org), or [run your own local instance](#running-a-local-instance). + + You can financially support [this project on Patreon](https://patreon.com/mattgodbolt), +-[GitHub](https://github.com/sponsors/mattgodbolt/), +-[Paypal](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=KQWQZ7GPY2GZ6&item_name=Compiler+Explorer+development¤cy_code=USD&source=url), +-or by buying cool gear on the [Compiler Explorer store](https://shop.compiler-explorer.com). ++ [GitHub](https://github.com/sponsors/mattgodbolt/), [Paypal](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=KQWQZ7GPY2GZ6&item_name=Compiler+Explorer+development¤cy_code=USD&source=url), or by ++ buying cool gear on the [Compiler Explorer store](https://shop.spreadshirt.com/compiler-explorer/). ++ ++**Compiler Explorer** follows a [Code of Conduct](CODE_OF_CONDUCT.md) which ++ aims to foster an open and welcoming environment. ++ ++**Compiler Explorer** was started in 2012 to show how C++ constructs translated to assembly code. It started out as a ++ `tmux` session with `vi` running in one pane and `watch gcc -S foo.cc -o -` running in the other. ++ ++Since then, it has become a public website serving around [2,000,000 compilations per week](https://www.stathat.com/cards/Tk5csAWI0O7x). + + ## Using Compiler Explorer + + ### FAQ + +-There is now a FAQ section [in the repository wiki](https://github.com/compiler-explorer/compiler-explorer/wiki/FAQ). If +-your question is not present, please contact us as described below, so we can help you. If you find that the FAQ is +-lacking some important point, please feel free to contribute to it and/or ask us to clarify it. ++There is now a FAQ section [in the repository wiki](https://github.com/compiler-explorer/compiler-explorer/wiki/FAQ). ++ If your question is not present, please contact us as described below, so we can help you. ++ If you find that the FAQ is lacking some important point, please free to contribute to it and/or ask us to clarify it. + + ### Videos + +-Several videos showcase some features of Compiler Explorer: ++There are a number of videos that showcase some features of Compiler Explorer: + +-- [Compiler Explorer 2023: What's New?](https://www.youtube.com/watch?v=Ey0H79z_pco): Presentation for CppNorth 2023. +-- [Presentation for CppCon 2019 about the project](https://www.youtube.com/watch?v=kIoZDUd5DKw) +-- [Older 2 part series of videos](https://www.youtube.com/watch?v=4_HL3PH4wDg) which go into a bit more detail into the +- more obscure features. +-- [Just Enough Assembly for Compiler Explorer](https://youtu.be/QLolzolunJ4): Practical introduction to Assembly with a +- focus on the usage of Compiler Explorer, from CppCon 2021. +-- [Playlist: Compiler Explorer](https://www.youtube.com/playlist?list=PL2HVqYf7If8dNYVN6ayjB06FPyhHCcnhG): A collection +- of videos discussing Compiler Explorer; using it, installing it, what it's for, etc. +- +-A [Road map](docs/Roadmap.md) is available which gives a little insight into the future plans for **Compiler Explorer**. ++* [presentation for CppCon 2019 about the project](https://www.youtube.com/watch?v=kIoZDUd5DKw) ++* [older 2 part series of videos](https://www.youtube.com/watch?v=4_HL3PH4wDg) which go into a bit more detail ++ into the more obscure features. ++* [playlist: Compiler Explorer](https://www.youtube.com/playlist?list=PL2HVqYf7If8dNYVN6ayjB06FPyhHCcnhG): A collection of videos discussing Compiler Explorer; using it, installing it, what it's for, etc. + + ## Developing + +-**Compiler Explorer** is written in [TypeScript](https://www.typescriptlang.org/), on [Node.js](https://nodejs.org/). ++**Compiler Explorer** is written in [Node.js](https://nodejs.org/). + +-Assuming you have a compatible version of `node` installed, on Linux simply running `make` ought to get you up and +-running with an Explorer running on port 10240 on your local machine: +-[http://localhost:10240/](http://localhost:10240/). If this doesn't work for you, please contact us, as we consider it +-important you can quickly and easily get running. Currently, **Compiler Explorer** requires +-[`node` 20 or higher](CONTRIBUTING.md#node-version) installed, either on the path or at `NODE_DIR` (an environment variable or +-`make` parameter). ++Assuming you have a compatible version of `node` installed, on Linux simply running ++ `make` ought to get you up and running with an Explorer running on port 10240 ++ on your local machine: [http://localhost:10240/](http://localhost:10240/). If this doesn't work for you, please contact ++ us, as we consider it important you can quickly and easily get running. ++ Currently, **Compiler Explorer** ++ requires [at least `node` 12 _(LTS version)_](CONTRIBUTING.md#node-version) installed, either on the path or at `NODE_DIR` ++ (an environment variable or `make` parameter). + +-Running with `make EXTRA_ARGS='--language LANG'` will allow you to load `LANG` exclusively, where `LANG` is one for the +-language ids/aliases defined in `lib/languages.ts`. For example, to only run **Compiler Explorer** with C++ support, +-you'd run `make EXTRA_ARGS='--language c++'`. You can supply multiple `--language` arguments to restrict to more than +-one language. The `Makefile` will automatically install all the third-party libraries needed to run; using `npm` to +-install server-side and client-side components. ++Running with `make EXTRA_ARGS='--language LANG'` will allow you to load ++ `LANG` exclusively, where `LANG` is one for the language ids/aliases defined ++ in `lib/languages.js`. For example, to only run CE with C++ support, you'd run ++ `make EXTRA_ARGS='--language c++'`. The `Makefile` will automatically install all the ++ third party libraries needed to run; using `npm` to install server-side and ++ client side components. + +-For development, we suggest using `make dev` to enable some useful features, such as automatic reloading on file changes +-and shorter startup times. ++For development, we suggest using `make dev` to enable some useful features, ++ such as automatic reloading on file changes and shorter startup times. + + You can also use `npm run dev` to run if `make dev` doesn't work on your machine. + +-When making UI changes, we recommend following the [UI Testing Checklist](docs/TestingTheUi.md) to ensure all components work correctly. +- +-Some languages need extra tools to demangle them, e.g. `rust`, `d`, or `haskell`. Such tools are kept separately in the +-[tools repo](https://github.com/compiler-explorer/compiler-explorer-tools). ++Some languages need extra tools to demangle them, e.g. `rust`, `d`, or `haskell`. ++ Such tools are kept separately in the ++ [tools repo](https://github.com/compiler-explorer/compiler-explorer-tools). + +-Configuring compiler explorer is achieved via configuration files in the `etc/config` directory. Values are `key=value`. +-Options in a `{type}.local.properties` file (where `{type}` is `c++` or similar) override anything in the +-`{type}.defaults.properties` file. There is a `.gitignore` file to ignore `*.local.*` files, so these won't be checked +-into git, and you won't find yourself fighting with updated versions when you `git pull`. For more information see +-[Adding a Compiler](docs/AddingACompiler.md). ++Configuring compiler explorer is achieved via configuration files in the `etc/config` directory. Values are ++ `key=value`. Options in a `{type}.local.properties` file (where `{type}` is `c++` or similar) override anything in the ++ `{type}.defaults.properties` file. There is a `.gitignore` file to ignore `*.local.*` files, so these won't be checked ++ into git, and you won't find yourself fighting with updated versions when you `git pull`. For more information see ++ [Adding a Compiler](docs/AddingACompiler.md). + +-Check [CONTRIBUTING.md](./CONTRIBUTING.md) for detailed information about how you can contribute to **Compiler +-Explorer**, and the [docs](./docs) folder for specific details regarding various things you might want to do, such as +-how to add new compilers or languages to the site. ++A [Road map](docs/Roadmap.md) is available which gives a little insight into ++ the future plans for **Compiler Explorer**. + + ### Running a local instance + +-If you want to point it at your own GCC or similar binaries, either edit the `etc/config/LANG.defaults.properties` or +-else make a new one with the name `LANG.local.properties`, substituting `LANG` as needed. `*.local.properties` files +-have the highest priority when loading properties. ++If you want to point it at your own GCC or similar binaries, either edit the ++ `etc/config/LANG.defaults.properties` or else make a new one with ++ the name `LANG.local.properties`, substituting `LANG` as needed. ++ `*.local.properties` files have the highest priority when loading properties. + +-For a quick and easy way to add local compilers, use the +-[CE Properties Wizard](etc/scripts/ce-properties-wizard/) which automatically detects and configures compilers +-for [30+ languages](etc/scripts/ce-properties-wizard/README.md#supported-languages). +-See [Adding a Compiler](docs/AddingACompiler.md) for more details. +- +-If you want to support multiple compilers and languages like [godbolt.org](https://godbolt.org), you can use the +-`bin/ce_install install compilers` command in the [infra](https://github.com/compiler-explorer/infra) project to install +-all or some of the compilers. Compilers installed in this way can be loaded through the configuration in +-`etc/config/*.amazon.properties`. If you need to deploy in a completely offline environment, you may need to remove some +-parts of the configuration that are pulled from `www.godbolt.ms@443`. +- +-When running in a corporate setting the URL shortening service can be replaced by an internal one if the default storage +-driver isn't appropriate for your environment. To do this, add a new module in `lib/shortener/myservice.js` and set the +-`urlShortenService` variable in configuration. This module should export a single function, see the +-[tinyurl module](lib/shortener/tinyurl.ts) for an example. ++When running in a corporate setting the URL shortening service can be replaced ++ by an internal one if the default storage driver isn't appropriate for your ++ environment. To do this, add a new module in `lib/shortener/myservice.js` and ++ set the `urlShortenService` variable in configuration. This module should ++ export a single function, see the [tinyurl module](lib/shortener/tinyurl.js) ++ for an example. + + ### RESTful API + +-There's a simple restful API that can be used to do compiles to asm and to list compilers. ++There's a simple restful API that can be used to do compiles to asm and to ++ list compilers. + + You can find the API documentation [here](docs/API.md). + +@@ -136,8 +110,7 @@ You can find the API documentation [here](docs/API.md). + + We run a [Compiler Explorer Discord](https://discord.gg/B5WacA7), which is a place to discuss using or developing + Compiler Explorer. We also have a presence on the [cpplang](https://cppalliance.org/slack/) Slack channel +-`#compiler_explorer` and we have +-[a public mailing list](https://groups.google.com/forum/#!forum/compiler-explorer-discussion). ++`#compiler_explorer` and we have [a public mailing list](https://groups.google.com/forum/#!forum/compiler-explorer-discussion). + + There's a development channel on the discord, and also a + [development mailing list](https://groups.google.com/forum/#!forum/compiler-explorer-development). +@@ -145,31 +118,22 @@ There's a development channel on the discord, and also a + Feel free to raise an issue on [github](https://github.com/compiler-explorer/compiler-explorer/issues) or + [email Matt directly](mailto:matt@godbolt.org) for more help. + +-## Official domains +- +-Following are the official domains for Compiler Explorer: +- +-- https://godbolt.org/ +-- https://godbo.lt/ +-- https://compiler-explorer.com/ +- +-The domains allow arbitrary subdomains, e.g., https://foo.godbolt.org/, which is convenient since each subdomain has an +-independent local state. Also, language subdomains such as https://rust.compiler-explorer.com/ will load with that +-language already selected. +- + ## Credits + +-**Compiler Explorer** is maintained by the awesome people listed in the [AUTHORS](AUTHORS.md) file. +- +-We would like to thank the contributors listed in the [CONTRIBUTORS](CONTRIBUTORS.md) file, who have helped shape +-**Compiler Explorer**. ++**Compiler Explorer** is maintained by the awesome people listed in the ++ [AUTHORS](AUTHORS.md) file. + +-We would also like to especially thank these people for their contributions to **Compiler Explorer**: ++We would like to thank the contributors listed in the ++ [CONTRIBUTORS](CONTRIBUTORS.md) file, who have helped shape **Compiler Explorer**. + +-- [Gabriel Devillers](https://github.com/voxelf) (_while working for [Kalray](http://www.kalrayinc.com/)_) ++We would also like to specially thank these people for their contributions to ++ **Compiler Explorer**: ++- [Gabriel Devillers](https://github.com/voxelf) ++ (_while working for [Kalray](http://www.kalrayinc.com/)_) + - [Johan Engelen](https://github.com/JohanEngelen) + - [Joshua Sheard](https://github.com/jsheard) ++- [Marc Poulhiès](https://github.com/dkm) + - [Andrew Pardoe](https://github.com/AndrewPardoe) + +-Many [amazing sponsors](https://godbolt.org/#sponsors), both individuals and companies, have helped fund and promote +-Compiler Explorer. ++A number of [amazing sponsors](https://godbolt.org/#sponsors), both individuals and companies, have helped fund and ++ promote Compiler Explorer. +diff --git a/WINDOWS-DEPLOYMENT.md b/WINDOWS-DEPLOYMENT.md +new file mode 100644 +index 000000000..1feb7964c +--- /dev/null ++++ b/WINDOWS-DEPLOYMENT.md +@@ -0,0 +1,281 @@ ++# Compiler Explorer - Windows Local Deployment ++ ++**Branch:** `CE-for-Win-Pascal-2025` ++ ++This is a customized build of Compiler Explorer for **local Windows deployment** with commercial and open-source compilers. It is **NOT** intended for public cloud deployment. ++ ++## Purpose ++ ++This branch removes the hundreds of cloud-based compilers from the public Compiler Explorer and configures it to use: ++- **Commercial Compilers**: Delphi (Embarcadero), C++Builder ++- **Free Pascal Compilers**: Multiple FPC versions ++- **Open Source Compilers**: Rust, Python (local installations) ++ ++## Differences from Public CE ++ ++### Key Customizations ++ ++1. **Minimal Language Support** (`lib/languages.ts`) ++ - Only includes: C++, Pascal, Rust, Python ++ - Full language list backed up in `lib/languages.ts.full-backup` ++ ++2. **Local Compiler Configurations** (`etc/config/*.local.properties`) ++ - Pascal compilers (FPC + Delphi) ++ - C++ compilers (C++Builder, MinGW) ++ - Paths configured for Windows file system ++ ++3. **TypeScript Modernization** ++ - Migrated from 2021 JavaScript to 2025 TypeScript ++ - Better type safety and modern features ++ - Smart Pascal program/unit detection ++ ++## Installation ++ ++### Prerequisites ++ ++- **Node.js**: Latest LTS version (v18+ recommended) ++- **npm**: Latest version ++- **Compilers** installed locally (see Configuration section) ++ ++### Setup Steps ++ ++1. **Clone this branch**: ++ ```bash ++ git clone -b CE-for-Win-Pascal-2025 https://github.com/pmcgee69/compiler-explorer.git ++ cd compiler-explorer ++ ``` ++ ++2. **Install dependencies**: ++ ```bash ++ npm install ++ npm install -g webpack webpack-cli ++ ``` ++ ++3. **Configure compilers** (see Configuration section below) ++ ++4. **Build**: ++ ```bash ++ npm run webpack ++ ``` ++ ++5. **Start server**: ++ ```bash ++ npm start ++ ``` ++ ++6. **Access**: Browse to http://localhost:10240/ ++ ++## Configuration ++ ++### Pascal Compilers ++ ++Edit `etc/config/pascal.local.properties` to configure your local installations: ++ ++#### Free Pascal (FPC) ++ ++```properties ++compiler.fpc331.exe=C:\fpcupdeluxe\fpc\bin\x86_64-win64\fpc.exe ++compiler.fpc322.exe=C:\FPC\3.2.2\bin\i386-win32\fpc.exe ++# Add more FPC versions as needed ++``` ++ ++#### Delphi Compilers ++ ++```properties ++# 32-bit Delphi ++compiler.delphi27.exe=C:\Program Files (x86)\Embarcadero\Studio\21.0\Bin\DCC32.EXE ++compiler.delphi27.name=x86 Delphi 10.4.2 Sydney ++ ++# 64-bit Delphi ++compiler.delphi27_64.exe=C:\Program Files (x86)\Embarcadero\Studio\21.0\Bin\DCC64.EXE ++compiler.delphi27_64.name=x64 Delphi 10.4.2 Sydney ++``` ++ ++#### Object Dump Tool ++ ++Configure objdump for assembly output: ++```properties ++group.fpc.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe ++group.delphi.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe ++``` ++ ++### C++ Compilers ++ ++Edit `etc/config/c++.local.properties` for C++Builder and other C++ compilers. ++ ++### Adding Your Own Compilers ++ ++1. Edit the appropriate `.local.properties` file ++2. Follow the existing patterns for compiler groups ++3. Ensure paths use Windows format (`C:\...`) ++4. Test with `npm start` ++ ++## Features ++ ++### Pascal Support ++ ++The current implementation includes **smart program/unit detection**: ++ ++- **`pascal-utils.ts`**: Automatically detects whether source is a `program` or `unit` ++- Extracts program name from source code ++- Handles both `.pas` (units) and `.dpr` (programs) files ++- No hardcoded filenames - intelligent detection ++ ++Example: ++```pascal ++program MyApp; // Detected as program, executable named "MyApp" ++``` ++ ++```pascal ++unit MyUnit; // Detected as unit, wrapped in dummy project ++``` ++ ++### Supported Languages ++ ++- **C++**: Full support with multiple compilers ++- **Pascal**: FPC and Delphi with program/unit detection ++- **Rust**: Local rustc installation ++- **Python**: Local Python installation ++ ++## Updating from Main Branch ++ ++To update this branch with latest improvements from public CE: ++ ++### Option 1: Merge (Recommended for small updates) ++ ++```bash ++git checkout CE-for-Win-Pascal-2025 ++git fetch origin main ++git merge origin/main ++# Resolve conflicts in lib/languages.ts - keep your minimal version ++# Test thoroughly ++``` ++ ++### Option 2: Rebase (For major updates) ++ ++This is more complex but gives cleaner history. See `REBASE-NOTES.md` for details. ++ ++### Files to Protect During Updates ++ ++When merging/rebasing, **preserve these customizations**: ++ ++1. **`lib/languages.ts`** - Your minimal language list ++2. **`etc/config/*.local.properties`** - Your compiler paths ++3. **`WINDOWS-DEPLOYMENT.md`** - This documentation ++ ++These are the **only** files that differ significantly from main branch. ++ ++## Development ++ ++### Build Commands ++ ++- **Development mode**: `npm run webpack:dev` ++- **Production build**: `npm run webpack` ++- **Watch mode**: `npm run webpack:watch` ++ ++### Testing ++ ++- **All tests**: `npm test` ++- **Minimal tests**: `npm run test-min` ++- **TypeScript check**: `npm run ts-check` ++- **Linting**: `npm run lint` ++ ++### Pre-commit Checks ++ ++Always run before committing: ++```bash ++npm run ts-check ++npm run lint ++npm run test-min ++``` ++ ++Or use the comprehensive check: ++```bash ++make pre-commit ++``` ++ ++## Troubleshooting ++ ++### Build Errors ++ ++**Issue**: TypeScript compilation errors ++- **Solution**: Run `npm run ts-check` to see detailed errors ++- Check that `lib/languages.ts` has correct type definitions ++ ++**Issue**: Missing dependencies ++- **Solution**: Delete `node_modules` and run `npm install` again ++ ++### Runtime Errors ++ ++**Issue**: Compiler not found ++- **Solution**: Check paths in `.local.properties` files ++- Ensure compilers are actually installed at those paths ++- Use absolute Windows paths (e.g., `C:\...`) ++ ++**Issue**: objdump errors ++- **Solution**: Install TDM-GCC or similar to get objdump.exe ++- Update objdumper paths in properties files ++ ++## Architecture Notes ++ ++### Language Detection ++ ++The modern TypeScript implementation uses: ++ ++- **Type-safe language definitions**: `types/languages.interfaces.ts` ++- **Monaco editor integration**: Each language maps to Monaco syntax highlighting ++- **Example code loading**: Automatic loading from `examples/{lang}/default{ext}` ++ ++### Pascal Compiler Classes ++ ++- **`pascal.ts`**: Main FPC compiler class (cross-platform) ++- **`pascal-win.ts`**: Windows-specific Delphi compiler ++- **`pascal-utils.ts`**: Helper functions for program/unit detection ++ ++## Maintenance Notes ++ ++### When Updating Compiler Versions ++ ++1. Update version in `.local.properties` ++2. Test compilation ++3. Update README if version numbers are mentioned ++ ++### Adding New Compilers ++ ++1. Add to appropriate `.local.properties` file ++2. Test with sample code ++3. Document in this file ++ ++## History ++ ++- **2021**: Original `CE-for-Win-Pascal` branch created ++- **2025**: Modernized to `CE-for-Win-Pascal-2025` ++ - Migrated to TypeScript ++ - Updated to latest CE architecture ++ - Added Rust and Python support ++ - Improved Pascal program/unit handling ++ ++## Backup ++ ++The following backups are maintained: ++ ++- **`lib/languages.ts.full-backup`**: Complete language list from main branch ++- **Git tag**: `CE-for-Win-Pascal-backup-20251122` - Previous branch state ++ ++## License ++ ++Same as Compiler Explorer: BSD 2-Clause License ++ ++## Support ++ ++This is a private/local deployment. For issues: ++ ++1. Check this documentation ++2. Check public CE docs: https://github.com/compiler-explorer/compiler-explorer ++3. For commercial compiler issues, contact vendor support ++ ++## See Also ++ ++- **Main CE Project**: https://github.com/compiler-explorer/compiler-explorer ++- **CE Documentation**: https://github.com/compiler-explorer/compiler-explorer/blob/main/docs/ ++- **Windows Native Guide**: https://github.com/compiler-explorer/compiler-explorer/blob/main/docs/WindowsNative.md +diff --git a/docs/AddingLocalCompilers.md b/docs/AddingLocalCompilers.md +new file mode 100644 +index 000000000..df358d61b +--- /dev/null ++++ b/docs/AddingLocalCompilers.md +@@ -0,0 +1,75 @@ ++# Adding Local Compilers - Quick Guide ++ ++This is a quick reference for adding local compilers to your Compiler Explorer instance. For comprehensive details, see [AddingACompiler.md](AddingACompiler.md). ++ ++## Configuration Files ++ ++Compiler Explorer uses `.local.properties` files for local configurations. These override defaults and are gitignored. ++ ++Common files: ++- `etc/config/c++.local.properties` - C++ compilers ++- `etc/config/pascal-win.local.properties` - Delphi compilers (Windows) ++- `etc/config/rust.local.properties` - Rust compilers ++- `etc/config/python.local.properties` - Python interpreters ++ ++## Example 1: Adding Delphi Compilers ++ ++**File:** `etc/config/pascal-win.local.properties` ++ ++```ini ++compilers=&delphi64 ++ ++group.delphi64.compilers=delphi27_64:delphi28_64 ++group.delphi64.compilerType=pascal-win ++ ++compiler.delphi27_64.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\20.0\\Bin\\DCC64.EXE ++compiler.delphi27_64.name=x64 Delphi 10.4.2 Sydney ++ ++compiler.delphi28_64.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\22.0\\Bin\\DCC64.EXE ++compiler.delphi28_64.name=x64 Delphi 11 Alexandria ++``` ++ ++## Example 2: Adding C++Builder Compilers ++ ++**File:** `etc/config/c++.local.properties` ++ ++```ini ++compilers=&embclang64:&embclang64mod ++ ++# Classic 64-bit compilers ++group.embclang64.compilers=bcc11_64:bcc123_64 ++group.embclang64.groupName=C++Builder x64 ++ ++compiler.bcc11_64.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\22.0\\bin\\bcc64.exe ++compiler.bcc11_64.name=C++Builder 11 x64 ++compiler.bcc11_64.ldPath=C:\\Program Files (x86)\\Embarcadero\\Studio\\22.0\\lib\\win64\\release ++ ++compiler.bcc123_64.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\23.0\\bin\\bcc64.exe ++compiler.bcc123_64.name=C++Builder 12.3 x64 ++compiler.bcc123_64.ldPath=C:\\Program Files (x86)\\Embarcadero\\Studio\\23.0\\lib\\win64\\release ++ ++# Modern 64-bit compilers (12.3+) ++group.embclang64mod.compilers=bcc123_64mod ++group.embclang64mod.groupName=C++Builder x64 modern ++ ++compiler.bcc123_64mod.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\23.0\\bin64\\bcc64x.exe ++compiler.bcc123_64mod.name=C++Builder 12.3 x64 modern ++compiler.bcc123_64mod.ldPath=C:\\Program Files (x86)\\Embarcadero\\Studio\\23.0\\lib\\win64x\\release|C:\\Program Files (x86)\\Embarcadero\\Studio\\23.0\\x86_64-w64-mingw32\\lib ++ ++defaultCompiler=bcc123_64mod ++``` ++ ++## Key Properties ++ ++- **compilers** - List of compiler IDs or groups (prefix groups with `&`) ++- **compiler.ID.exe** - Path to compiler executable ++- **compiler.ID.name** - Display name ++- **compiler.ID.ldPath** - Library paths for linking (use `|` separator for multiple paths) ++- **group.NAME.compilers** - List of compilers in group ++- **group.NAME.compilerType** - Compiler type (e.g., `pascal-win`, `gcc`) ++ ++## See Also ++ ++- [AddingACompiler.md](AddingACompiler.md) - Full documentation ++- [Configuration.md](Configuration.md) - Configuration system details ++- [DelphiCppBuilderSpecifics.md](DelphiCppBuilderSpecifics.md) - Delphi and C++Builder setup guide +diff --git a/docs/DelphiCppBuilderSpecifics.md b/docs/DelphiCppBuilderSpecifics.md +new file mode 100644 +index 000000000..bec1b094b +--- /dev/null ++++ b/docs/DelphiCppBuilderSpecifics.md +@@ -0,0 +1,48 @@ ++# Delphi & C++Builder Specifics ++ ++```The original basis document: https://github.com/compiler-explorer/compiler-explorer/blob/main/docs/WindowsNative.md``` ++ ++## Installation ++ ++- Install latest Node.js (my current = v14.17.0) ++- Install latest npm (my current = 7.14.0) ++ ++- Clone this branch of Compiler Explorer repository into a directory: https://github.com/compiler-explorer/compiler-explorer ++ ++ ie https://github.com/pmcgee69/compiler-explorer/edit/CE-for-Win-Pascal ++ ++In the directory, run: ++- npm install ++- npm install webpack -g ++- npm install webpack-cli -g ++- npm update webpack ++ ++You may need to fix up some directories... maybe comment out eg the C++ options. Changes were made to the following files from this repo: ++ ++- \lib\languages.js - Comment out languages as desired. ++- \lib\languages.PasWin.js ++ ++For Object Pascal compilers: ++- \lib\compilers\pascal.js ++- \lib\compilers\pascal-win.js ++- \etc\config\pascal.defaults.properties ++ ++For C++ compilers: ++- \etc\config\c++.win32.properties ++- \etc\config\c++.local.properties ++ ++Finally: ++- npm start ++ ++To access Compiler Explorer, browse to: (http://localhost:10240/) ++ ++## Screenshots ++ ++// --- --- --- --- --- --- --- --- ++![Install](https://user-images.githubusercontent.com/11953157/120332379-455d1f80-c321-11eb-85ae-e9cd31cc9814.png) ++// --- --- --- --- --- --- --- --- ++![Start Server](https://user-images.githubusercontent.com/11953157/120332478-5d34a380-c321-11eb-9bd5-a2a86447e963.png) ++// --- --- --- --- --- --- --- --- ++![Compiler Explorer - Object Pascal](https://user-images.githubusercontent.com/11953157/120333650-7b4ed380-c322-11eb-8042-5b1d710a5814.png) ++// --- --- --- --- --- --- --- --- ++![Compiler Explorer - C++](https://user-images.githubusercontent.com/11953157/120351986-eaccbf00-c332-11eb-939c-a0338e333945.png) +diff --git a/etc/config/c++.local.properties b/etc/config/c++.local.properties +new file mode 100644 +index 000000000..2af44a976 +--- /dev/null ++++ b/etc/config/c++.local.properties +@@ -0,0 +1,126 @@ ++# Compiler groups to include (msclang and vc2019 commented out - not installed) ++compilers=&embclang32:&embclang64:&embclang64mod:&tdmgcc ++ ++# replace with the result of `echo %INCLUDE%` ++# if you want a specific includePath for a specific compiler, ++# you can set it up in that compiler's config, with, say ++# compiler.my_clang.include=path_to_libc++ ++ ++includePath=C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\atlmfc\include;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\include;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\ucrt;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\shared;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\winrt;C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\cppwinrt; ++ ++#Listed individually ... ++#C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\atlmfc\include; ++#C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\include; ++#C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\ucrt; ++#C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\shared; ++#C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\um; ++#C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\winrt; ++#C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\cppwinrt ++ ++ ++# replace with the result of `where undname.exe` from a developer command prompt ++# Using llvm-cxxfilt for Clang-based C++Builder compilers ++ ++demangler=D:\\ghcup\\ghc\\9.6.6\\mingw\\bin\\llvm-cxxfilt.exe ++ ++# the compiler you want compiler explorer to start up in ++ ++defaultCompiler=bcc131_64 ++ ++ ++# note: adding new compiler groups ++# the default compiler groups should be fine for most, ++# but if you'd like to add more groups ++# (for example, for vc 2015, or for gcc), ++# you can uncomment and edit the following lines. ++# check `c++.win32.properties` for how to modify the group options ++ ++ ++# C++Builder compilers - Installed versions: 10.4.2, 11, 12.3, 13.1 ++group.embclang32.compilers =bcc104_32:bcc11_32:bcc123_32:bcc131_32 ++group.embclang32.groupName =C++Builder x86 ++group.embclang32.options =-Wno-user-defined-literals -Wno-comment -I'C:\Program Files (x86)\Embarcadero\Studio\20.0\include\dinkumware64' -I'C:\Program Files (x86)\Embarcadero\Studio\20.0\include\windows\crtl' ++group.embclang32.intelAsm =-masm=intel ++ ++group.embclang64.compilers =bcc104_64:bcc11_64:bcc123_64:bcc131_64 ++group.embclang64.groupName =C++Builder x64 ++group.embclang64.options =-Wno-user-defined-literals -Wno-comment -I'C:\Program Files (x86)\Embarcadero\Studio\20.0\include\dinkumware64' -I'C:\Program Files (x86)\Embarcadero\Studio\20.0\include\windows\crtl' ++group.embclang64.intelAsm =-masm=intel ++ ++group.embclang64mod.compilers=bcc123_64mod:bcc131_64mod ++group.embclang64mod.groupName=C++Builder x64 modern ++group.embclang64mod.options =-Wno-user-defined-literals -Wno-comment -isystem "C:\Program Files (x86)\Embarcadero\Studio\23.0\include" -isystem "C:\Program Files (x86)\Embarcadero\Studio\23.0\include\x86_64-w64-mingw32\c++\v1" -isystem "C:\Program Files (x86)\Embarcadero\Studio\23.0\lib\clang\15.0.7\include" -isystem "C:\Program Files (x86)\Embarcadero\Studio\23.0\include\x86_64-w64-mingw32" ++group.embclang64mod.intelAsm =-masm=intel ++ ++# MS Clang compilers - not installed on this system ++#group.msclang.compilers =mscl32:mscl64 ++#group.msclang.groupName =ms clang ++ ++# C++Builder 10.4.2 Sydney (Studio 20.0) ++compiler.bcc104_32.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\bin\bcc32x.exe ++compiler.bcc104_32.name =C++Builder 10.4.2 x86 ++compiler.bcc104_32.ldPath =C:\Program Files (x86)\Embarcadero\Studio\20.0\lib\win32c\release ++ ++compiler.bcc104_64.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\bin\bcc64.exe ++compiler.bcc104_64.name =C++Builder 10.4.2 x64 ++compiler.bcc104_64.ldPath =C:\Program Files (x86)\Embarcadero\Studio\20.0\lib\win64\release ++ ++# C++Builder 11 Alexandria (Studio 22.0) ++compiler.bcc11_32.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\bin\bcc32x.exe ++compiler.bcc11_32.name =C++Builder 11.3 x86 ++compiler.bcc11_32.ldPath =C:\Program Files (x86)\Embarcadero\Studio\22.0\lib\win32c\release ++ ++compiler.bcc11_64.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\bin\bcc64.exe ++compiler.bcc11_64.name =C++Builder 11.3 x64 ++compiler.bcc11_64.ldPath =C:\Program Files (x86)\Embarcadero\Studio\22.0\lib\win64\release ++ ++# C++Builder 12.3 Athens (Studio 23.0) ++compiler.bcc123_32.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\bin\bcc32x.exe ++compiler.bcc123_32.name =C++Builder 12.3 x86 ++compiler.bcc123_32.ldPath =C:\Program Files (x86)\Embarcadero\Studio\23.0\lib\win32c\release ++ ++compiler.bcc123_64.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\bin\bcc64.exe ++compiler.bcc123_64.name =C++Builder 12.3 x64 ++compiler.bcc123_64.ldPath =C:\Program Files (x86)\Embarcadero\Studio\23.0\lib\win64\release ++ ++compiler.bcc123_64mod.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\bin64\bcc64x.exe ++compiler.bcc123_64mod.name =C++Builder 12.3 x64 modern ++compiler.bcc123_64mod.ldPath =C:\Program Files (x86)\Embarcadero\Studio\23.0\lib\win64x\release|C:\Program Files (x86)\Embarcadero\Studio\23.0\x86_64-w64-mingw32\lib|C:\Program Files (x86)\Embarcadero\Studio\23.0\lib\clang\15.0.7\lib\windows ++ ++# C++Builder 13.1 Florence (Studio 37.0) ++compiler.bcc131_32.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\bin\bcc32x.exe ++compiler.bcc131_32.name =C++Builder 13.1 Florence x86 ++compiler.bcc131_32.ldPath =C:\Program Files (x86)\Embarcadero\Studio\37.0\lib\win32c\release ++ ++compiler.bcc131_64.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\bin\bcc64.exe ++compiler.bcc131_64.name =C++Builder 13.1 Florence x64 ++compiler.bcc131_64.ldPath =C:\Program Files (x86)\Embarcadero\Studio\37.0\lib\win64\release ++ ++compiler.bcc131_64mod.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\bin64\bcc64x.exe ++compiler.bcc131_64mod.name =C++Builder 13.1 Florence x64 modern ++compiler.bcc131_64mod.ldPath =C:\Program Files (x86)\Embarcadero\Studio\37.0\lib\win64x\release|C:\Program Files (x86)\Embarcadero\Studio\37.0\x86_64-w64-mingw32\lib|C:\Program Files (x86)\Embarcadero\Studio\37.0\lib\clang\15.0.7\lib\windows ++ ++#compiler.mscl32.exe =C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\Llvm\bin\clang++.exe ++#compiler.mscl32.name =clang x86 ++#compiler.mscl32.options =-m32 ++# ++#compiler.mscl64.exe =C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\Llvm\x64\bin\clang++.exe ++#compiler.mscl64.name =clang x64 ++ ++# Visual C++ 2019 compilers - not installed on this system ++#group.vc2019.compilers=vc2019_32:vc2019_64 ++#group.vc2019.groupName=Visual C++ 2019 ++# ++#compiler.vc2019_32.exe =C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\bin\Hostx64\x86\cl.exe ++#compiler.vc2019_32.name =VC 2019 x86 ++#compiler.vc2019_32.include =C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\lib\x86\ ++# ++#compiler.vc2019_64.exe =C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\bin\Hostx64\x64\cl.exe ++#compiler.vc2019_64.name =VC 2019 x64 ++ ++# gcc ++group.tdmgcc.compilers =gcc64 ++ ++compiler.gcc64.exe =C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\g++.exe ++compiler.gcc64.name =tdm64 g++ 9.0 ++ +diff --git a/etc/config/pascal-win.defaults.properties b/etc/config/pascal-win.defaults.properties +new file mode 100644 +index 000000000..9f7ca15bb +--- /dev/null ++++ b/etc/config/pascal-win.defaults.properties +@@ -0,0 +1,9 @@ ++# Default settings for Pascal on Windows ++compilerType=pascal-win ++supportsBinary=true ++rpathFlag=-O ++objdumper=objdump ++demangler= ++versionFlag=| grep "Version" ++ ++# Compilers are defined in pascal-win.local.properties +diff --git a/etc/config/pascal-win.local.properties b/etc/config/pascal-win.local.properties +new file mode 100644 +index 000000000..17cd7a614 +--- /dev/null ++++ b/etc/config/pascal-win.local.properties +@@ -0,0 +1,76 @@ ++compilers=&delphi:&delphi64 ++maxLinesOfAsm=1000 ++rpathFlag=-O ++ ++################################# ++# Delphi - Installed versions: 10.4.2, 11, 12.3, 13.1 ++group.delphi.compilers=delphi27:delphi28:delphi29:delphi31 ++group.delphi.compilerType=pascal-win ++group.delphi.demangler= ++group.delphi.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe ++#D:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin\objdump.exe ++group.delphi.versionFlags=| grep "Version" ++ ++group.delphi64.compilers=delphi27_64:delphi28_64:delphi29_64:delphi31_64 ++group.delphi64.compilerType=pascal-win ++group.delphi64.demangler= ++group.delphi64.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe ++group.delphi64.versionFlags=| grep "Version" ++ ++# Older Delphi versions - not installed on this system ++#compiler.delphi21.exe =C:\Program Files (x86)\Embarcadero\Studio\15.0\Bin\DCC32.EXE ++#compiler.delphi21.name =x86 Delphi XE7 ++# ++#compiler.delphi22.exe =C:\Program Files (x86)\Embarcadero\Studio\16.0\Bin\DCC32.EXE ++#compiler.delphi22.name =x86 Delphi XE8 ++# ++#compiler.delphi23.exe =C:\Program Files (x86)\Embarcadero\Studio\17.0\bin\DCC32.exe ++#compiler.delphi23.name =x86 Delphi 10 Seattle ++# ++#compiler.delphi23_64.exe =C:\Program Files (x86)\Embarcadero\Studio\17.0\bin\DCC64.exe ++#compiler.delphi23_64.name=x64 Delphi 10 Seattle ++# ++#compiler.delphi24.exe =c:\Program Files (x86)\Embarcadero\Studio\18.0\Bin\DCC32.EXE ++#compiler.delphi24.name =x86 Delphi 10.1 Berlin ++# ++#compiler.delphi24_64.exe =c:\Program Files (x86)\Embarcadero\Studio\18.0\Bin\DCC64.EXE ++#compiler.delphi24_64.name=x64 Delphi 10.1 Berlin ++# ++#compiler.delphi25.exe =C:\Program Files (x86)\Embarcadero\Studio\19.0\Bin\DCC32.EXE ++#compiler.delphi25.name =x86 Delphi 10.2 Tokyo ++# ++#compiler.delphi25_64.exe =C:\Program Files (x86)\Embarcadero\Studio\19.0\Bin\DCC64.EXE ++#compiler.delphi25_64.name=x64 Delphi 10.2 Tokyo ++# ++#compiler.delphi26.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC32.EXE ++#compiler.delphi26.name =x86 Delphi 10.3 Rio ++# ++#compiler.delphi26_64.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC64.EXE ++#compiler.delphi26_64.name=x64 Delphi 10.3 Rio ++ ++compiler.delphi27.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC32.EXE ++compiler.delphi27.name =x86 Delphi 10.4.2 Sydney ++ ++compiler.delphi27_64.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC64.EXE ++compiler.delphi27_64.name=x64 Delphi 10.4.2 Sydney ++ ++# Delphi 11 Alexandria (Studio 22.0) ++compiler.delphi28.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\Bin\DCC32.EXE ++compiler.delphi28.name =x86 Delphi 11 Alexandria ++ ++compiler.delphi28_64.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\Bin\DCC64.EXE ++compiler.delphi28_64.name=x64 Delphi 11 Alexandria ++ ++# Delphi 12.3 Athens (Studio 23.0) ++compiler.delphi29.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\Bin\DCC32.EXE ++compiler.delphi29.name =x86 Delphi 12.3 Athens ++ ++compiler.delphi29_64.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\Bin\DCC64.EXE ++compiler.delphi29_64.name=x64 Delphi 12.3 Athens ++ ++# Delphi 13.1 (Studio 37.0) ++compiler.delphi31.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\Bin\DCC32.EXE ++compiler.delphi31.name =x86 Delphi 13.1 ++ ++compiler.delphi31_64.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\Bin\DCC64.EXE ++compiler.delphi31_64.name=x64 Delphi 13.1 +\ No newline at end of file +diff --git a/etc/config/pascal.local.properties b/etc/config/pascal.local.properties +new file mode 100644 +index 000000000..b6a2a0521 +--- /dev/null ++++ b/etc/config/pascal.local.properties +@@ -0,0 +1,156 @@ ++# Delphi and FPC compilers for Windows ++compilers=&delphi:&delphi64:&fpc ++maxLinesOfAsm=1000 ++rpathFlag=-O ++defaultCompiler=delphi31_64 ++delayCleanupTemp=true ++ ++# Delphi 32-bit group ++group.delphi.compilers=delphi27:delphi28:delphi29:delphi31 ++group.delphi.compilerType=pascal-win ++group.delphi.demangler= ++group.delphi.objdumper=C:\\Program Files (x86)\\Embarcadero\\Dev-Cpp\\TDM-GCC-64\\bin\\objdump.exe ++group.delphi.versionFlags=| grep "Version" ++ ++# Delphi 64-bit group ++group.delphi64.compilers=delphi27_64:delphi28_64:delphi29_64:delphi31_64 ++group.delphi64.compilerType=pascal-win ++group.delphi64.demangler= ++group.delphi64.objdumper=C:\\Program Files (x86)\\Embarcadero\\Dev-Cpp\\TDM-GCC-64\\bin\\objdump.exe ++group.delphi64.versionFlags=| grep "Version" ++ ++# Individual compiler definitions ++compiler.delphi27.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\20.0\\Bin\\DCC32.EXE ++compiler.delphi27.name=x86 Delphi 10.4.2 Sydney ++ ++compiler.delphi27_64.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\20.0\\Bin\\DCC64.EXE ++compiler.delphi27_64.name=x64 Delphi 10.4.2 Sydney ++ ++compiler.delphi28.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\22.0\\Bin\\DCC32.EXE ++compiler.delphi28.name=x86 Delphi 11.3 Alexandria ++ ++compiler.delphi28_64.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\22.0\\Bin\\DCC64.EXE ++compiler.delphi28_64.name=x64 Delphi 11.3 Alexandria ++ ++compiler.delphi29.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\23.0\\Bin\\DCC32.EXE ++compiler.delphi29.name=x86 Delphi 12.3 Athens ++ ++compiler.delphi29_64.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\23.0\\Bin\\DCC64.EXE ++compiler.delphi29_64.name=x64 Delphi 12.3 Athens ++ ++compiler.delphi31.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\37.0\\Bin\\DCC32.EXE ++compiler.delphi31.name=x86 Delphi 13.1 Florence ++ ++compiler.delphi31_64.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\37.0\\Bin\\DCC64.EXE ++compiler.delphi31_64.name=x64 Delphi 13.1 Florence ++ ++# FPC (Free Pascal Compiler) group ++group.fpc.compilers=fpc300:fpc320:fpc322:fpc331 ++group.fpc.compilerType=pascal ++group.fpc.isSemVer=true ++group.fpc.baseName=FPC ++group.fpc.versionFlag=-iV ++group.fpc.supportsBinary=true ++group.fpc.supportsExecute=true ++group.fpc.objdumper=C:\\Program Files (x86)\\Embarcadero\\Dev-Cpp\\TDM-GCC-64\\bin\\objdump.exe ++ ++# FPC 3.0.0 ++compiler.fpc300.exe=D:\\fpc\\3.0.0\\fpc\\bin\\x86_64-win64\\fpc.exe ++compiler.fpc300.semver=3.0.0 ++compiler.fpc300.name=FPC 3.0.0 ++ ++# FPC 3.2.0 ++compiler.fpc320.exe=D:\\fpc\\3.2.0\\fpc\\bin\\x86_64-win64\\fpc.exe ++compiler.fpc320.semver=3.2.0 ++compiler.fpc320.name=FPC 3.2.0 ++ ++# FPC 3.2.2 ++compiler.fpc322.exe=D:\\fpc\\3.2.2\\fpc\\bin\\x86_64-win64\\fpc.exe ++compiler.fpc322.semver=3.2.2 ++compiler.fpc322.name=FPC 3.2.2 ++ ++# FPC 3.3.1 ++compiler.fpc331.exe=D:\\fpc\\3.3.1\\fpc\\bin\\x86_64-win64\\fpc.exe ++compiler.fpc331.semver=3.3.1 ++compiler.fpc331.name=FPC 3.3.1 ++ ++ ++ ++ ++################################# ++# Delphi - Configured in pascal-win.local.properties ++#group.delphi.compilers=delphi27:delphi28:delphi29:delphi31 ++#group.delphi.compilerType=pascal-win ++#group.delphi.demangler= ++#group.delphi.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe ++#group.delphi.versionFlags=| grep "Version" ++# ++#group.delphi64.compilers=delphi27_64:delphi28_64:delphi29_64:delphi31_64 ++#group.delphi64.compilerType=pascal-win ++#group.delphi64.demangler= ++#group.delphi64.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe ++#group.delphi64.versionFlags=| grep "Version" ++ ++#compiler.delphi21.exe =C:\Program Files (x86)\Embarcadero\Studio\15.0\Bin\DCC32.EXE ++#compiler.delphi21.name =x86 Delphi XE7 ++ ++#compiler.delphi22.exe =C:\Program Files (x86)\Embarcadero\Studio\16.0\Bin\DCC32.EXE ++#compiler.delphi22.name =x86 Delphi XE8 ++ ++#compiler.delphi23.exe =C:\Program Files (x86)\Embarcadero\Studio\17.0\bin\DCC32.exe ++#compiler.delphi23.name =x86 Delphi 10 Seattle ++ ++#compiler.delphi23_64.exe =C:\Program Files (x86)\Embarcadero\Studio\17.0\bin\DCC64.exe ++#compiler.delphi23_64.name=x64 Delphi 10 Seattle ++ ++#compiler.delphi24.exe =c:\Program Files (x86)\Embarcadero\Studio\18.0\Bin\DCC32.EXE ++#ompiler.delphi24.name =x86 Delphi 10.1 Berlin ++ ++#compiler.delphi24_64.exe =c:\Program Files (x86)\Embarcadero\Studio\18.0\Bin\DCC64.EXE ++#compiler.delphi24_64.name=x64 Delphi 10.1 Berlin ++ ++# Delphi 10.4.2 Sydney (Studio 20.0) ++#compiler.delphi27.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC32.EXE ++#compiler.delphi27.name =x86 Delphi 10.4.2 Sydney ++# ++#compiler.delphi27_64.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC64.EXE ++#compiler.delphi27_64.name=x64 Delphi 10.4.2 Sydney ++ ++# Delphi 11 Alexandria (Studio 22.0) ++#compiler.delphi28.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\Bin\DCC32.EXE ++#compiler.delphi28.name =x86 Delphi 11 Alexandria ++# ++#compiler.delphi28_64.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\Bin\DCC64.EXE ++#compiler.delphi28_64.name=x64 Delphi 11 Alexandria ++ ++# Delphi 12.3 Athens (Studio 23.0) ++#compiler.delphi29.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\Bin\DCC32.EXE ++#compiler.delphi29.name =x86 Delphi 12.3 Athens ++# ++#compiler.delphi29_64.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\Bin\DCC64.EXE ++#compiler.delphi29_64.name=x64 Delphi 12.3 Athens ++ ++# Delphi 13.1 (Studio 37.0) ++#compiler.delphi31.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\Bin\DCC32.EXE ++#compiler.delphi31.name =x86 Delphi 13.1 ++# ++#compiler.delphi31_64.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\Bin\DCC64.EXE ++#compiler.delphi31_64.name=x64 Delphi 13.1 ++ ++ ++ ++ ++ ++ ++################################# ++################################# ++# Installed libs (See c++.amazon.properties for a scheme of libs group) ++libs= ++ ++################################# ++################################# ++# Installed tools ++ ++#tools=llvm-mcatrunk:pahole ++ ++ +diff --git a/etc/config/python.local.properties b/etc/config/python.local.properties +new file mode 100644 +index 000000000..ee1badb64 +--- /dev/null ++++ b/etc/config/python.local.properties +@@ -0,0 +1,15 @@ ++# Windows Local Deployment - Python ++# Local Python installation - version 3.13.9 ++ ++compilers=pythonlocal ++defaultCompiler=pythonlocal ++ ++compiler.pythonlocal.exe=python ++compiler.pythonlocal.name=Python 3.13.9 (local) ++compiler.pythonlocal.semver=3.13.9 ++ ++supportsBinary=false ++interpreted=true ++compilerType=python ++objdumper= ++instructionSet=python +diff --git a/etc/config/rust.local.properties b/etc/config/rust.local.properties +new file mode 100644 +index 000000000..b9bdb160a +--- /dev/null ++++ b/etc/config/rust.local.properties +@@ -0,0 +1,30 @@ ++# Windows Local Deployment - Rust ++# Local rustc installation - version 1.85.0 ++ ++compilers=rustclocal ++defaultCompiler=rustclocal ++ ++compiler.rustclocal.exe=C:\Users\User\.cargo\bin\rustc.exe ++compiler.rustclocal.name=rustc 1.85.0 (local) ++compiler.rustclocal.semver=1.85.0 ++ ++supportsBinary=true ++supportsBinaryObject=true ++compilerType=rust ++demangler= ++demanglerArgs= ++objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe ++stubRe=\bmain\b ++stubText=pub fn main() {/*stub provided by Compiler Explorer*/} ++ ++versionFlag=-vV ++ ++libs= ++ ++# Clippy tool - enabled ++tools=clippy ++tools.clippy.name=Clippy ++tools.clippy.exe=C:\Users\User\.cargo\bin\cargo-clippy.exe ++tools.clippy.type=postcompilation ++tools.clippy.class=clippy-tool ++tools.clippy.stdinHint=disabled +diff --git a/examples/c++/default.cpp b/examples/c++/default.cpp +index e8c4fe4ec..827199622 100644 +--- a/examples/c++/default.cpp ++++ b/examples/c++/default.cpp +@@ -1,4 +1,9 @@ +-// Type your code here, or load an example. ++#include ++ + int square(int num) { + return num * num; ++} ++ ++int main() { ++ std::cout << "hello"; + } +\ No newline at end of file +diff --git a/examples/pascal/default.pas b/examples/pascal/default.pas +index 1bbf29d51..f3f570b5f 100644 +--- a/examples/pascal/default.pas ++++ b/examples/pascal/default.pas +@@ -1,16 +1,10 @@ +-unit output; +- +-interface +- +-function Square(const num: Integer): Integer; +- +-implementation +- +-// Type your code here, or load an example. ++program test; + + function Square(const num: Integer): Integer; + begin + Square := num * num; + end; + ++begin ++ writeln('Helllooo.'); + end. +diff --git a/examples/rust/default.rs b/examples/rust/default.rs +index acf928648..db45321a1 100644 +--- a/examples/rust/default.rs ++++ b/examples/rust/default.rs +@@ -12,4 +12,4 @@ pub fn square(num: i32) -> i32 { + } + + // If you use `main()`, declare it as `pub` to see it in the output: +-// pub fn main() { ... } ++ pub fn main() { print!("hello") } +diff --git a/lib/compilers/pascal-utils.ts b/lib/compilers/pascal-utils.ts +index 4ddc7c322..db18f7e84 100644 +--- a/lib/compilers/pascal-utils.ts ++++ b/lib/compilers/pascal-utils.ts +@@ -22,14 +22,41 @@ + // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + // POSSIBILITY OF SUCH DAMAGE. + ++function stripCommentsForDetection(source: string): string { ++ // For detection only - remove comments entirely ++ let result = source.replace(/\/\/.*$/gm, ''); ++ result = result.replace(/\{[^}]*\}/g, ''); ++ result = result.replace(/\(\*[\s\S]*?\*\)/g, ''); ++ return result; ++} ++ ++export function stripComments(source: string): string { ++ // Blank out comment content but preserve line numbers ++ // For // comments: keep the // but blank the rest of the line ++ let result = source.replace(/\/\/.*$/gm, '//'); ++ // For { } comments: keep delimiters, blank content ++ result = result.replace(/\{[^}]*\}/g, match => '{}'); ++ // For (* *) comments: keep delimiters, preserve newlines in content ++ result = result.replace(/\(\*[\s\S]*?\*\)/g, match => { ++ const lines = match.split('\n'); ++ if (lines.length === 1) { ++ return '(**)'; ++ } else { ++ // Multi-line: preserve newlines ++ return '(*' + '\n'.repeat(lines.length - 1) + '*)'; ++ } ++ }); ++ return result; ++} ++ + export function isProgram(source: string) { + const re = /\s?program\s+([\w.-]*);/i; +- return !!re.test(source); ++ return !!re.test(stripCommentsForDetection(source)); + } + + export function isUnit(source: string) { + const re = /\s?unit\s+([\w.-]*);/i; +- return !!re.test(source); ++ return !!re.test(stripCommentsForDetection(source)); + } + + export function getUnitname(source: string) { +diff --git a/lib/compilers/pascal-win.ts b/lib/compilers/pascal-win.ts +index 46768f413..7c300f3b4 100644 +--- a/lib/compilers/pascal-win.ts ++++ b/lib/compilers/pascal-win.ts +@@ -36,7 +36,7 @@ import {unwrap} from '../assert.js'; + import {BaseCompiler} from '../base-compiler.js'; + import {CompilationEnvironment} from '../compilation-env.js'; + import {MapFileReaderDelphi} from '../mapfiles/map-file-delphi.js'; +-import {PELabelReconstructor} from '../pe32-support.js'; ++import {PELabelReconstructor, PELabelReconstructorOptions} from '../pe32-support.js'; + import * as utils from '../utils.js'; + + import * as pascalUtils from './pascal-utils.js'; +@@ -48,6 +48,8 @@ export class PascalWinCompiler extends BaseCompiler { + + mapFilename: string | null; + dprFilename: string; ++ projectBaseName: string; ++ isWrapperProgram: boolean; + + constructor(info: PreliminaryCompilerInfo, env: CompilationEnvironment) { + super(info, env); +@@ -56,6 +58,8 @@ export class PascalWinCompiler extends BaseCompiler { + this.mapFilename = null; + this.compileFilename = 'output.pas'; + this.dprFilename = 'prog.dpr'; ++ this.projectBaseName = 'prog'; ++ this.isWrapperProgram = false; + } + + override getSharedLibraryPathsAsArguments() { +@@ -77,11 +81,11 @@ export class PascalWinCompiler extends BaseCompiler { + } + + override getExecutableFilename(dirPath: string) { +- return path.join(dirPath, 'prog.exe'); ++ return path.join(dirPath, this.projectBaseName + '.exe'); + } + + override getOutputFilename(dirPath: string) { +- return path.join(dirPath, 'prog.exe'); ++ return path.join(dirPath, this.projectBaseName + '.exe'); + } + + override filename(fn: string) { +@@ -100,12 +104,27 @@ export class PascalWinCompiler extends BaseCompiler { + outputFilename = this.getOutputFilename(path.dirname(outputFilename)); + } + +- let args = [...this.compiler.objdumperArgs, '-d', outputFilename]; ++ let args = [...this.compiler.objdumperArgs, '-d', '-l', outputFilename]; + if (intelAsm) args = args.concat(['-M', 'intel']); ++ console.log(`[Delphi] Running objdump on: ${outputFilename}`); ++ console.log(`[Delphi] Objdump command: ${this.compiler.objdumper} ${args.join(' ')}`); + return this.exec(this.compiler.objdumper, args, {maxOutput: 1024 * 1024 * 1024}).then(objResult => { + if (objResult.code === 0) { + result.asm = objResult.stdout; ++ const lines = objResult.stdout.split('\n'); ++ console.log(`[Delphi] Objdump output: ${lines.length} lines`); ++ console.log(`[Delphi] First 5 lines with addresses:`); ++ let addressLineCount = 0; ++ for (let i = 0; i < Math.min(50, lines.length); i++) { ++ if (lines[i].match(/^\s*[0-9a-f]+:/)) { ++ console.log(`[Delphi] Line ${i}: ${lines[i]}`); ++ if (++addressLineCount >= 5) break; ++ } ++ } + } else { ++ console.log(`[Delphi] Objdump failed with code ${objResult.code}`); ++ console.log(`[Delphi] Objdump stderr: ${objResult.stderr}`); ++ console.log(`[Delphi] Objdump stdout: ${objResult.stdout}`); + result.asm = ''; + } + +@@ -125,9 +144,14 @@ export class PascalWinCompiler extends BaseCompiler { + } + + override async writeAllFiles(dirPath: string, source: string, files: FiledataPair[]) { ++ // Strip comment content to avoid highlighting commented code ++ const cleanedSource = pascalUtils.stripComments(source); ++ + let inputFilename: string; + if (pascalUtils.isProgram(source)) { +- inputFilename = path.join(dirPath, this.dprFilename); ++ // Use the program name from the source, like FPC does ++ const progName = pascalUtils.getProgName(source); ++ inputFilename = path.join(dirPath, progName + '.dpr'); + } else { + const unitName = pascalUtils.getUnitname(source); + if (unitName) { +@@ -137,7 +161,7 @@ export class PascalWinCompiler extends BaseCompiler { + } + } + +- await fs.writeFile(inputFilename, source); ++ await fs.writeFile(inputFilename, cleanedSource); + + if (files && files.length > 0) { + await this.writeMultipleFiles(files, dirPath); +@@ -158,24 +182,36 @@ export class PascalWinCompiler extends BaseCompiler { + execOptions = this.getDefaultExecOptions(); + } + +- const alreadyHasDPR = path.basename(inputFilename) === this.dprFilename; +- + const tempPath = path.dirname(inputFilename); +- const projectFile = path.join(tempPath, this.dprFilename); ++ const inputBasename = path.basename(inputFilename); ++ const isDprFile = inputBasename.toLowerCase().endsWith('.dpr'); + +- this.mapFilename = path.join(tempPath, 'prog.map'); ++ let projectFile: string; ++ let projectBaseName: string; + +- inputFilename = inputFilename.replaceAll('/', '\\'); +- +- if (!alreadyHasDPR) { +- const unitFilepath = path.basename(inputFilename); +- const unitName = unitFilepath.replace(/.pas$/i, ''); ++ if (isDprFile) { ++ // Input is already a .dpr program file, compile it directly (like FPC does) ++ projectFile = inputFilename; ++ projectBaseName = inputBasename.replace(/\.dpr$/i, ''); ++ this.isWrapperProgram = false; ++ } else { ++ // Input is a .pas unit file, create a dummy prog.dpr project that uses it ++ const unitFilepath = inputBasename; ++ const unitName = unitFilepath.replace(/\.pas$/i, ''); ++ projectFile = path.join(tempPath, this.dprFilename); ++ projectBaseName = 'prog'; + await this.saveDummyProjectFile(projectFile, unitName, unitFilepath); ++ this.isWrapperProgram = true; + } + ++ this.projectBaseName = projectBaseName; ++ this.mapFilename = path.join(tempPath, projectBaseName + '.map'); ++ ++ inputFilename = inputFilename.replaceAll('/', '\\'); ++ + options.pop(); + +- options.unshift('-CC', '-W', '-H', '-GD', '-$D+', '-V', '-B'); ++ options.unshift('-CC', '-W', '-H', '-GD', '-$D+', '-$L+', '-$O-', '-$W+', '-$C-', '-V', '-B'); + + options.push(projectFile); + execOptions.customCwd = tempPath; +@@ -194,13 +230,125 @@ export class PascalWinCompiler extends BaseCompiler { + filters.binary = true; + filters.dontMaskFilenames = true; + filters.preProcessBinaryAsmLines = (asmLines: string[]) => { ++ console.log(`[Delphi] Map filename: ${this.mapFilename}`); + const mapFileReader = new MapFileReaderDelphi(unwrap(this.mapFilename)); +- const reconstructor = new PELabelReconstructor(asmLines, false, mapFileReader, false); ++ // If this is a wrapper program (unit case), exclude prog.dpr segments ++ const excludedUnits = this.isWrapperProgram ? ['prog.dpr'] : []; ++ const reconstructor = new PELabelReconstructor( ++ asmLines, ++ mapFileReader, ++ new Set([PELabelReconstructorOptions.DeleteBeforeFirstSegment]), ++ excludedUnits, ++ ); + reconstructor.run('output'); + +- return reconstructor.asmLines; ++ // Convert source line markers from /app/filename:line format to .loc directives ++ const fileMap = new Map(); ++ let fileCounter = 1; ++ const result: string[] = []; ++ let topLevelFileAdded = false; ++ let firstFilename: string | null = null; ++ ++ let sourceMarkerCount = 0; ++ for (const line of reconstructor.asmLines) { ++ const sourceMatch = line.match(/^\/app\/(.+):(\d+)$/); ++ if (sourceMatch) { ++ const filename = sourceMatch[1]; ++ const lineNumber = sourceMatch[2]; ++ ++ // Skip line 0 markers - they indicate no line info available ++ // Let the previous source line continue instead of breaking highlighting ++ if (lineNumber === '0') { ++ continue; ++ } ++ ++ // Track the first file we encounter ++ if (firstFilename === null) { ++ firstFilename = filename; ++ } ++ ++ // Only use markers from the first file (skip wrapper prog.dpr if unit exists) ++ if (filename !== firstFilename) { ++ continue; ++ } ++ ++ sourceMarkerCount++; ++ if (sourceMarkerCount <= 10) { ++ console.log(`[Delphi] Source marker ${sourceMarkerCount}: file="${filename}" line=${lineNumber}`); ++ } ++ ++ // Add top-level .file directive once at the very beginning (like FPC does) ++ if (!topLevelFileAdded) { ++ result.unshift(`\t.file "${filename}"`); ++ topLevelFileAdded = true; ++ } ++ ++ // Get or assign file number for DWARF debug info ++ if (!fileMap.has(filename)) { ++ const fileNum = fileCounter++; ++ fileMap.set(filename, fileNum); ++ result.push(`\t.file ${fileNum} "${filename}"`); ++ } ++ ++ const fileNum = fileMap.get(filename)!; ++ result.push(`\t.loc ${fileNum} ${lineNumber} 0`); ++ } else { ++ result.push(line); ++ } ++ } ++ ++ console.log(`[Delphi] Total source markers found: ${sourceMarkerCount}`); ++ ++ // Truncate unmapped sections to max 5 lines ++ return this.truncateUnmappedSections(result); + }; + + return []; + } ++ ++ /** ++ * Truncate sections with no source line mappings to max 5 lines ++ * This removes large finalization/initialization blocks that have no debug info ++ */ ++ truncateUnmappedSections(asmLines: string[]): string[] { ++ const maxUnmappedLines = 5; ++ const sourceMarkerRegex = /^\s*\.loc\s+/; ++ const addressRegex = /^\s*[\da-f]+:/i; ++ ++ let lineIdx = 0; ++ let unmappedCount = 0; ++ let unmappedStartIdx = -1; ++ ++ while (lineIdx < asmLines.length) { ++ const line = asmLines[lineIdx]; ++ ++ if (sourceMarkerRegex.test(line)) { ++ // Found a source marker - reset counter ++ if (unmappedCount > maxUnmappedLines && unmappedStartIdx !== -1) { ++ // Delete excess unmapped lines ++ const deleteCount = unmappedCount - maxUnmappedLines; ++ asmLines.splice(unmappedStartIdx + maxUnmappedLines, deleteCount); ++ lineIdx -= deleteCount; ++ } ++ unmappedCount = 0; ++ unmappedStartIdx = -1; ++ } else if (addressRegex.test(line)) { ++ // This is an assembly line with an address ++ if (unmappedStartIdx === -1) { ++ unmappedStartIdx = lineIdx; ++ } ++ unmappedCount++; ++ } ++ ++ lineIdx++; ++ } ++ ++ // Handle trailing unmapped section ++ if (unmappedCount > maxUnmappedLines && unmappedStartIdx !== -1) { ++ const deleteCount = unmappedCount - maxUnmappedLines; ++ asmLines.splice(unmappedStartIdx + maxUnmappedLines, deleteCount); ++ } ++ ++ return asmLines; ++ } + } +diff --git a/lib/compilers/pascal.ts b/lib/compilers/pascal.ts +index 0d66a261c..86add4183 100644 +--- a/lib/compilers/pascal.ts ++++ b/lib/compilers/pascal.ts +@@ -133,11 +133,19 @@ export class FPCCompiler extends BaseCompiler { + + override getExecutableFilename(dirPath: string, outputFilebase: string, key?: CacheKey | CompilationCacheKey) { + const source = (key && (key as CacheKey).source) || ''; ++ let progName; + if (key && pascalUtils.isProgram(source)) { +- return path.join(dirPath, pascalUtils.getProgName(source)); ++ progName = pascalUtils.getProgName(source); ++ } else { ++ progName = 'prog'; ++ } ++ ++ // Add .exe extension on Windows (process.platform is 'win32' for all Windows) ++ if (process.platform === 'win32' && !progName.endsWith('.exe')) { ++ progName += '.exe'; + } + +- return path.join(dirPath, 'prog'); ++ return path.join(dirPath, progName); + } + + override async objdump( +diff --git a/lib/compilers/win32.ts b/lib/compilers/win32.ts +index fed83ad15..b0d9a781c 100644 +--- a/lib/compilers/win32.ts ++++ b/lib/compilers/win32.ts +@@ -40,7 +40,7 @@ import {copyNeededDlls} from '../binaries/win-utils.js'; + import {CompilationEnvironment} from '../compilation-env.js'; + import {MapFileReaderVS} from '../mapfiles/map-file-vs.js'; + import {VcAsmParser} from '../parsers/asm-parser-vc.js'; +-import {PELabelReconstructor} from '../pe32-support.js'; ++import {PELabelReconstructor, PELabelReconstructorOptions} from '../pe32-support.js'; + + export class Win32Compiler extends BaseCompiler { + static get key() { +@@ -252,7 +252,7 @@ export class Win32Compiler extends BaseCompiler { + const mapFileReader = new MapFileReaderVS(mapFilename); + + filters.preProcessBinaryAsmLines = asmLines => { +- const reconstructor = new PELabelReconstructor(asmLines, false, mapFileReader); ++ const reconstructor = new PELabelReconstructor(asmLines, mapFileReader); + reconstructor.run('output.s.obj'); + + return reconstructor.asmLines; +diff --git a/lib/compilers/wine-vc.ts b/lib/compilers/wine-vc.ts +index 10b88f068..b3ce298ae 100644 +--- a/lib/compilers/wine-vc.ts ++++ b/lib/compilers/wine-vc.ts +@@ -31,7 +31,7 @@ import {BaseCompiler} from '../base-compiler.js'; + import {CompilationEnvironment} from '../compilation-env.js'; + import {MapFileReaderVS} from '../mapfiles/map-file-vs.js'; + import {VcAsmParser} from '../parsers/asm-parser-vc.js'; +-import {PELabelReconstructor} from '../pe32-support.js'; ++import {PELabelReconstructor, PELabelReconstructorOptions} from '../pe32-support.js'; + + import {VCParser} from './argument-parsers.js'; + +@@ -90,7 +90,7 @@ export class WineVcCompiler extends BaseCompiler { + const mapFileReader = new MapFileReaderVS(mapFilename); + + filters.preProcessBinaryAsmLines = (asmLines: string[]) => { +- const reconstructor = new PELabelReconstructor(asmLines, false, mapFileReader); ++ const reconstructor = new PELabelReconstructor(asmLines, mapFileReader); + reconstructor.run('output.s.obj'); + + return reconstructor.asmLines; +diff --git a/lib/languages.ts b/lib/languages.ts +index 71d69e157..b5807622b 100644 +--- a/lib/languages.ts ++++ b/lib/languages.ts +@@ -22,6 +22,11 @@ + // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + // POSSIBILITY OF SUCH DAMAGE. + ++// CUSTOM BUILD FOR WINDOWS - LOCAL DEPLOYMENT ONLY ++// This is a minimal language configuration for local Windows deployment ++// with commercial compilers (Delphi, C++Builder, Free Pascal) and local open-source compilers ++// Full language list is backed up in languages.ts.full-backup ++ + import fs from 'node:fs'; + import path from 'node:path'; + +@@ -41,18 +46,8 @@ type DefKeys = + | 'digitSeparator'; + type LanguageDefinition = Pick; + ++// Minimal language definitions for Windows local deployment + const definitions: Record = { +- jakt: { +- name: 'Jakt', +- monaco: 'jakt', +- extensions: ['.jakt'], +- alias: [], +- logoFilename: null, +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: 'cppp', +- }, + 'c++': { + name: 'C++', + monaco: 'cppp', +@@ -65,690 +60,31 @@ const definitions: Record = { + monacoDisassembly: null, + digitSeparator: "'", + }, +- ada: { +- name: 'Ada', +- monaco: 'ada', +- extensions: ['.adb', '.ads'], +- alias: [], +- logoFilename: 'ada.svg', +- logoFilenameDark: 'ada-dark.svg', +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- algol68: { +- name: 'Algol68', +- monaco: 'algol68', +- extensions: ['.a68'], +- alias: [], +- logoFilename: null, +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- analysis: { +- name: 'Analysis', +- monaco: 'asm', +- extensions: ['.asm'], // maybe add more? Change to a unique one? +- alias: ['tool', 'tools'], +- logoFilename: 'analysis.png', // TODO: Find a better alternative +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- tooltip: 'A collection of asm analysis tools', +- }, +- 'android-java': { +- name: 'Android Java', +- monaco: 'java', +- extensions: ['.java'], +- alias: [], +- logoFilename: 'android.svg', +- logoFilenameDark: 'android-dark.svg', +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- digitSeparator: '_', +- }, +- 'android-kotlin': { +- name: 'Android Kotlin', +- monaco: 'kotlin', +- extensions: ['.kt'], +- alias: [], +- logoFilename: 'android.svg', +- logoFilenameDark: 'android-dark.svg', +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- digitSeparator: '_', +- }, +- assembly: { +- name: 'Assembly', +- monaco: 'asm', +- extensions: ['.asm', '.6502', '.s'], +- alias: ['asm'], +- logoFilename: 'assembly.png', // TODO: Find a better alternative +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- c: { +- name: 'C', +- monaco: 'nc', +- extensions: ['.c', '.h'], +- alias: [], +- logoFilename: 'c.svg', +- logoFilenameDark: null, +- formatter: 'clangformat', +- previewFilter: /^\s*#include/, +- monacoDisassembly: null, +- digitSeparator: "'", +- }, +- c3: { +- name: 'C3', +- monaco: 'c3', +- extensions: ['.c3'], +- alias: [], +- logoFilename: 'c3.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- carbon: { +- name: 'Carbon', +- monaco: 'carbon', +- extensions: ['.carbon'], +- alias: [], +- logoFilename: 'carbon.png', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- coccinelle_for_c: { +- name: 'C with Coccinelle', +- monaco: 'nc', +- extensions: ['.c', '.h'], +- alias: [], +- logoFilename: 'c.svg', +- logoFilenameDark: null, +- formatter: 'clangformat', +- previewFilter: /^\s*#include/, +- monacoDisassembly: null, +- digitSeparator: "'", +- }, +- coccinelle_for_cpp: { +- name: 'C++ with Coccinelle', +- monaco: 'cppp', +- extensions: ['.cpp', '.h'], +- alias: [], +- logoFilename: 'cpp.svg', +- logoFilenameDark: null, +- formatter: 'clangformat', +- previewFilter: /^\s*#include/, +- monacoDisassembly: null, +- digitSeparator: "'", +- }, +- circle: { +- name: 'C++ (Circle)', +- monaco: 'cppcircle', +- extensions: ['.cpp', '.cxx', '.h', '.hpp', '.hxx', '.c'], +- alias: [], +- previewFilter: /^\s*#include/, +- logoFilename: 'cpp.svg', // TODO: Find a better alternative +- logoFilenameDark: null, +- formatter: null, +- monacoDisassembly: null, +- digitSeparator: "'", +- }, +- circt: { +- name: 'CIRCT', +- monaco: 'mlir', +- extensions: ['.mlir'], +- alias: [], +- logoFilename: 'circt.svg', +- formatter: null, +- logoFilenameDark: null, +- previewFilter: null, +- monacoDisassembly: 'mlir', +- }, +- clean: { +- name: 'Clean', +- monaco: 'clean', +- extensions: ['.icl'], +- alias: [], +- logoFilename: 'clean.svg', // TODO: Find a better alternative +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- clojure: { +- name: 'Clojure', +- monaco: 'clojure', +- extensions: ['.clj'], +- alias: [], +- logoFilename: 'clojure.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- cmake: { +- name: 'CMake', +- monaco: 'cmake', +- extensions: ['.txt'], +- alias: [], +- logoFilename: 'cmake.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- cmakescript: { +- name: 'CMakeScript', +- monaco: 'cmake', +- extensions: ['.cmake'], +- alias: [], +- logoFilename: 'cmake.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- cobol: { +- name: 'COBOL', +- monaco: 'cobol', +- extensions: ['.cob', '.cbl', '.cobol'], +- alias: [], +- logoFilename: null, // TODO: Find a better alternative +- formatter: null, +- logoFilenameDark: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- cpp_for_opencl: { +- name: 'C++ for OpenCL', +- monaco: 'cpp-for-opencl', +- extensions: ['.clcpp', '.cl', '.ocl'], +- alias: [], +- logoFilename: 'opencl.svg', // TODO: Find a better alternative +- logoFilenameDark: 'opencl-dark.svg', +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- digitSeparator: "'", +- }, +- mlir: { +- name: 'MLIR', +- monaco: 'mlir', +- extensions: ['.mlir'], +- alias: [], +- logoFilename: 'mlir.svg', +- formatter: null, +- logoFilenameDark: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- cppx: { +- name: 'Cppx', +- monaco: 'cppp', +- extensions: ['.cpp', '.cxx', '.h', '.hpp', '.hxx', '.c'], +- alias: [], +- logoFilename: 'cpp.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: /^\s*#include/, +- monacoDisassembly: null, +- digitSeparator: "'", +- }, +- cppx_blue: { +- name: 'Cppx-Blue', +- monaco: 'cppx-blue', +- extensions: ['.blue', '.cpp', '.cxx', '.h', '.hpp', '.hxx', '.c'], +- alias: [], +- logoFilename: 'cpp.svg', // TODO: Find a better alternative +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- cppx_gold: { +- name: 'Cppx-Gold', +- monaco: 'cppx-gold', +- extensions: ['.usyntax', '.cpp', '.cxx', '.h', '.hpp', '.hxx', '.c'], +- alias: [], +- logoFilename: 'cpp.svg', // TODO: Find a better alternative +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- digitSeparator: "'", +- }, +- cpp2_cppfront: { +- name: 'Cpp2-cppfront', +- monaco: 'cpp2-cppfront', +- extensions: ['.cpp2'], +- alias: [], +- logoFilename: 'cpp.svg', // TODO: Find a better alternative +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: 'cppp', +- digitSeparator: "'", +- }, +- crystal: { +- name: 'Crystal', +- monaco: 'crystal', +- extensions: ['.cr'], +- alias: [], +- logoFilename: 'crystal.svg', +- logoFilenameDark: 'crystal-dark.svg', +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- digitSeparator: '_', +- }, +- csharp: { +- name: 'C#', +- monaco: 'csharp', +- extensions: ['.cs'], +- alias: [], +- logoFilename: 'dotnet.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- digitSeparator: '_', +- }, +- cuda: { +- name: 'CUDA C++', +- monaco: 'cuda', +- extensions: ['.cu', '.cuh'], +- alias: ['nvcc'], +- logoFilename: 'cuda.svg', +- logoFilenameDark: 'cuda-dark.svg', +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- digitSeparator: "'", +- }, +- d: { +- name: 'D', +- monaco: 'd', +- extensions: ['.d'], +- alias: [], +- logoFilename: 'd.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- dart: { +- name: 'Dart', +- monaco: 'dart', +- extensions: ['.dart'], +- alias: [], +- logoFilename: 'dart.svg', +- logoFilenameDark: null, +- formatter: 'dartformat', +- previewFilter: null, +- monacoDisassembly: null, +- }, +- elixir: { +- name: 'Elixir', +- monaco: 'elixir', +- extensions: ['.ex'], +- alias: [], +- logoFilename: 'elixir.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- erlang: { +- name: 'Erlang', +- monaco: 'erlang', +- extensions: ['.erl', '.hrl'], +- alias: [], +- logoFilename: 'erlang.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- fortran: { +- name: 'Fortran', +- monaco: 'fortran', +- extensions: ['.f90', '.F90', '.f95', '.F95', '.f'], +- alias: [], +- logoFilename: 'fortran.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- fsharp: { +- name: 'F#', +- monaco: 'fsharp', +- extensions: ['.fs'], +- alias: [], +- logoFilename: 'fsharp.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- glsl: { +- name: 'GLSL', +- monaco: 'glsl', +- extensions: ['.glsl'], +- alias: [], +- logoFilename: 'glsl.svg', +- logoFilenameDark: 'glsl-dark.svg', +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- go: { +- name: 'Go', +- monaco: 'go', +- extensions: ['.go'], ++ pascal: { ++ name: 'Pascal', ++ monaco: 'pascal', ++ extensions: ['.pas', '.dpr', '.inc'], + alias: [], +- logoFilename: 'go.svg', +- logoFilenameDark: null, ++ logoFilename: 'pascal.svg', ++ logoFilenameDark: 'pascal-dark.svg', + formatter: null, + previewFilter: null, + monacoDisassembly: null, +- digitSeparator: '_', + }, +- haskell: { +- name: 'Haskell', +- monaco: 'haskell', +- extensions: ['.hs', '.haskell'], ++ rust: { ++ name: 'Rust', ++ monaco: 'rustp', ++ extensions: ['.rs'], + alias: [], +- logoFilename: 'haskell.png', +- logoFilenameDark: null, +- formatter: null, ++ logoFilename: 'rust.svg', ++ logoFilenameDark: 'rust-dark.svg', ++ formatter: 'rustfmt', + previewFilter: null, + monacoDisassembly: null, + digitSeparator: '_', + }, +- hlsl: { +- name: 'HLSL', +- monaco: 'hlsl', +- extensions: ['.hlsl', '.hlsli'], +- alias: [], +- logoFilename: 'hlsl.png', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- helion: { +- name: 'Helion', +- monaco: 'python', +- extensions: ['.py'], +- alias: [], +- logoFilename: 'helion.png', +- logoFilenameDark: 'helion.png', +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- digitSeparator: '_', +- }, +- hook: { +- name: 'Hook', +- monaco: 'hook', +- extensions: ['.hk', '.hook'], +- alias: [], +- logoFilename: 'hook.png', +- logoFilenameDark: 'hook-dark.png', +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- hylo: { +- name: 'Hylo', +- monaco: 'hylo', +- extensions: ['.hylo'], +- alias: [], +- logoFilename: 'hylo.png', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- il: { +- name: 'IL', +- monaco: 'asm', +- extensions: ['.il'], +- alias: [], +- logoFilename: 'dotnet.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- ispc: { +- name: 'ispc', +- monaco: 'ispc', +- extensions: ['.ispc'], +- alias: [], +- logoFilename: 'ispc.png', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- java: { +- name: 'Java', +- monaco: 'java', +- extensions: ['.java'], +- alias: [], +- logoFilename: 'java.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- digitSeparator: '_', +- }, +- julia: { +- name: 'Julia', +- monaco: 'julia', +- extensions: ['.jl'], +- alias: [], +- logoFilename: 'julia.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- digitSeparator: '_', +- }, +- kotlin: { +- name: 'Kotlin', +- monaco: 'kotlin', +- extensions: ['.kt'], +- alias: [], +- logoFilename: 'kotlin.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- digitSeparator: '_', +- }, +- llvm: { +- name: 'LLVM IR', +- monaco: 'llvm-ir', +- extensions: ['.ll'], +- alias: [], +- logoFilename: 'llvm.png', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- llvm_mir: { +- name: 'LLVM MIR', +- monaco: 'llvm-ir', +- extensions: ['.mir'], +- alias: [], +- logoFilename: 'llvm.png', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- modula2: { +- name: 'Modula-2', +- monaco: 'modula2', +- extensions: ['.mod'], +- alias: [], +- logoFilename: null, +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- mojo: { +- name: 'Mojo', +- monaco: 'mojo', +- extensions: ['.mojo', '.🔥'], +- alias: [], +- logoFilename: 'mojo.svg', +- logoFilenameDark: null, +- formatter: 'mblack', +- previewFilter: null, +- monacoDisassembly: null, +- digitSeparator: '_', +- }, +- nim: { +- name: 'Nim', +- monaco: 'nim', +- extensions: ['.nim'], +- alias: [], +- logoFilename: 'nim.png', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- numba: { +- name: 'Numba', +- monaco: 'python', +- extensions: ['.py'], +- alias: [], +- logoFilename: 'numba.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- nix: { +- name: 'Nix', +- monaco: 'nix', +- extensions: ['.nix'], +- alias: [], +- logoFilename: 'nix.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- objc: { +- name: 'Objective-C', +- monaco: 'objective-c', +- extensions: ['.m'], +- alias: [], +- logoFilename: null, +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- 'objc++': { +- name: 'Objective-C++', +- monaco: 'objective-c', +- extensions: ['.mm'], +- alias: [], +- logoFilename: null, +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- digitSeparator: "'", +- }, +- ocaml: { +- name: 'OCaml', +- monaco: 'ocaml', +- extensions: ['.ml', '.mli'], +- alias: [], +- logoFilename: 'ocaml.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- odin: { +- name: 'Odin', +- monaco: 'odin', +- extensions: ['.odin'], +- alias: [], +- logoFilename: 'odin.png', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- openclc: { +- name: 'OpenCL C', +- monaco: 'openclc', +- extensions: ['.cl', '.ocl'], +- alias: [], +- logoFilename: 'opencl.svg', +- logoFilenameDark: 'opencl-dark.svg', +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- pascal: { +- name: 'Pascal', +- monaco: 'pascal', +- extensions: ['.pas', '.dpr', '.inc'], +- alias: [], +- logoFilename: 'pascal.svg', // TODO: Find a better alternative +- logoFilenameDark: 'pascal-dark.svg', +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- pony: { +- name: 'Pony', +- monaco: 'pony', +- extensions: ['.pony'], +- alias: [], +- logoFilename: 'pony.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- ptx: { +- name: 'PTX', +- monaco: 'ptx', +- extensions: ['.ptx'], +- alias: [], +- logoFilename: 'cuda.svg', +- logoFilenameDark: 'cuda-dark.svg', +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- python: { +- name: 'Python', ++ python: { ++ name: 'Python', + monaco: 'python', + extensions: ['.py'], + alias: [], +@@ -759,311 +95,6 @@ const definitions: Record = { + monacoDisassembly: null, + digitSeparator: '_', + }, +- racket: { +- name: 'Racket', +- monaco: 'scheme', +- extensions: ['.rkt'], +- alias: [], +- logoFilename: 'racket.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: 'scheme', +- }, +- raku: { +- name: 'Raku', +- monaco: 'perl', +- extensions: ['.raku', '.rakutest', '.rakumod', '.rakudoc'], +- alias: ['Perl 6'], +- logoFilename: 'camelia.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- ruby: { +- name: 'Ruby', +- monaco: 'ruby', +- extensions: ['.rb'], +- alias: [], +- logoFilename: 'ruby.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: 'asmruby', +- digitSeparator: '_', +- }, +- rust: { +- name: 'Rust', +- monaco: 'rustp', +- extensions: ['.rs'], +- alias: [], +- logoFilename: 'rust.svg', +- logoFilenameDark: 'rust-dark.svg', +- formatter: 'rustfmt', +- previewFilter: null, +- monacoDisassembly: null, +- digitSeparator: '_', +- }, +- sail: { +- name: 'Sail', +- monaco: 'sail', +- extensions: ['.sail'], +- alias: [], +- logoFilename: 'sail.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- snowball: { +- name: 'Snowball', +- monaco: 'swift', +- extensions: ['.sn'], +- alias: [], +- logoFilename: 'snowball.svg', +- logoFilenameDark: 'snowball.svg', +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- scala: { +- name: 'Scala', +- monaco: 'scala', +- extensions: ['.scala'], +- alias: [], +- logoFilename: 'scala.png', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- digitSeparator: '_', +- }, +- slang: { +- name: 'Slang', +- monaco: 'slang', +- extensions: ['.slang'], +- alias: [], +- logoFilename: 'slang.svg', +- logoFilenameDark: 'slang-dark.svg', +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- solidity: { +- name: 'Solidity', +- monaco: 'sol', +- extensions: ['.sol'], +- alias: [], +- logoFilename: 'solidity.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- spice: { +- name: 'Spice', +- monaco: 'spice', +- extensions: ['.spice'], +- alias: [], +- logoFilename: 'spice.png', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- spirv: { +- name: 'SPIR-V', +- monaco: 'spirv', +- extensions: ['.spvasm'], +- alias: [], +- logoFilename: 'spirv.svg', +- logoFilenameDark: 'spirv-dark.svg', +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- swift: { +- name: 'Swift', +- monaco: 'swift', +- extensions: ['.swift'], +- alias: [], +- logoFilename: 'swift.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- digitSeparator: '_', +- }, +- tablegen: { +- name: 'LLVM TableGen', +- monaco: 'tablegen', +- extensions: ['.td'], +- alias: [], +- logoFilename: 'llvm.png', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- toit: { +- name: 'Toit', +- monaco: 'toit', +- extensions: ['.toit'], +- alias: [], +- logoFilename: 'toit.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- triton: { +- name: 'Triton', +- monaco: 'python', +- extensions: ['.py'], +- alias: [], +- logoFilename: 'triton.png', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- typescript: { +- name: 'TypeScript Native', +- monaco: 'typescript', +- extensions: ['.ts', '.d.ts'], +- alias: [], +- logoFilename: 'ts.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- digitSeparator: '_', +- }, +- v: { +- name: 'V', +- monaco: 'v', +- extensions: ['.v', '.vsh'], +- alias: [], +- logoFilename: 'v.svg', +- logoFilenameDark: null, +- formatter: 'vfmt', +- previewFilter: null, +- monacoDisassembly: 'nc', +- }, +- vala: { +- name: 'Vala', +- monaco: 'vala', +- extensions: ['.vala'], +- alias: [], +- logoFilename: 'vala.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- vb: { +- name: 'Visual Basic', +- monaco: 'vb', +- extensions: ['.vb'], +- alias: [], +- logoFilename: 'dotnet.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- vyper: { +- name: 'Vyper', +- monaco: 'python', +- extensions: ['.vy'], +- alias: [], +- logoFilename: 'vyper.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- wasm: { +- name: 'WASM', +- monaco: 'wat', +- extensions: ['.wat'], +- alias: [], +- logoFilename: 'wasm.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- yul: { +- name: 'Yul (Solidity IR)', +- monaco: 'yul', +- extensions: ['.yul'], +- alias: [], +- logoFilename: 'solidity.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- zig: { +- name: 'Zig', +- monaco: 'zig', +- extensions: ['.zig'], +- alias: [], +- logoFilename: 'zig.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- digitSeparator: '_', +- }, +- javascript: { +- name: 'Javascript', +- monaco: 'typescript', +- extensions: ['.mjs'], +- alias: [], +- logoFilename: 'js.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- digitSeparator: '_', +- }, +- gimple: { +- name: 'GIMPLE', +- monaco: 'nc', +- extensions: ['.c'], +- alias: [], +- logoFilename: 'gimple.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: /^\s*#include/, +- monacoDisassembly: null, +- }, +- ylc: { +- name: 'Ygen', +- monaco: 'llvm-ir', +- extensions: ['.yl'], +- alias: [], +- logoFilename: null, // ygen does not yet have a logo ping me if it requires one (@Cr0a3) +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- }, +- sway: { +- name: 'sway', +- monaco: 'sway', +- extensions: ['.sw'], +- alias: [], +- logoFilename: 'sway.svg', +- logoFilenameDark: null, +- formatter: null, +- previewFilter: null, +- monacoDisassembly: null, +- digitSeparator: '_', +- }, + }; + + export const languages = Object.fromEntries( +diff --git a/lib/languages.ts.full-backup b/lib/languages.ts.full-backup +new file mode 100644 +index 000000000..71d69e157 +--- /dev/null ++++ b/lib/languages.ts.full-backup +@@ -0,0 +1,1086 @@ ++// Copyright (c) 2017, Compiler Explorer Authors ++// All rights reserved. ++// ++// Redistribution and use in source and binary forms, with or without ++// modification, are permitted provided that the following conditions are met: ++// ++// * Redistributions of source code must retain the above copyright notice, ++// this list of conditions and the following disclaimer. ++// * Redistributions in binary form must reproduce the above copyright ++// notice, this list of conditions and the following disclaimer in the ++// documentation and/or other materials provided with the distribution. ++// ++// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ++// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++// POSSIBILITY OF SUCH DAMAGE. ++ ++import fs from 'node:fs'; ++import path from 'node:path'; ++ ++import type {Language, LanguageKey} from '../types/languages.interfaces.js'; ++ ++type DefKeys = ++ | 'name' ++ | 'monaco' ++ | 'extensions' ++ | 'alias' ++ | 'previewFilter' ++ | 'formatter' ++ | 'logoFilename' ++ | 'logoFilenameDark' ++ | 'monacoDisassembly' ++ | 'tooltip' ++ | 'digitSeparator'; ++type LanguageDefinition = Pick; ++ ++const definitions: Record = { ++ jakt: { ++ name: 'Jakt', ++ monaco: 'jakt', ++ extensions: ['.jakt'], ++ alias: [], ++ logoFilename: null, ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: 'cppp', ++ }, ++ 'c++': { ++ name: 'C++', ++ monaco: 'cppp', ++ extensions: ['.cpp', '.cxx', '.h', '.hpp', '.hxx', '.c', '.cc', '.ixx'], ++ alias: ['gcc', 'cpp'], ++ logoFilename: 'cpp.svg', ++ logoFilenameDark: null, ++ formatter: 'clangformat', ++ previewFilter: /^\s*#include/, ++ monacoDisassembly: null, ++ digitSeparator: "'", ++ }, ++ ada: { ++ name: 'Ada', ++ monaco: 'ada', ++ extensions: ['.adb', '.ads'], ++ alias: [], ++ logoFilename: 'ada.svg', ++ logoFilenameDark: 'ada-dark.svg', ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ algol68: { ++ name: 'Algol68', ++ monaco: 'algol68', ++ extensions: ['.a68'], ++ alias: [], ++ logoFilename: null, ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ analysis: { ++ name: 'Analysis', ++ monaco: 'asm', ++ extensions: ['.asm'], // maybe add more? Change to a unique one? ++ alias: ['tool', 'tools'], ++ logoFilename: 'analysis.png', // TODO: Find a better alternative ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ tooltip: 'A collection of asm analysis tools', ++ }, ++ 'android-java': { ++ name: 'Android Java', ++ monaco: 'java', ++ extensions: ['.java'], ++ alias: [], ++ logoFilename: 'android.svg', ++ logoFilenameDark: 'android-dark.svg', ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ digitSeparator: '_', ++ }, ++ 'android-kotlin': { ++ name: 'Android Kotlin', ++ monaco: 'kotlin', ++ extensions: ['.kt'], ++ alias: [], ++ logoFilename: 'android.svg', ++ logoFilenameDark: 'android-dark.svg', ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ digitSeparator: '_', ++ }, ++ assembly: { ++ name: 'Assembly', ++ monaco: 'asm', ++ extensions: ['.asm', '.6502', '.s'], ++ alias: ['asm'], ++ logoFilename: 'assembly.png', // TODO: Find a better alternative ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ c: { ++ name: 'C', ++ monaco: 'nc', ++ extensions: ['.c', '.h'], ++ alias: [], ++ logoFilename: 'c.svg', ++ logoFilenameDark: null, ++ formatter: 'clangformat', ++ previewFilter: /^\s*#include/, ++ monacoDisassembly: null, ++ digitSeparator: "'", ++ }, ++ c3: { ++ name: 'C3', ++ monaco: 'c3', ++ extensions: ['.c3'], ++ alias: [], ++ logoFilename: 'c3.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ carbon: { ++ name: 'Carbon', ++ monaco: 'carbon', ++ extensions: ['.carbon'], ++ alias: [], ++ logoFilename: 'carbon.png', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ coccinelle_for_c: { ++ name: 'C with Coccinelle', ++ monaco: 'nc', ++ extensions: ['.c', '.h'], ++ alias: [], ++ logoFilename: 'c.svg', ++ logoFilenameDark: null, ++ formatter: 'clangformat', ++ previewFilter: /^\s*#include/, ++ monacoDisassembly: null, ++ digitSeparator: "'", ++ }, ++ coccinelle_for_cpp: { ++ name: 'C++ with Coccinelle', ++ monaco: 'cppp', ++ extensions: ['.cpp', '.h'], ++ alias: [], ++ logoFilename: 'cpp.svg', ++ logoFilenameDark: null, ++ formatter: 'clangformat', ++ previewFilter: /^\s*#include/, ++ monacoDisassembly: null, ++ digitSeparator: "'", ++ }, ++ circle: { ++ name: 'C++ (Circle)', ++ monaco: 'cppcircle', ++ extensions: ['.cpp', '.cxx', '.h', '.hpp', '.hxx', '.c'], ++ alias: [], ++ previewFilter: /^\s*#include/, ++ logoFilename: 'cpp.svg', // TODO: Find a better alternative ++ logoFilenameDark: null, ++ formatter: null, ++ monacoDisassembly: null, ++ digitSeparator: "'", ++ }, ++ circt: { ++ name: 'CIRCT', ++ monaco: 'mlir', ++ extensions: ['.mlir'], ++ alias: [], ++ logoFilename: 'circt.svg', ++ formatter: null, ++ logoFilenameDark: null, ++ previewFilter: null, ++ monacoDisassembly: 'mlir', ++ }, ++ clean: { ++ name: 'Clean', ++ monaco: 'clean', ++ extensions: ['.icl'], ++ alias: [], ++ logoFilename: 'clean.svg', // TODO: Find a better alternative ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ clojure: { ++ name: 'Clojure', ++ monaco: 'clojure', ++ extensions: ['.clj'], ++ alias: [], ++ logoFilename: 'clojure.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ cmake: { ++ name: 'CMake', ++ monaco: 'cmake', ++ extensions: ['.txt'], ++ alias: [], ++ logoFilename: 'cmake.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ cmakescript: { ++ name: 'CMakeScript', ++ monaco: 'cmake', ++ extensions: ['.cmake'], ++ alias: [], ++ logoFilename: 'cmake.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ cobol: { ++ name: 'COBOL', ++ monaco: 'cobol', ++ extensions: ['.cob', '.cbl', '.cobol'], ++ alias: [], ++ logoFilename: null, // TODO: Find a better alternative ++ formatter: null, ++ logoFilenameDark: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ cpp_for_opencl: { ++ name: 'C++ for OpenCL', ++ monaco: 'cpp-for-opencl', ++ extensions: ['.clcpp', '.cl', '.ocl'], ++ alias: [], ++ logoFilename: 'opencl.svg', // TODO: Find a better alternative ++ logoFilenameDark: 'opencl-dark.svg', ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ digitSeparator: "'", ++ }, ++ mlir: { ++ name: 'MLIR', ++ monaco: 'mlir', ++ extensions: ['.mlir'], ++ alias: [], ++ logoFilename: 'mlir.svg', ++ formatter: null, ++ logoFilenameDark: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ cppx: { ++ name: 'Cppx', ++ monaco: 'cppp', ++ extensions: ['.cpp', '.cxx', '.h', '.hpp', '.hxx', '.c'], ++ alias: [], ++ logoFilename: 'cpp.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: /^\s*#include/, ++ monacoDisassembly: null, ++ digitSeparator: "'", ++ }, ++ cppx_blue: { ++ name: 'Cppx-Blue', ++ monaco: 'cppx-blue', ++ extensions: ['.blue', '.cpp', '.cxx', '.h', '.hpp', '.hxx', '.c'], ++ alias: [], ++ logoFilename: 'cpp.svg', // TODO: Find a better alternative ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ cppx_gold: { ++ name: 'Cppx-Gold', ++ monaco: 'cppx-gold', ++ extensions: ['.usyntax', '.cpp', '.cxx', '.h', '.hpp', '.hxx', '.c'], ++ alias: [], ++ logoFilename: 'cpp.svg', // TODO: Find a better alternative ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ digitSeparator: "'", ++ }, ++ cpp2_cppfront: { ++ name: 'Cpp2-cppfront', ++ monaco: 'cpp2-cppfront', ++ extensions: ['.cpp2'], ++ alias: [], ++ logoFilename: 'cpp.svg', // TODO: Find a better alternative ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: 'cppp', ++ digitSeparator: "'", ++ }, ++ crystal: { ++ name: 'Crystal', ++ monaco: 'crystal', ++ extensions: ['.cr'], ++ alias: [], ++ logoFilename: 'crystal.svg', ++ logoFilenameDark: 'crystal-dark.svg', ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ digitSeparator: '_', ++ }, ++ csharp: { ++ name: 'C#', ++ monaco: 'csharp', ++ extensions: ['.cs'], ++ alias: [], ++ logoFilename: 'dotnet.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ digitSeparator: '_', ++ }, ++ cuda: { ++ name: 'CUDA C++', ++ monaco: 'cuda', ++ extensions: ['.cu', '.cuh'], ++ alias: ['nvcc'], ++ logoFilename: 'cuda.svg', ++ logoFilenameDark: 'cuda-dark.svg', ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ digitSeparator: "'", ++ }, ++ d: { ++ name: 'D', ++ monaco: 'd', ++ extensions: ['.d'], ++ alias: [], ++ logoFilename: 'd.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ dart: { ++ name: 'Dart', ++ monaco: 'dart', ++ extensions: ['.dart'], ++ alias: [], ++ logoFilename: 'dart.svg', ++ logoFilenameDark: null, ++ formatter: 'dartformat', ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ elixir: { ++ name: 'Elixir', ++ monaco: 'elixir', ++ extensions: ['.ex'], ++ alias: [], ++ logoFilename: 'elixir.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ erlang: { ++ name: 'Erlang', ++ monaco: 'erlang', ++ extensions: ['.erl', '.hrl'], ++ alias: [], ++ logoFilename: 'erlang.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ fortran: { ++ name: 'Fortran', ++ monaco: 'fortran', ++ extensions: ['.f90', '.F90', '.f95', '.F95', '.f'], ++ alias: [], ++ logoFilename: 'fortran.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ fsharp: { ++ name: 'F#', ++ monaco: 'fsharp', ++ extensions: ['.fs'], ++ alias: [], ++ logoFilename: 'fsharp.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ glsl: { ++ name: 'GLSL', ++ monaco: 'glsl', ++ extensions: ['.glsl'], ++ alias: [], ++ logoFilename: 'glsl.svg', ++ logoFilenameDark: 'glsl-dark.svg', ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ go: { ++ name: 'Go', ++ monaco: 'go', ++ extensions: ['.go'], ++ alias: [], ++ logoFilename: 'go.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ digitSeparator: '_', ++ }, ++ haskell: { ++ name: 'Haskell', ++ monaco: 'haskell', ++ extensions: ['.hs', '.haskell'], ++ alias: [], ++ logoFilename: 'haskell.png', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ digitSeparator: '_', ++ }, ++ hlsl: { ++ name: 'HLSL', ++ monaco: 'hlsl', ++ extensions: ['.hlsl', '.hlsli'], ++ alias: [], ++ logoFilename: 'hlsl.png', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ helion: { ++ name: 'Helion', ++ monaco: 'python', ++ extensions: ['.py'], ++ alias: [], ++ logoFilename: 'helion.png', ++ logoFilenameDark: 'helion.png', ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ digitSeparator: '_', ++ }, ++ hook: { ++ name: 'Hook', ++ monaco: 'hook', ++ extensions: ['.hk', '.hook'], ++ alias: [], ++ logoFilename: 'hook.png', ++ logoFilenameDark: 'hook-dark.png', ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ hylo: { ++ name: 'Hylo', ++ monaco: 'hylo', ++ extensions: ['.hylo'], ++ alias: [], ++ logoFilename: 'hylo.png', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ il: { ++ name: 'IL', ++ monaco: 'asm', ++ extensions: ['.il'], ++ alias: [], ++ logoFilename: 'dotnet.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ ispc: { ++ name: 'ispc', ++ monaco: 'ispc', ++ extensions: ['.ispc'], ++ alias: [], ++ logoFilename: 'ispc.png', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ java: { ++ name: 'Java', ++ monaco: 'java', ++ extensions: ['.java'], ++ alias: [], ++ logoFilename: 'java.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ digitSeparator: '_', ++ }, ++ julia: { ++ name: 'Julia', ++ monaco: 'julia', ++ extensions: ['.jl'], ++ alias: [], ++ logoFilename: 'julia.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ digitSeparator: '_', ++ }, ++ kotlin: { ++ name: 'Kotlin', ++ monaco: 'kotlin', ++ extensions: ['.kt'], ++ alias: [], ++ logoFilename: 'kotlin.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ digitSeparator: '_', ++ }, ++ llvm: { ++ name: 'LLVM IR', ++ monaco: 'llvm-ir', ++ extensions: ['.ll'], ++ alias: [], ++ logoFilename: 'llvm.png', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ llvm_mir: { ++ name: 'LLVM MIR', ++ monaco: 'llvm-ir', ++ extensions: ['.mir'], ++ alias: [], ++ logoFilename: 'llvm.png', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ modula2: { ++ name: 'Modula-2', ++ monaco: 'modula2', ++ extensions: ['.mod'], ++ alias: [], ++ logoFilename: null, ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ mojo: { ++ name: 'Mojo', ++ monaco: 'mojo', ++ extensions: ['.mojo', '.🔥'], ++ alias: [], ++ logoFilename: 'mojo.svg', ++ logoFilenameDark: null, ++ formatter: 'mblack', ++ previewFilter: null, ++ monacoDisassembly: null, ++ digitSeparator: '_', ++ }, ++ nim: { ++ name: 'Nim', ++ monaco: 'nim', ++ extensions: ['.nim'], ++ alias: [], ++ logoFilename: 'nim.png', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ numba: { ++ name: 'Numba', ++ monaco: 'python', ++ extensions: ['.py'], ++ alias: [], ++ logoFilename: 'numba.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ nix: { ++ name: 'Nix', ++ monaco: 'nix', ++ extensions: ['.nix'], ++ alias: [], ++ logoFilename: 'nix.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ objc: { ++ name: 'Objective-C', ++ monaco: 'objective-c', ++ extensions: ['.m'], ++ alias: [], ++ logoFilename: null, ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ 'objc++': { ++ name: 'Objective-C++', ++ monaco: 'objective-c', ++ extensions: ['.mm'], ++ alias: [], ++ logoFilename: null, ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ digitSeparator: "'", ++ }, ++ ocaml: { ++ name: 'OCaml', ++ monaco: 'ocaml', ++ extensions: ['.ml', '.mli'], ++ alias: [], ++ logoFilename: 'ocaml.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ odin: { ++ name: 'Odin', ++ monaco: 'odin', ++ extensions: ['.odin'], ++ alias: [], ++ logoFilename: 'odin.png', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ openclc: { ++ name: 'OpenCL C', ++ monaco: 'openclc', ++ extensions: ['.cl', '.ocl'], ++ alias: [], ++ logoFilename: 'opencl.svg', ++ logoFilenameDark: 'opencl-dark.svg', ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ pascal: { ++ name: 'Pascal', ++ monaco: 'pascal', ++ extensions: ['.pas', '.dpr', '.inc'], ++ alias: [], ++ logoFilename: 'pascal.svg', // TODO: Find a better alternative ++ logoFilenameDark: 'pascal-dark.svg', ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ pony: { ++ name: 'Pony', ++ monaco: 'pony', ++ extensions: ['.pony'], ++ alias: [], ++ logoFilename: 'pony.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ ptx: { ++ name: 'PTX', ++ monaco: 'ptx', ++ extensions: ['.ptx'], ++ alias: [], ++ logoFilename: 'cuda.svg', ++ logoFilenameDark: 'cuda-dark.svg', ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ python: { ++ name: 'Python', ++ monaco: 'python', ++ extensions: ['.py'], ++ alias: [], ++ logoFilename: 'python.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ digitSeparator: '_', ++ }, ++ racket: { ++ name: 'Racket', ++ monaco: 'scheme', ++ extensions: ['.rkt'], ++ alias: [], ++ logoFilename: 'racket.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: 'scheme', ++ }, ++ raku: { ++ name: 'Raku', ++ monaco: 'perl', ++ extensions: ['.raku', '.rakutest', '.rakumod', '.rakudoc'], ++ alias: ['Perl 6'], ++ logoFilename: 'camelia.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ ruby: { ++ name: 'Ruby', ++ monaco: 'ruby', ++ extensions: ['.rb'], ++ alias: [], ++ logoFilename: 'ruby.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: 'asmruby', ++ digitSeparator: '_', ++ }, ++ rust: { ++ name: 'Rust', ++ monaco: 'rustp', ++ extensions: ['.rs'], ++ alias: [], ++ logoFilename: 'rust.svg', ++ logoFilenameDark: 'rust-dark.svg', ++ formatter: 'rustfmt', ++ previewFilter: null, ++ monacoDisassembly: null, ++ digitSeparator: '_', ++ }, ++ sail: { ++ name: 'Sail', ++ monaco: 'sail', ++ extensions: ['.sail'], ++ alias: [], ++ logoFilename: 'sail.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ snowball: { ++ name: 'Snowball', ++ monaco: 'swift', ++ extensions: ['.sn'], ++ alias: [], ++ logoFilename: 'snowball.svg', ++ logoFilenameDark: 'snowball.svg', ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ scala: { ++ name: 'Scala', ++ monaco: 'scala', ++ extensions: ['.scala'], ++ alias: [], ++ logoFilename: 'scala.png', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ digitSeparator: '_', ++ }, ++ slang: { ++ name: 'Slang', ++ monaco: 'slang', ++ extensions: ['.slang'], ++ alias: [], ++ logoFilename: 'slang.svg', ++ logoFilenameDark: 'slang-dark.svg', ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ solidity: { ++ name: 'Solidity', ++ monaco: 'sol', ++ extensions: ['.sol'], ++ alias: [], ++ logoFilename: 'solidity.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ spice: { ++ name: 'Spice', ++ monaco: 'spice', ++ extensions: ['.spice'], ++ alias: [], ++ logoFilename: 'spice.png', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ spirv: { ++ name: 'SPIR-V', ++ monaco: 'spirv', ++ extensions: ['.spvasm'], ++ alias: [], ++ logoFilename: 'spirv.svg', ++ logoFilenameDark: 'spirv-dark.svg', ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ swift: { ++ name: 'Swift', ++ monaco: 'swift', ++ extensions: ['.swift'], ++ alias: [], ++ logoFilename: 'swift.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ digitSeparator: '_', ++ }, ++ tablegen: { ++ name: 'LLVM TableGen', ++ monaco: 'tablegen', ++ extensions: ['.td'], ++ alias: [], ++ logoFilename: 'llvm.png', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ toit: { ++ name: 'Toit', ++ monaco: 'toit', ++ extensions: ['.toit'], ++ alias: [], ++ logoFilename: 'toit.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ triton: { ++ name: 'Triton', ++ monaco: 'python', ++ extensions: ['.py'], ++ alias: [], ++ logoFilename: 'triton.png', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ typescript: { ++ name: 'TypeScript Native', ++ monaco: 'typescript', ++ extensions: ['.ts', '.d.ts'], ++ alias: [], ++ logoFilename: 'ts.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ digitSeparator: '_', ++ }, ++ v: { ++ name: 'V', ++ monaco: 'v', ++ extensions: ['.v', '.vsh'], ++ alias: [], ++ logoFilename: 'v.svg', ++ logoFilenameDark: null, ++ formatter: 'vfmt', ++ previewFilter: null, ++ monacoDisassembly: 'nc', ++ }, ++ vala: { ++ name: 'Vala', ++ monaco: 'vala', ++ extensions: ['.vala'], ++ alias: [], ++ logoFilename: 'vala.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ vb: { ++ name: 'Visual Basic', ++ monaco: 'vb', ++ extensions: ['.vb'], ++ alias: [], ++ logoFilename: 'dotnet.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ vyper: { ++ name: 'Vyper', ++ monaco: 'python', ++ extensions: ['.vy'], ++ alias: [], ++ logoFilename: 'vyper.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ wasm: { ++ name: 'WASM', ++ monaco: 'wat', ++ extensions: ['.wat'], ++ alias: [], ++ logoFilename: 'wasm.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ yul: { ++ name: 'Yul (Solidity IR)', ++ monaco: 'yul', ++ extensions: ['.yul'], ++ alias: [], ++ logoFilename: 'solidity.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ zig: { ++ name: 'Zig', ++ monaco: 'zig', ++ extensions: ['.zig'], ++ alias: [], ++ logoFilename: 'zig.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ digitSeparator: '_', ++ }, ++ javascript: { ++ name: 'Javascript', ++ monaco: 'typescript', ++ extensions: ['.mjs'], ++ alias: [], ++ logoFilename: 'js.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ digitSeparator: '_', ++ }, ++ gimple: { ++ name: 'GIMPLE', ++ monaco: 'nc', ++ extensions: ['.c'], ++ alias: [], ++ logoFilename: 'gimple.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: /^\s*#include/, ++ monacoDisassembly: null, ++ }, ++ ylc: { ++ name: 'Ygen', ++ monaco: 'llvm-ir', ++ extensions: ['.yl'], ++ alias: [], ++ logoFilename: null, // ygen does not yet have a logo ping me if it requires one (@Cr0a3) ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ }, ++ sway: { ++ name: 'sway', ++ monaco: 'sway', ++ extensions: ['.sw'], ++ alias: [], ++ logoFilename: 'sway.svg', ++ logoFilenameDark: null, ++ formatter: null, ++ previewFilter: null, ++ monacoDisassembly: null, ++ digitSeparator: '_', ++ }, ++}; ++ ++export const languages = Object.fromEntries( ++ Object.entries(definitions).map(([key, lang]) => { ++ let example: string; ++ try { ++ example = fs.readFileSync(path.join('examples', key, 'default' + lang.extensions[0]), 'utf8'); ++ } catch { ++ example = 'Oops, something went wrong and we could not get the default code for this language.'; ++ } ++ ++ const def: Language = { ++ ...lang, ++ id: key as LanguageKey, ++ supportsExecute: false, ++ example, ++ }; ++ return [key, def]; ++ }), ++) as Record; +diff --git a/lib/mapfiles/map-file-delphi.ts b/lib/mapfiles/map-file-delphi.ts +index 51ef094c2..81edc3ba9 100644 +--- a/lib/mapfiles/map-file-delphi.ts ++++ b/lib/mapfiles/map-file-delphi.ts +@@ -29,9 +29,11 @@ export class MapFileReaderDelphi extends MapFileReader { + regexDelphiCodeSegment = /^\s([\da-f]*):([\da-f]*)\s*([\da-f]*)\s*c=code\s*s=.text\s*g=.*m=([\w.]*)\s.*/i; + regexDelphiICodeSegment = /^\s([\da-f]*):([\da-f]*)\s*([\da-f]*)\s*c=icode\s*s=.itext\s*g=.*m=([\w.]*)\s.*/i; + regexDelphiNames = /^\s([\da-f]*):([\da-f]*)\s*([\w$.<>@{}]*)$/i; +- regexDelphiLineNumbersStart = /line numbers for (.*)\(.*\) segment \.text/i; +- regexDelphiLineNumber = /^(\d*)\s([\da-f]*):([\da-f]*)/i; +- regexDelphiLineNumbersStartIText = /line numbers for (.*)\(.*\) segment \.itext/i; ++ regexDelphiLineNumbersStart = /line numbers for (.*)\((.*)\) segment \.text/i; ++ regexDelphiLineNumber = /^\s*(\d+)\s+([\da-f]+):([\da-f]+)/i; ++ regexDelphiLineNumbersStartIText = /line numbers for (.*)\((.*)\) segment \.itext/i; ++ currentLineNumbersFilename: string | null = null; ++ moduleToFilename: Map = new Map(); + + /** + * Tries to match the given line to code segment information +@@ -90,8 +92,69 @@ export class MapFileReaderDelphi extends MapFileReader { + } + } + ++ override run() { ++ console.log(`[MapFileDelphi] Starting map file read: ${this.mapFilename}`); ++ ++ // First pass: read the map file ++ super.run(); ++ ++ console.log(`[MapFileDelphi] Map file read complete. Line numbers found: ${this.lineNumbers.length}`); ++ ++ // Second pass: fix unitName for segments using the module-to-filename mapping ++ this.fixSegmentUnitNames(); ++ } ++ ++ fixSegmentUnitNames() { ++ for (const segment of this.segments) { ++ // Extract module name from current unitName (remove .pas or .dpr extension) ++ const moduleName = segment.unitName?.replace(/\.(pas|dpr)$/i, '') || ''; ++ if (this.moduleToFilename.has(moduleName)) { ++ segment.unitName = this.moduleToFilename.get(moduleName)!; ++ } ++ } ++ for (const segment of this.isegments) { ++ const moduleName = segment.unitName?.replace(/\.(pas|dpr)$/i, '') || ''; ++ if (this.moduleToFilename.has(moduleName)) { ++ segment.unitName = this.moduleToFilename.get(moduleName)!; ++ } ++ } ++ } ++ ++ override getSegmentInfoByStartingAddress(segment: string | undefined, address: number) { ++ // Check regular segments first ++ let result = super.getSegmentInfoByStartingAddress(segment, address); ++ if (result) return result; ++ ++ // Also check isegments (for x86 .itext segments) ++ for (let idx = 0; idx < this.isegments.length; idx++) { ++ const info = this.isegments[idx]; ++ if (!segment && info.addressInt === address) { ++ return info; ++ } ++ if (info.segment === segment && info.addressWithoutOffset === address) { ++ return info; ++ } ++ } ++ ++ return undefined; ++ } ++ + override isStartOfLineNumbers(line: string) { +- const matches = line.match(this.regexDelphiLineNumbersStart); ++ // Check both .text and .itext segments ++ let matches = line.match(this.regexDelphiLineNumbersStart); ++ if (!matches) { ++ matches = line.match(this.regexDelphiLineNumbersStartIText); ++ } ++ ++ if (matches) { ++ // Extract module name and actual filename from the path in parentheses ++ const moduleName = matches[1]; ++ const fullPath = matches[2]; ++ const filename = fullPath.split('\\').pop() || fullPath.split('/').pop() || fullPath; ++ this.currentLineNumbersFilename = filename; ++ this.moduleToFilename.set(moduleName, filename); ++ console.log(`[MapFileDelphi] Found line numbers for module "${moduleName}" -> file: ${filename}`); ++ } + return !!matches; + } + +@@ -105,10 +168,16 @@ export class MapFileReaderDelphi extends MapFileReader { + for (const reference of references) { + const matches = reference.match(this.regexDelphiLineNumber); + if (matches) { +- this.lineNumbers.push({ ++ const lineNumObj = { + ...this.addressToObject(matches[2], matches[3]), + lineNumber: Number.parseInt(matches[1], 10), +- }); ++ filename: this.currentLineNumbersFilename, ++ }; ++ this.lineNumbers.push(lineNumObj); ++ ++ if (this.lineNumbers.length <= 3) { ++ console.log(`[MapFileDelphi] Line ${lineNumObj.lineNumber} at address ${lineNumObj.addressInt.toString(16)} (segment ${lineNumObj.segment}:${matches[3]})`); ++ } + + hasLineNumbers = true; + } +diff --git a/lib/parsers/asm-parser.ts b/lib/parsers/asm-parser.ts +index 5ab3c2f40..7f614844a 100644 +--- a/lib/parsers/asm-parser.ts ++++ b/lib/parsers/asm-parser.ts +@@ -625,6 +625,13 @@ export class AsmParser extends AsmRegex implements IAsmParser { + + if (filters.preProcessBinaryAsmLines) asmLines = filters.preProcessBinaryAsmLines(asmLines); + ++ // Parse .file directives to build file number -> filename mapping ++ const files = this.parseFiles(asmLines); ++ const sourceContext: SourceHandlerContext = { ++ files: files, ++ dontMaskFilenames: dontMaskFilenames || false, ++ }; ++ + for (const line of asmLines) { + const labelsInLine: AsmResultLabel[] = []; + +@@ -653,6 +660,16 @@ export class AsmParser extends AsmRegex implements IAsmParser { + continue; + } + ++ // Handle .file and .loc directives (DWARF debug info) ++ const sourceResult = this.sourceLineHandler.processSourceLine(line, sourceContext); ++ if (sourceResult.source !== undefined) { ++ source = sourceResult.source; ++ if (source && asm.length < 3) { ++ console.log(`[AsmParser] Parsed directive: file="${source.file}" line=${source.line} mainsource=${source.mainsource}`); ++ } ++ continue; // Don't display the directive itself ++ } ++ + match = line.match(this.labelRe); + if (match) { + func = match[2]; +diff --git a/lib/parsers/source-line-handler.ts b/lib/parsers/source-line-handler.ts +index bb82b6e9a..15e8799f8 100644 +--- a/lib/parsers/source-line-handler.ts ++++ b/lib/parsers/source-line-handler.ts +@@ -56,7 +56,9 @@ export class SourceLineHandler { + } + + private createSource(file: string, line: number, context: SourceHandlerContext, column?: number): AsmResultSource { +- const isMainSource = this.stdInLooking.test(file); ++ // Check if this is main source: either matches stdInLooking pattern, or is a simple filename without path separators ++ const isSimpleFilename = !file.includes('/') && !file.includes('\\'); ++ const isMainSource = this.stdInLooking.test(file) || isSimpleFilename; + const source: AsmResultSource = context.dontMaskFilenames + ? { + file, +diff --git a/lib/pe32-support.ts b/lib/pe32-support.ts +index ecaf2e23b..11b657dbe 100644 +--- a/lib/pe32-support.ts ++++ b/lib/pe32-support.ts +@@ -24,6 +24,15 @@ + + import {MapFileReader, Segment} from './mapfiles/map-file.js'; + ++export enum PELabelReconstructorOptions { ++ /** Reconstruct segment information from the map file */ ++ NeedsReconstruction, ++ /** Don't label addresses that aren't in the map file */ ++ DontLabelUnmappedAddresses, ++ /** Delete all assembly before the first user code segment */ ++ DeleteBeforeFirstSegment, ++} ++ + export class PELabelReconstructor { + public readonly asmLines: string[]; + private readonly addressesToLabel: string[]; +@@ -35,15 +44,18 @@ export class PELabelReconstructor { + private readonly callRegex: RegExp; + private readonly int3Regex: RegExp; + ++ private readonly deleteBeforeFirstSegment: boolean; ++ private readonly additionalExcludedUnits: string[]; ++ + constructor( + asmLines: string[], +- dontLabelUnmappedAddresses: boolean, + mapFileReader: MapFileReader, +- needsReconstruction = true, ++ options: Set = new Set(), ++ additionalExcludedUnits: string[] = [], + ) { + this.asmLines = asmLines; + this.addressesToLabel = []; +- this.dontLabelUnmappedAddresses = dontLabelUnmappedAddresses; ++ this.dontLabelUnmappedAddresses = options.has(PELabelReconstructorOptions.DontLabelUnmappedAddresses); + + this.addressRegex = /^\s*([\da-f]*):/i; + this.jumpRegex = /(\sj[a-z]*)(\s*)0x([\da-f]*)/i; +@@ -51,7 +63,9 @@ export class PELabelReconstructor { + this.int3Regex = /\tcc\s*\tint3\s*$/i; + + this.mapFileReader = mapFileReader; +- this.needsReconstruction = needsReconstruction; ++ this.needsReconstruction = options.has(PELabelReconstructorOptions.NeedsReconstruction); ++ this.deleteBeforeFirstSegment = options.has(PELabelReconstructorOptions.DeleteBeforeFirstSegment); ++ this.additionalExcludedUnits = additionalExcludedUnits; + } + + /** +@@ -62,6 +76,9 @@ export class PELabelReconstructor { + this.mapFileReader.run(); + + //this.deleteEverythingBut(unitName); ++ if (this.deleteBeforeFirstSegment) { ++ this.deleteBeforeUserCode(); ++ } + this.deleteSystemUnits(); + this.shortenInt3s(); + +@@ -138,7 +155,7 @@ export class PELabelReconstructor { + } + + deleteSystemUnits() { +- const systemUnits = new Set(['SysInit.pas', 'System.pas', 'SysUtils.pas', 'Classes.pas']); ++ const systemUnits = new Set(['SysInit.pas', 'System.pas', 'SysUtils.pas', 'Classes.pas', ...this.additionalExcludedUnits]); + + let idx; + let info; +@@ -157,6 +174,35 @@ export class PELabelReconstructor { + } + } + ++ deleteBeforeUserCode() { ++ // Find the first user code segment (not system units) ++ const systemUnits = new Set(['SysInit.pas', 'System.pas', 'SysUtils.pas', 'Classes.pas']); ++ let firstUserAddress: number | undefined; ++ ++ // Check both regular segments and isegments, take the minimum address ++ for (const info of this.mapFileReader.segments) { ++ if (info.unitName && !systemUnits.has(info.unitName)) { ++ if (firstUserAddress === undefined || info.addressInt < firstUserAddress) { ++ firstUserAddress = info.addressInt; ++ } ++ } ++ } ++ ++ for (const info of this.mapFileReader.isegments) { ++ if (info.unitName && !systemUnits.has(info.unitName)) { ++ if (firstUserAddress === undefined || info.addressInt < firstUserAddress) { ++ firstUserAddress = info.addressInt; ++ } ++ } ++ } ++ ++ // Delete everything before the first user code ++ if (firstUserAddress !== undefined) { ++ console.log(`[PELabel] Deleting from 0 to 0x${firstUserAddress.toString(16)}`); ++ this.deleteLinesBetweenAddresses(0, firstUserAddress); ++ } ++ } ++ + deleteLinesBetweenAddresses(beginAddress: number, endAddress?: number) { + let startIdx = -1; + let linesRemoved = false; +@@ -276,8 +322,15 @@ export class PELabelReconstructor { + } + + const lineInfo = this.mapFileReader.getLineInfoByAddress(undefined, address); ++ ++ if (lineIdx < 3) { ++ console.log(`[PELabel] Address ${address.toString(16)}: lineInfo=${lineInfo ? `${lineInfo.lineNumber} (${(lineInfo as any).filename || 'no filename'})` : 'null'}, segment=${currentSegment ? currentSegment.unitName : 'null'}`); ++ } ++ + if (lineInfo && currentSegment && currentSegment.unitName) { +- this.asmLines.splice(lineIdx, 0, '/app/' + currentSegment.unitName + ':' + lineInfo.lineNumber); ++ // Use filename from lineInfo if available (for Delphi), otherwise fall back to segment unitName ++ const sourceFile = (lineInfo as any).filename || currentSegment.unitName; ++ this.asmLines.splice(lineIdx, 0, '/app/' + sourceFile + ':' + lineInfo.lineNumber); + lineIdx++; + } else if (segmentChanged && currentSegment) { + this.asmLines.splice(lineIdx, 0, '/app/' + currentSegment.unitName + ':0'); diff --git a/etc/config/pascal-win.local.properties b/etc/config/pascal-win.local.properties deleted file mode 100644 index 17cd7a614de..00000000000 --- a/etc/config/pascal-win.local.properties +++ /dev/null @@ -1,76 +0,0 @@ -compilers=&delphi:&delphi64 -maxLinesOfAsm=1000 -rpathFlag=-O - -################################# -# Delphi - Installed versions: 10.4.2, 11, 12.3, 13.1 -group.delphi.compilers=delphi27:delphi28:delphi29:delphi31 -group.delphi.compilerType=pascal-win -group.delphi.demangler= -group.delphi.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe -#D:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin\objdump.exe -group.delphi.versionFlags=| grep "Version" - -group.delphi64.compilers=delphi27_64:delphi28_64:delphi29_64:delphi31_64 -group.delphi64.compilerType=pascal-win -group.delphi64.demangler= -group.delphi64.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe -group.delphi64.versionFlags=| grep "Version" - -# Older Delphi versions - not installed on this system -#compiler.delphi21.exe =C:\Program Files (x86)\Embarcadero\Studio\15.0\Bin\DCC32.EXE -#compiler.delphi21.name =x86 Delphi XE7 -# -#compiler.delphi22.exe =C:\Program Files (x86)\Embarcadero\Studio\16.0\Bin\DCC32.EXE -#compiler.delphi22.name =x86 Delphi XE8 -# -#compiler.delphi23.exe =C:\Program Files (x86)\Embarcadero\Studio\17.0\bin\DCC32.exe -#compiler.delphi23.name =x86 Delphi 10 Seattle -# -#compiler.delphi23_64.exe =C:\Program Files (x86)\Embarcadero\Studio\17.0\bin\DCC64.exe -#compiler.delphi23_64.name=x64 Delphi 10 Seattle -# -#compiler.delphi24.exe =c:\Program Files (x86)\Embarcadero\Studio\18.0\Bin\DCC32.EXE -#compiler.delphi24.name =x86 Delphi 10.1 Berlin -# -#compiler.delphi24_64.exe =c:\Program Files (x86)\Embarcadero\Studio\18.0\Bin\DCC64.EXE -#compiler.delphi24_64.name=x64 Delphi 10.1 Berlin -# -#compiler.delphi25.exe =C:\Program Files (x86)\Embarcadero\Studio\19.0\Bin\DCC32.EXE -#compiler.delphi25.name =x86 Delphi 10.2 Tokyo -# -#compiler.delphi25_64.exe =C:\Program Files (x86)\Embarcadero\Studio\19.0\Bin\DCC64.EXE -#compiler.delphi25_64.name=x64 Delphi 10.2 Tokyo -# -#compiler.delphi26.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC32.EXE -#compiler.delphi26.name =x86 Delphi 10.3 Rio -# -#compiler.delphi26_64.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC64.EXE -#compiler.delphi26_64.name=x64 Delphi 10.3 Rio - -compiler.delphi27.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC32.EXE -compiler.delphi27.name =x86 Delphi 10.4.2 Sydney - -compiler.delphi27_64.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC64.EXE -compiler.delphi27_64.name=x64 Delphi 10.4.2 Sydney - -# Delphi 11 Alexandria (Studio 22.0) -compiler.delphi28.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\Bin\DCC32.EXE -compiler.delphi28.name =x86 Delphi 11 Alexandria - -compiler.delphi28_64.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\Bin\DCC64.EXE -compiler.delphi28_64.name=x64 Delphi 11 Alexandria - -# Delphi 12.3 Athens (Studio 23.0) -compiler.delphi29.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\Bin\DCC32.EXE -compiler.delphi29.name =x86 Delphi 12.3 Athens - -compiler.delphi29_64.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\Bin\DCC64.EXE -compiler.delphi29_64.name=x64 Delphi 12.3 Athens - -# Delphi 13.1 (Studio 37.0) -compiler.delphi31.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\Bin\DCC32.EXE -compiler.delphi31.name =x86 Delphi 13.1 - -compiler.delphi31_64.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\Bin\DCC64.EXE -compiler.delphi31_64.name=x64 Delphi 13.1 \ No newline at end of file diff --git a/etc/config/pascal.local.properties b/etc/config/pascal.local.properties index 251ee75482c..b6a2a0521cf 100644 --- a/etc/config/pascal.local.properties +++ b/etc/config/pascal.local.properties @@ -1,118 +1,156 @@ -# FPC compilers for Windows -# Delphi compilers are configured in pascal-win.local.properties -compilers=&fpc -maxLinesOfAsm=1000 -rpathFlag=-O -defaultCompiler=fpc331 -delayCleanupTemp=true - -# FPC (Free Pascal Compiler) group -group.fpc.compilers=fpc300:fpc320:fpc322:fpc331 -group.fpc.compilerType=pascal -group.fpc.isSemVer=true -group.fpc.baseName=FPC -group.fpc.versionFlag=-iV -group.fpc.supportsBinary=true -group.fpc.supportsExecute=true -group.fpc.objdumper=C:\\Program Files (x86)\\Embarcadero\\Dev-Cpp\\TDM-GCC-64\\bin\\objdump.exe - -# FPC 3.0.0 -compiler.fpc300.exe=D:\\fpc\\3.0.0\\fpc\\bin\\x86_64-win64\\fpc.exe -compiler.fpc300.semver=3.0.0 -compiler.fpc300.name=FPC 3.0.0 - -# FPC 3.2.0 -compiler.fpc320.exe=D:\\fpc\\3.2.0\\fpc\\bin\\x86_64-win64\\fpc.exe -compiler.fpc320.semver=3.2.0 -compiler.fpc320.name=FPC 3.2.0 - -# FPC 3.2.2 -compiler.fpc322.exe=D:\\fpc\\3.2.2\\fpc\\bin\\x86_64-win64\\fpc.exe -compiler.fpc322.semver=3.2.2 -compiler.fpc322.name=FPC 3.2.2 - -# FPC 3.3.1 -compiler.fpc331.exe=D:\\fpc\\3.3.1\\fpc\\bin\\x86_64-win64\\fpc.exe -compiler.fpc331.semver=3.3.1 -compiler.fpc331.name=FPC 3.3.1 - - - - -################################# -# Delphi - Configured in pascal-win.local.properties -#group.delphi.compilers=delphi27:delphi28:delphi29:delphi31 -#group.delphi.compilerType=pascal-win -#group.delphi.demangler= -#group.delphi.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe -#group.delphi.versionFlags=| grep "Version" -# -#group.delphi64.compilers=delphi27_64:delphi28_64:delphi29_64:delphi31_64 -#group.delphi64.compilerType=pascal-win -#group.delphi64.demangler= -#group.delphi64.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe -#group.delphi64.versionFlags=| grep "Version" - -#compiler.delphi21.exe =C:\Program Files (x86)\Embarcadero\Studio\15.0\Bin\DCC32.EXE -#compiler.delphi21.name =x86 Delphi XE7 - -#compiler.delphi22.exe =C:\Program Files (x86)\Embarcadero\Studio\16.0\Bin\DCC32.EXE -#compiler.delphi22.name =x86 Delphi XE8 - -#compiler.delphi23.exe =C:\Program Files (x86)\Embarcadero\Studio\17.0\bin\DCC32.exe -#compiler.delphi23.name =x86 Delphi 10 Seattle - -#compiler.delphi23_64.exe =C:\Program Files (x86)\Embarcadero\Studio\17.0\bin\DCC64.exe -#compiler.delphi23_64.name=x64 Delphi 10 Seattle - -#compiler.delphi24.exe =c:\Program Files (x86)\Embarcadero\Studio\18.0\Bin\DCC32.EXE -#ompiler.delphi24.name =x86 Delphi 10.1 Berlin - -#compiler.delphi24_64.exe =c:\Program Files (x86)\Embarcadero\Studio\18.0\Bin\DCC64.EXE -#compiler.delphi24_64.name=x64 Delphi 10.1 Berlin - -# Delphi 10.4.2 Sydney (Studio 20.0) -#compiler.delphi27.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC32.EXE -#compiler.delphi27.name =x86 Delphi 10.4.2 Sydney -# -#compiler.delphi27_64.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC64.EXE -#compiler.delphi27_64.name=x64 Delphi 10.4.2 Sydney - -# Delphi 11 Alexandria (Studio 22.0) -#compiler.delphi28.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\Bin\DCC32.EXE -#compiler.delphi28.name =x86 Delphi 11 Alexandria -# -#compiler.delphi28_64.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\Bin\DCC64.EXE -#compiler.delphi28_64.name=x64 Delphi 11 Alexandria - -# Delphi 12.3 Athens (Studio 23.0) -#compiler.delphi29.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\Bin\DCC32.EXE -#compiler.delphi29.name =x86 Delphi 12.3 Athens -# -#compiler.delphi29_64.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\Bin\DCC64.EXE -#compiler.delphi29_64.name=x64 Delphi 12.3 Athens - -# Delphi 13.1 (Studio 37.0) -#compiler.delphi31.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\Bin\DCC32.EXE -#compiler.delphi31.name =x86 Delphi 13.1 -# -#compiler.delphi31_64.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\Bin\DCC64.EXE -#compiler.delphi31_64.name=x64 Delphi 13.1 - - - - - - -################################# -################################# -# Installed libs (See c++.amazon.properties for a scheme of libs group) -libs= - -################################# -################################# -# Installed tools - -#tools=llvm-mcatrunk:pahole - - +# Delphi and FPC compilers for Windows +compilers=&delphi:&delphi64:&fpc +maxLinesOfAsm=1000 +rpathFlag=-O +defaultCompiler=delphi31_64 +delayCleanupTemp=true + +# Delphi 32-bit group +group.delphi.compilers=delphi27:delphi28:delphi29:delphi31 +group.delphi.compilerType=pascal-win +group.delphi.demangler= +group.delphi.objdumper=C:\\Program Files (x86)\\Embarcadero\\Dev-Cpp\\TDM-GCC-64\\bin\\objdump.exe +group.delphi.versionFlags=| grep "Version" + +# Delphi 64-bit group +group.delphi64.compilers=delphi27_64:delphi28_64:delphi29_64:delphi31_64 +group.delphi64.compilerType=pascal-win +group.delphi64.demangler= +group.delphi64.objdumper=C:\\Program Files (x86)\\Embarcadero\\Dev-Cpp\\TDM-GCC-64\\bin\\objdump.exe +group.delphi64.versionFlags=| grep "Version" + +# Individual compiler definitions +compiler.delphi27.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\20.0\\Bin\\DCC32.EXE +compiler.delphi27.name=x86 Delphi 10.4.2 Sydney + +compiler.delphi27_64.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\20.0\\Bin\\DCC64.EXE +compiler.delphi27_64.name=x64 Delphi 10.4.2 Sydney + +compiler.delphi28.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\22.0\\Bin\\DCC32.EXE +compiler.delphi28.name=x86 Delphi 11.3 Alexandria + +compiler.delphi28_64.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\22.0\\Bin\\DCC64.EXE +compiler.delphi28_64.name=x64 Delphi 11.3 Alexandria + +compiler.delphi29.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\23.0\\Bin\\DCC32.EXE +compiler.delphi29.name=x86 Delphi 12.3 Athens + +compiler.delphi29_64.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\23.0\\Bin\\DCC64.EXE +compiler.delphi29_64.name=x64 Delphi 12.3 Athens + +compiler.delphi31.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\37.0\\Bin\\DCC32.EXE +compiler.delphi31.name=x86 Delphi 13.1 Florence + +compiler.delphi31_64.exe=C:\\Program Files (x86)\\Embarcadero\\Studio\\37.0\\Bin\\DCC64.EXE +compiler.delphi31_64.name=x64 Delphi 13.1 Florence + +# FPC (Free Pascal Compiler) group +group.fpc.compilers=fpc300:fpc320:fpc322:fpc331 +group.fpc.compilerType=pascal +group.fpc.isSemVer=true +group.fpc.baseName=FPC +group.fpc.versionFlag=-iV +group.fpc.supportsBinary=true +group.fpc.supportsExecute=true +group.fpc.objdumper=C:\\Program Files (x86)\\Embarcadero\\Dev-Cpp\\TDM-GCC-64\\bin\\objdump.exe + +# FPC 3.0.0 +compiler.fpc300.exe=D:\\fpc\\3.0.0\\fpc\\bin\\x86_64-win64\\fpc.exe +compiler.fpc300.semver=3.0.0 +compiler.fpc300.name=FPC 3.0.0 + +# FPC 3.2.0 +compiler.fpc320.exe=D:\\fpc\\3.2.0\\fpc\\bin\\x86_64-win64\\fpc.exe +compiler.fpc320.semver=3.2.0 +compiler.fpc320.name=FPC 3.2.0 + +# FPC 3.2.2 +compiler.fpc322.exe=D:\\fpc\\3.2.2\\fpc\\bin\\x86_64-win64\\fpc.exe +compiler.fpc322.semver=3.2.2 +compiler.fpc322.name=FPC 3.2.2 + +# FPC 3.3.1 +compiler.fpc331.exe=D:\\fpc\\3.3.1\\fpc\\bin\\x86_64-win64\\fpc.exe +compiler.fpc331.semver=3.3.1 +compiler.fpc331.name=FPC 3.3.1 + + + + +################################# +# Delphi - Configured in pascal-win.local.properties +#group.delphi.compilers=delphi27:delphi28:delphi29:delphi31 +#group.delphi.compilerType=pascal-win +#group.delphi.demangler= +#group.delphi.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe +#group.delphi.versionFlags=| grep "Version" +# +#group.delphi64.compilers=delphi27_64:delphi28_64:delphi29_64:delphi31_64 +#group.delphi64.compilerType=pascal-win +#group.delphi64.demangler= +#group.delphi64.objdumper=C:\Program Files (x86)\Embarcadero\Dev-Cpp\TDM-GCC-64\bin\objdump.exe +#group.delphi64.versionFlags=| grep "Version" + +#compiler.delphi21.exe =C:\Program Files (x86)\Embarcadero\Studio\15.0\Bin\DCC32.EXE +#compiler.delphi21.name =x86 Delphi XE7 + +#compiler.delphi22.exe =C:\Program Files (x86)\Embarcadero\Studio\16.0\Bin\DCC32.EXE +#compiler.delphi22.name =x86 Delphi XE8 + +#compiler.delphi23.exe =C:\Program Files (x86)\Embarcadero\Studio\17.0\bin\DCC32.exe +#compiler.delphi23.name =x86 Delphi 10 Seattle + +#compiler.delphi23_64.exe =C:\Program Files (x86)\Embarcadero\Studio\17.0\bin\DCC64.exe +#compiler.delphi23_64.name=x64 Delphi 10 Seattle + +#compiler.delphi24.exe =c:\Program Files (x86)\Embarcadero\Studio\18.0\Bin\DCC32.EXE +#ompiler.delphi24.name =x86 Delphi 10.1 Berlin + +#compiler.delphi24_64.exe =c:\Program Files (x86)\Embarcadero\Studio\18.0\Bin\DCC64.EXE +#compiler.delphi24_64.name=x64 Delphi 10.1 Berlin + +# Delphi 10.4.2 Sydney (Studio 20.0) +#compiler.delphi27.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC32.EXE +#compiler.delphi27.name =x86 Delphi 10.4.2 Sydney +# +#compiler.delphi27_64.exe =C:\Program Files (x86)\Embarcadero\Studio\20.0\Bin\DCC64.EXE +#compiler.delphi27_64.name=x64 Delphi 10.4.2 Sydney + +# Delphi 11 Alexandria (Studio 22.0) +#compiler.delphi28.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\Bin\DCC32.EXE +#compiler.delphi28.name =x86 Delphi 11 Alexandria +# +#compiler.delphi28_64.exe =C:\Program Files (x86)\Embarcadero\Studio\22.0\Bin\DCC64.EXE +#compiler.delphi28_64.name=x64 Delphi 11 Alexandria + +# Delphi 12.3 Athens (Studio 23.0) +#compiler.delphi29.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\Bin\DCC32.EXE +#compiler.delphi29.name =x86 Delphi 12.3 Athens +# +#compiler.delphi29_64.exe =C:\Program Files (x86)\Embarcadero\Studio\23.0\Bin\DCC64.EXE +#compiler.delphi29_64.name=x64 Delphi 12.3 Athens + +# Delphi 13.1 (Studio 37.0) +#compiler.delphi31.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\Bin\DCC32.EXE +#compiler.delphi31.name =x86 Delphi 13.1 +# +#compiler.delphi31_64.exe =C:\Program Files (x86)\Embarcadero\Studio\37.0\Bin\DCC64.EXE +#compiler.delphi31_64.name=x64 Delphi 13.1 + + + + + + +################################# +################################# +# Installed libs (See c++.amazon.properties for a scheme of libs group) +libs= + +################################# +################################# +# Installed tools + +#tools=llvm-mcatrunk:pahole + + diff --git a/lib/compilers/pascal-win.ts b/lib/compilers/pascal-win.ts index 4994c2a2051..314e9988755 100644 --- a/lib/compilers/pascal-win.ts +++ b/lib/compilers/pascal-win.ts @@ -231,7 +231,6 @@ export class PascalWinCompiler extends BaseCompiler { let fileCounter = 1; const result: string[] = []; let topLevelFileAdded = false; - let firstFilename: string | null = null; for (const line of reconstructor.asmLines) { const sourceMatch = line.match(/^\/app\/(.+):(\d+)$/); @@ -245,13 +244,8 @@ export class PascalWinCompiler extends BaseCompiler { continue; } - // Track the first file we encounter - if (firstFilename === null) { - firstFilename = filename; - } - - // Only use markers from the first file (skip wrapper prog.dpr if unit exists) - if (filename !== firstFilename) { + // If using a wrapper program, skip prog.dpr markers (only show user's unit code) + if (this.isWrapperProgram && filename === 'prog.dpr') { continue; } From e261d9c08a0e036293e18e551462248a5d18daff Mon Sep 17 00:00:00 2001 From: Paul McGee Date: Fri, 28 Nov 2025 02:55:09 +0800 Subject: [PATCH 23/27] Simplify comment stripping to single line-preserving approach MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove redundant stripCommentsForDetection() function - Use single stripComments() function for all purposes - Consistently preserves line numbers for accurate source mapping - Simplifies code: one function instead of two with unclear distinction 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- lib/compilers/pascal-utils.ts | 152 ++++++++++++++++------------------ 1 file changed, 72 insertions(+), 80 deletions(-) diff --git a/lib/compilers/pascal-utils.ts b/lib/compilers/pascal-utils.ts index db18f7e8487..7ddf7cd272b 100644 --- a/lib/compilers/pascal-utils.ts +++ b/lib/compilers/pascal-utils.ts @@ -1,80 +1,72 @@ -// Copyright (c) 2021, Compiler Explorer Authors -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. - -function stripCommentsForDetection(source: string): string { - // For detection only - remove comments entirely - let result = source.replace(/\/\/.*$/gm, ''); - result = result.replace(/\{[^}]*\}/g, ''); - result = result.replace(/\(\*[\s\S]*?\*\)/g, ''); - return result; -} - -export function stripComments(source: string): string { - // Blank out comment content but preserve line numbers - // For // comments: keep the // but blank the rest of the line - let result = source.replace(/\/\/.*$/gm, '//'); - // For { } comments: keep delimiters, blank content - result = result.replace(/\{[^}]*\}/g, match => '{}'); - // For (* *) comments: keep delimiters, preserve newlines in content - result = result.replace(/\(\*[\s\S]*?\*\)/g, match => { - const lines = match.split('\n'); - if (lines.length === 1) { - return '(**)'; - } else { - // Multi-line: preserve newlines - return '(*' + '\n'.repeat(lines.length - 1) + '*)'; - } - }); - return result; -} - -export function isProgram(source: string) { - const re = /\s?program\s+([\w.-]*);/i; - return !!re.test(stripCommentsForDetection(source)); -} - -export function isUnit(source: string) { - const re = /\s?unit\s+([\w.-]*);/i; - return !!re.test(stripCommentsForDetection(source)); -} - -export function getUnitname(source: string) { - const re = /\s?unit\s+([\w.-]*);/i; - const match = source.match(re); - if (match) { - return match[1]; - } - - return 'example'; -} - -export function getProgName(source: string) { - const re = /\s?program\s+([\w.-]*);/i; - const match = source.match(re); - if (match) { - return match[1]; - } - - return 'prog'; -} +// Copyright (c) 2021, Compiler Explorer Authors +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +export function stripComments(source: string): string { + // Blank out comment content but preserve line numbers + // For // comments: keep the // but blank the rest of the line + let result = source.replace(/\/\/.*$/gm, '//'); + // For { } comments: keep delimiters, blank content + result = result.replace(/\{[^}]*\}/g, match => '{}'); + // For (* *) comments: keep delimiters, preserve newlines in content + result = result.replace(/\(\*[\s\S]*?\*\)/g, match => { + const lines = match.split('\n'); + if (lines.length === 1) { + return '(**)'; + } else { + // Multi-line: preserve newlines + return '(*' + '\n'.repeat(lines.length - 1) + '*)'; + } + }); + return result; +} + +export function isProgram(source: string) { + const re = /\s?program\s+([\w.-]*);/i; + return !!re.test(stripComments(source)); +} + +export function isUnit(source: string) { + const re = /\s?unit\s+([\w.-]*);/i; + return !!re.test(stripComments(source)); +} + +export function getUnitname(source: string) { + const re = /\s?unit\s+([\w.-]*);/i; + const match = source.match(re); + if (match) { + return match[1]; + } + + return 'example'; +} + +export function getProgName(source: string) { + const re = /\s?program\s+([\w.-]*);/i; + const match = source.match(re); + if (match) { + return match[1]; + } + + return 'prog'; +} From f51f55cd5e9e17ccb9044eec261fc4f471320880 Mon Sep 17 00:00:00 2001 From: Paul McGee Date: Fri, 28 Nov 2025 03:31:28 +0800 Subject: [PATCH 24/27] Simplify segment iteration in deleteBeforeUserCode() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace duplicate loops with single combined array - Use filter() and Math.min() for cleaner logic - Reduce from 21 lines to 8 lines with same functionality - No more manual iteration - let built-in functions handle it 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- lib/pe32-support.ts | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/lib/pe32-support.ts b/lib/pe32-support.ts index 89c3fe244fc..5a288ab7756 100644 --- a/lib/pe32-support.ts +++ b/lib/pe32-support.ts @@ -177,24 +177,15 @@ export class PELabelReconstructor { deleteBeforeUserCode() { // Find the first user code segment (not system units) const systemUnits = new Set(['SysInit.pas', 'System.pas', 'SysUtils.pas', 'Classes.pas']); - let firstUserAddress: number | undefined; - // Check both regular segments and isegments, take the minimum address - for (const info of this.mapFileReader.segments) { - if (info.unitName && !systemUnits.has(info.unitName)) { - if (firstUserAddress === undefined || info.addressInt < firstUserAddress) { - firstUserAddress = info.addressInt; - } - } - } + // Combine both segment arrays and filter out system units + const allSegments = [...this.mapFileReader.segments, ...this.mapFileReader.isegments]; + const userSegments = allSegments.filter(info => info.unitName && !systemUnits.has(info.unitName)); - for (const info of this.mapFileReader.isegments) { - if (info.unitName && !systemUnits.has(info.unitName)) { - if (firstUserAddress === undefined || info.addressInt < firstUserAddress) { - firstUserAddress = info.addressInt; - } - } - } + // Find the minimum address + const firstUserAddress = userSegments.length > 0 + ? Math.min(...userSegments.map(info => info.addressInt)) + : undefined; // Delete everything before the first user code if (firstUserAddress !== undefined) { From ea516dd74bdc064240b025d1e459b22fbdc498f4 Mon Sep 17 00:00:00 2001 From: Paul McGee Date: Fri, 28 Nov 2025 20:23:10 +0800 Subject: [PATCH 25/27] Refactor truncateUnmappedSections and add map file error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify truncateUnmappedSections: - Replace complex array mutation with single-pass filter - Remove fragile index adjustment logic - Use running counter to decide which lines to keep - Reduce from 45 lines to 30 lines Add graceful error handling for missing map files: - Wrap mapFileReader.run() in try-catch - If map file is missing or unreadable, continue with empty map data - Assembly will be shown without source highlighting instead of crashing - MapFileReader with empty arrays is safe - all code checks for undefined results 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- lib/compilers/pascal-win.ts | 66 +++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 36 deletions(-) diff --git a/lib/compilers/pascal-win.ts b/lib/compilers/pascal-win.ts index 314e9988755..17c4aef13bc 100644 --- a/lib/compilers/pascal-win.ts +++ b/lib/compilers/pascal-win.ts @@ -216,6 +216,14 @@ export class PascalWinCompiler extends BaseCompiler { filters.dontMaskFilenames = true; filters.preProcessBinaryAsmLines = (asmLines: string[]) => { const mapFileReader = new MapFileReaderDelphi(unwrap(this.mapFilename)); + + // Try to read map file - if it fails, continue with empty map data (no source highlighting) + try { + mapFileReader.run(); + } catch (error) { + // Map file missing or unreadable - assembly will be shown without source mapping + } + // If this is a wrapper program (unit case), exclude prog.dpr segments const excludedUnits = this.isWrapperProgram ? ['prog.dpr'] : []; const reconstructor = new PELabelReconstructor( @@ -281,44 +289,30 @@ export class PascalWinCompiler extends BaseCompiler { * This removes large finalization/initialization blocks that have no debug info */ truncateUnmappedSections(asmLines: string[]): string[] { - const maxUnmappedLines = 5; - const sourceMarkerRegex = /^\s*\.loc\s+/; - const addressRegex = /^\s*[\da-f]+:/i; - - let lineIdx = 0; - let unmappedCount = 0; - let unmappedStartIdx = -1; - - while (lineIdx < asmLines.length) { - const line = asmLines[lineIdx]; - - if (sourceMarkerRegex.test(line)) { - // Found a source marker - reset counter - if (unmappedCount > maxUnmappedLines && unmappedStartIdx !== -1) { - // Delete excess unmapped lines - const deleteCount = unmappedCount - maxUnmappedLines; - asmLines.splice(unmappedStartIdx + maxUnmappedLines, deleteCount); - lineIdx -= deleteCount; - } - unmappedCount = 0; - unmappedStartIdx = -1; - } else if (addressRegex.test(line)) { - // This is an assembly line with an address - if (unmappedStartIdx === -1) { - unmappedStartIdx = lineIdx; + const sourceMarkerRegex = /^\s*\.loc\s+/; + const addressRegex = /^\s*[\da-f]+:/i; + const result: string[] = []; + const maxUnmappedLines = 5; + let currentUnmappedCount = 0; + + for (const line of asmLines) { + if (sourceMarkerRegex.test(line)) // Reset counter when we hit a source marker + { + currentUnmappedCount = 0; + result.push(line); + } + else if (addressRegex.test(line)) // Address line - only keep if under limit + { + if (currentUnmappedCount < maxUnmappedLines) { + result.push(line); + currentUnmappedCount++; } - unmappedCount++; } - - lineIdx++; - } - - // Handle trailing unmapped section - if (unmappedCount > maxUnmappedLines && unmappedStartIdx !== -1) { - const deleteCount = unmappedCount - maxUnmappedLines; - asmLines.splice(unmappedStartIdx + maxUnmappedLines, deleteCount); + else + { + result.push(line); // Other lines (labels, directives) - always keep + } } - - return asmLines; + return result; } } From cfd5fc95b90021215f2ea613bc61b6af3e927415 Mon Sep 17 00:00:00 2001 From: Paul McGee Date: Fri, 28 Nov 2025 22:35:48 +0800 Subject: [PATCH 26/27] Readme - Add YouTube Demo of LCE --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 7c54d721855..77d6e572d3a 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,17 @@ [See **_Windows install_** guideline for Delphi & fpc **_here_**](docs/DelphiCppBuilderSpecifics.md) + + +[Demonstration - Local Compiler Explorer - 2025](https://youtu.be/yPOwvKojM7s) + + + + +[![Youtube Video](https://github.com/user-attachments/assets/865b9e5c-82a5-42dd-89c0-5e5ea4883d79)](https://youtu.be/yPOwvKojM7s) + + + --- **Compiler Explorer** is an interactive compiler exploration website. Edit C, C++, Rust, Go, D, Haskell, Swift, Pascal, [ispc](https://ispc.github.io/) or other language code, and see how that code looks after being compiled in real time. From bb72a8ae8fd332691ef273b3fffe50f3645c665d Mon Sep 17 00:00:00 2001 From: Compiler Explorer Bot Date: Wed, 1 Jul 2026 03:59:55 +0000 Subject: [PATCH 27/27] Automated checkin - update browsers list --- package-lock.json | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8835aa41340..1ee1851d4d1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6280,12 +6280,15 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.8.19", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.19.tgz", - "integrity": "sha512-zoKGUdu6vb2jd3YOq0nnhEDQVbPcHhco3UImJrv5dSkvxTc2pl2WjOPsjZXDwPDSl5eghIMuY3R6J9NDKF3KcQ==", + "version": "2.10.40", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.40.tgz", + "integrity": "sha512-BSSLZ9/Cjjv7Gtj5B68ZzXcXUg8iOf3fme+FCuh8rC/Go+Kmh8cox7M3A8dolou16s64QjLPOSdngh7GxXvkSw==", "license": "Apache-2.0", "bin": { - "baseline-browser-mapping": "dist/cli.js" + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" } }, "node_modules/basic-auth": { @@ -6646,9 +6649,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001757", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001757.tgz", - "integrity": "sha512-r0nnL/I28Zi/yjk1el6ilj27tKcdjLsNqAOZr0yVjWPrSQyHgKI2INaEWw21bAQSv2LXRt1XuCS/GomNpWOxsQ==", + "version": "1.0.30001800", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001800.tgz", + "integrity": "sha512-MMHtuAz9Ys840zAY5F4k6fV5GaivZ9sPk+nz0mY+GYVzRBnYkN0mpqkSR92oWRQ19yQWo4HvBV/FnC16AJX8MA==", "funding": [ { "type": "opencollective",