diff options
author | Patrick Quist <partouf@gmail.com> | 2021-09-13 20:22:27 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-09-13 20:22:27 +0200 |
commit | bc6757ae94dbc46fa1243f3277de2262794d5a75 (patch) | |
tree | d264a83fea30a6b189def084c0d422814b814de3 /lib/compilers | |
parent | 3d1a6a672066d5d2b93255ffb7e39a1293bb227c (diff) | |
download | compiler-explorer-bc6757ae94dbc46fa1243f3277de2262794d5a75.tar.gz compiler-explorer-bc6757ae94dbc46fa1243f3277de2262794d5a75.zip |
Pascalchanges (#2881)
* Changes to allow Program (vs Unit) in Object Pascal
* add possibility of dpr
* more flexibility with pascal filenames
* lintfixes
* i have no idea what im doing
* apply changes to pascal-win
* pascal fixes
* pascal projectfile changes
* work in progress
* bugfixes
* bla
* bugfixes
* mostly working
Co-authored-by: paul mcgee <paul.mcgee.8@bigpond.com>
Co-authored-by: Paul McGee <paulmcgee1969@gmail.com>
Diffstat (limited to 'lib/compilers')
-rw-r--r-- | lib/compilers/pascal-utils.js | 45 | ||||
-rw-r--r-- | lib/compilers/pascal-win.js | 67 | ||||
-rw-r--r-- | lib/compilers/pascal.js | 119 |
3 files changed, 193 insertions, 38 deletions
diff --git a/lib/compilers/pascal-utils.js b/lib/compilers/pascal-utils.js new file mode 100644 index 000000000..d1f354bc1 --- /dev/null +++ b/lib/compilers/pascal-utils.js @@ -0,0 +1,45 @@ +// 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 class PascalUtils { + isProgram(source) { + const re = /\s?program\s+([\w.-]*);/i; + return !!re.test(source); + } + + isUnit(source) { + const re = /\s?unit\s+([\w.-]*);/i; + return !!re.test(source); + } + + getUnitname(source) { + const re = /\s?unit\s+([\w.-]*);/i; + const match = source.match(re); + if (match) { + return match[1]; + } + + return 'example'; + } +} diff --git a/lib/compilers/pascal-win.js b/lib/compilers/pascal-win.js index eef29685e..85bdac61b 100644 --- a/lib/compilers/pascal-win.js +++ b/lib/compilers/pascal-win.js @@ -31,6 +31,8 @@ import { MapFileReaderDelphi } from '../map-file-delphi'; import { PELabelReconstructor } from '../pe32-support'; import * as utils from '../utils'; +import { PascalUtils } from './pascal-utils'; + export class PascalWinCompiler extends BaseCompiler { static get key() { return 'pascal-win'; } @@ -40,6 +42,12 @@ export class PascalWinCompiler extends BaseCompiler { this.mapFilename = false; this.compileFilename = 'output.pas'; + this.dprFilename = 'prog.dpr'; + this.pasUtils = new PascalUtils(); + } + + getSharedLibraryPathsAsArguments() { + return []; } exec(command, args, options) { @@ -56,6 +64,10 @@ export class PascalWinCompiler extends BaseCompiler { return super.exec(command, args, options); } + getExecutableFilename(dirPath) { + return path.join(dirPath, 'prog.exe'); + } + getOutputFilename(dirPath) { return path.join(dirPath, 'prog.exe'); } @@ -85,30 +97,59 @@ export class PascalWinCompiler extends BaseCompiler { }); } - saveDummyProjectFile(dprfile, sourcefile) { - if (dprfile.startsWith('Z:')) { - dprfile = dprfile.substr(2); + async saveDummyProjectFile(filename, unitName, unitPath) { + await fs.writeFile(filename, + 'program prog;\n' + + 'uses ' + unitName + ' in \'' + unitPath + '\';\n' + + 'begin\n' + + 'end.\n'); + } + + async writeAllFiles(dirPath, source, files, filters) { + let inputFilename; + if (this.pasUtils.isProgram(source)) { + inputFilename = path.join(dirPath, this.dprFilename); + } else { + const unitName = this.pasUtils.getUnitname(source); + if (unitName) { + inputFilename = path.join(dirPath, unitName + '.pas'); + } else { + inputFilename = path.join(dirPath, this.compileFilename); + } + } + + await fs.writeFile(inputFilename, source); + + if (files) { + filters.dontMaskFilenames = true; + + await this.writeMultipleFiles(files, dirPath); } - fs.writeFileSync(dprfile, - 'program prog; ' + - "uses output in '" + sourcefile + "'; " + - 'begin ' + - 'end.'); + return { + inputFilename, + }; } - runCompiler(compiler, options, inputFilename, execOptions) { + async runCompiler(compiler, options, inputFilename, execOptions) { if (!execOptions) { execOptions = this.getDefaultExecOptions(); } + let alreadyHasDPR = path.basename(inputFilename) === this.dprFilename; + const tempPath = path.dirname(inputFilename); - const projectFile = path.join(tempPath, 'prog.dpr'); + const projectFile = path.join(tempPath, this.dprFilename); this.mapFilename = path.join(tempPath, 'prog.map'); inputFilename = inputFilename.replace(/\//g, '\\'); - this.saveDummyProjectFile(projectFile, inputFilename); + + if (!alreadyHasDPR) { + const unitFilepath = path.basename(inputFilename); + const unitName = unitFilepath.replace(/.pas$/i, ''); + await this.saveDummyProjectFile(projectFile, unitName, unitFilepath); + } options.pop(); @@ -121,7 +162,8 @@ export class PascalWinCompiler extends BaseCompiler { '-V', '-B'); - options.push(projectFile.replace(/\//g, '\\')); + options.push(projectFile); + execOptions.customCwd = tempPath; return this.exec(compiler, options, execOptions).then((result) => { result.inputFilename = inputFilename; @@ -133,6 +175,7 @@ export class PascalWinCompiler extends BaseCompiler { optionsForFilter(filters) { filters.binary = true; + filters.dontMaskFilenames = true; filters.preProcessBinaryAsmLines = (asmLines) => { const mapFileReader = new MapFileReaderDelphi(this.mapFilename); const reconstructor = new PELabelReconstructor(asmLines, false, mapFileReader, false); diff --git a/lib/compilers/pascal.js b/lib/compilers/pascal.js index 605e741ab..136e49190 100644 --- a/lib/compilers/pascal.js +++ b/lib/compilers/pascal.js @@ -31,6 +31,7 @@ import { BaseCompiler } from '../base-compiler'; import * as utils from '../utils'; import { PascalParser } from './argument-parsers'; +import { PascalUtils } from './pascal-utils'; export class FPCCompiler extends BaseCompiler { static get key() { @@ -41,8 +42,10 @@ export class FPCCompiler extends BaseCompiler { super(info, env); this.compileFilename = 'output.pas'; + this.dprFilename = 'prog.dpr'; this.supportsOptOutput = false; this.nasmPath = this.compilerProps('nasmpath'); + this.pasUtils = new PascalUtils(); } getSharedLibraryPathsAsArguments() { @@ -78,6 +81,10 @@ export class FPCCompiler extends BaseCompiler { filters.preProcessLines = _.bind(this.preProcessLines, this); + if (filters.binary) { + filters.dontMaskFilenames = true; + } + return options; } @@ -90,7 +97,8 @@ export class FPCCompiler extends BaseCompiler { } static preProcessBinaryAsm(input) { - const relevantAsmStartsAt = input.indexOf('<OUTPUT'); + const systemInitOffset = input.indexOf('<SYSTEM_$$_init$>'); + const relevantAsmStartsAt = input.indexOf('...', systemInitOffset); if (relevantAsmStartsAt !== -1) { const lastLinefeedBeforeStart = input.lastIndexOf('\n', relevantAsmStartsAt); if (lastLinefeedBeforeStart !== -1) { @@ -106,22 +114,44 @@ export class FPCCompiler extends BaseCompiler { return input; } - getObjdumpOutputFilename(defaultOutputFilename) { - return this.getExecutableFilename(path.dirname(defaultOutputFilename)); - } - postProcessObjdumpOutput(output) { return FPCCompiler.preProcessBinaryAsm(output); } - async saveDummyProjectFile(filename) { - const unitName = path.basename(this.compileFilename, this.lang.extensions[0]); - + async saveDummyProjectFile(filename, unitName, unitPath) { await fs.writeFile(filename, - 'program prog; ' + - 'uses ' + unitName + ' in \'' + this.compileFilename + '\'; ' + - 'begin ' + - 'end.'); + 'program prog;\n' + + 'uses ' + unitName + ' in \'' + unitPath + '\';\n' + + 'begin\n' + + 'end.\n'); + } + + async writeAllFiles(dirPath, source, files, filters) { + let inputFilename; + if (this.pasUtils.isProgram(source)) { + inputFilename = path.join(dirPath, this.dprFilename); + } else { + const unitName = this.pasUtils.getUnitname(source); + if (unitName) { + inputFilename = path.join(dirPath, unitName + '.pas'); + } else { + inputFilename = path.join(dirPath, this.compileFilename); + } + } + + if (source !== '' || !files) { + await fs.writeFile(inputFilename, source); + } + + if (files) { + filters.dontMaskFilenames = true; + + await this.writeMultipleFiles(files, dirPath); + } + + return { + inputFilename, + }; } async runCompiler(compiler, options, inputFilename, execOptions) { @@ -129,14 +159,21 @@ export class FPCCompiler extends BaseCompiler { execOptions = this.getDefaultExecOptions(); } + let alreadyHasDPR = path.basename(inputFilename) === this.dprFilename; const dirPath = path.dirname(inputFilename); - const projectFile = path.join(dirPath, 'prog.dpr'); + + const projectFile = path.join(dirPath, this.dprFilename); execOptions.customCwd = dirPath; if (this.nasmPath) { execOptions.env = _.clone(process.env); execOptions.env.PATH = execOptions.env.PATH + ':' + this.nasmPath; } - await this.saveDummyProjectFile(projectFile); + + if (!alreadyHasDPR) { + const unitFilepath = path.basename(inputFilename); + const unitName = unitFilepath.replace(/.pas$/i, ''); + await this.saveDummyProjectFile(projectFile, unitName, unitFilepath); + } options.pop(); options.push('-FE' + dirPath, '-B', projectFile); @@ -152,17 +189,11 @@ export class FPCCompiler extends BaseCompiler { return result; } - execBinary(executable, maxSize, executeParameters, homeDir) { - executable = this.getExecutableFilename(path.dirname(executable)); - - return super.execBinary(executable, maxSize, executeParameters, homeDir); - } - getArgumentParser() { return PascalParser; } - getExtraAsmHint(asm) { + getExtraAsmHint(asm, currentFileId) { if (asm.startsWith('# [')) { const bracketEndPos = asm.indexOf(']', 3); let valueInBrackets = asm.substr(3, bracketEndPos - 3); @@ -171,12 +202,14 @@ export class FPCCompiler extends BaseCompiler { valueInBrackets = valueInBrackets.substr(0, colonPos - 1); } + if (valueInBrackets.startsWith('/')) { + valueInBrackets = valueInBrackets.substr(1); + } + if (!isNaN(valueInBrackets)) { - return ' .loc 1 ' + valueInBrackets + ' 0'; - } else if (valueInBrackets.includes(this.compileFilename)) { - return ' .file 1 "<stdin>"'; + return ` .loc ${currentFileId} ${valueInBrackets} 0`; } else { - return false; + return ` .file ${currentFileId} "${valueInBrackets}"`; } } else if (asm.startsWith('.Le')) { return ' .cfi_endproc'; @@ -185,11 +218,45 @@ export class FPCCompiler extends BaseCompiler { } } + tryGetFilenumber(asm, files) { + if (asm.startsWith('# [')) { + const bracketEndPos = asm.indexOf(']', 3); + let valueInBrackets = asm.substr(3, bracketEndPos - 3); + const colonPos = valueInBrackets.indexOf(':'); + if (colonPos !== -1) { + valueInBrackets = valueInBrackets.substr(0, colonPos - 1); + } + + if (valueInBrackets.startsWith('/')) { + valueInBrackets = valueInBrackets.substr(1); + } + + if (isNaN(valueInBrackets)) { + if (!files[valueInBrackets]) { + let maxFileId = _.max(files); + if (maxFileId === -Infinity) { + maxFileId = 0; + } + + files[valueInBrackets] = maxFileId + 1; + return maxFileId + 1; + } + } + } + + return false; + } + preProcessLines(asmLines) { let i = 0; + let files = {}; + let currentFileId = 1; while (i < asmLines.length) { - const extraHint = this.getExtraAsmHint(asmLines[i]); + let newFileId = this.tryGetFilenumber(asmLines[i], files); + if (newFileId) currentFileId = newFileId; + + const extraHint = this.getExtraAsmHint(asmLines[i], currentFileId); if (extraHint) { i++; asmLines.splice(i, 0, extraHint); |