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>
This commit is contained in:
Patrick Quist
2021-09-13 20:22:27 +02:00
committed by GitHub
parent 3d1a6a6720
commit bc6757ae94
12 changed files with 489 additions and 91 deletions

View File

@@ -761,15 +761,26 @@ export class BaseCompiler {
return Promise.all(filesToWrite);
}
async writeAllFiles(dirPath, source, files, filters) {
const inputFilename = path.join(dirPath, this.compileFilename);
await fs.writeFile(inputFilename, source);
if (files) {
filters.dontMaskFilenames = true;
await this.writeMultipleFiles(files, dirPath);
}
return {
inputFilename,
};
}
async buildExecutableInFolder(key, dirPath) {
const buildEnvironment = this.setupBuildEnvironment(key, dirPath);
const inputFilename = path.join(dirPath, this.compileFilename);
const writerOfSource = fs.writeFile(inputFilename, key.source);
if (key.files) {
await this.writeMultipleFiles(key.files, dirPath);
}
const writeSummary = await this.writeAllFiles(dirPath, key.source, key.files, key.filters);
const inputFilename = writeSummary.inputFilename;
const outputFilename = this.getExecutableFilename(dirPath, this.outputFilebase, key);
@@ -785,7 +796,6 @@ export class BaseCompiler {
const execOptions = this.getDefaultExecOptions();
execOptions.ldPath = this.getSharedLibraryPathsAsLdLibraryPaths(key.libraries);
await writerOfSource;
const downloads = await buildEnvironment;
const result = await this.buildExecutable(key.compiler.exe, compilerArguments, inputFilename,
execOptions);
@@ -829,7 +839,7 @@ export class BaseCompiler {
const endTime = process.hrtime.bigint();
return Object.assign({}, buildResults, {
code: 0,
inputFilename: path.join(dirPath, this.compileFilename),
inputFilename: path.join(dirPath, path.basename(buildResults.inputFilename)),
dirPath: dirPath,
executableFilename: this.getExecutableFilename(dirPath, this.outputFilebase, key),
packageDownloadAndUnzipTime: ((endTime - startTime) / BigInt(1000000)).toString(),
@@ -1329,17 +1339,11 @@ export class BaseCompiler {
}
const dirPath = await this.newTempDir();
const inputFilename = path.join(dirPath, this.compileFilename);
await fs.writeFile(inputFilename, source);
if (files) {
filters.dontMaskFilenames = true;
const writeSummary = await this.writeAllFiles(dirPath, source, files, filters);
const inputFilename = writeSummary.inputFilename;
await this.writeMultipleFiles(files, dirPath);
}
// TODO make const when I can
let [result, optOutput] = await this.doCompilation(
const [result, optOutput] = await this.doCompilation(
inputFilename, dirPath, key, options, filters, backendOptions, libraries, tools);
return await this.afterCompilation(result, doExecute, key, executeParameters, tools, backendOptions,

View File

@@ -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';
}
}

View File

@@ -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);
}
fs.writeFileSync(dprfile,
'program prog; ' +
"uses output in '" + sourcefile + "'; " +
'begin ' +
'end.');
async saveDummyProjectFile(filename, unitName, unitPath) {
await fs.writeFile(filename,
'program prog;\n' +
'uses ' + unitName + ' in \'' + unitPath + '\';\n' +
'begin\n' +
'end.\n');
}
runCompiler(compiler, options, inputFilename, execOptions) {
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);
}
return {
inputFilename,
};
}
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);

View File

@@ -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);

View File

@@ -172,7 +172,7 @@ export const languages = {
pascal: {
name: 'Pascal',
monaco: 'pascal',
extensions: ['.pas'],
extensions: ['.pas', '.dpr'],
alias: [],
},
fortran: {

View File

@@ -72,6 +72,12 @@ export class MapFileReaderDelphi extends MapFileReader {
codesegmentObject.segmentLength = parseInt(matches[3], 16);
codesegmentObject.unitName = matches[4];
if (codesegmentObject.unitName === 'prog') {
codesegmentObject.unitName = 'prog.dpr';
} else {
codesegmentObject.unitName = codesegmentObject.unitName + '.pas';
}
this.segments.push(codesegmentObject);
} else {
matches = line.match(this.regexDelphiICodeSegment);
@@ -81,6 +87,12 @@ export class MapFileReaderDelphi extends MapFileReader {
codesegmentObject.segmentLength = parseInt(matches[3], 16);
codesegmentObject.unitName = matches[4];
if (codesegmentObject.unitName === 'prog') {
codesegmentObject.unitName = 'prog.dpr';
} else {
codesegmentObject.unitName = codesegmentObject.unitName + '.pas';
}
this.isegments.push(codesegmentObject);
}
}

View File

@@ -48,10 +48,11 @@ export class PELabelReconstructor {
*
* @param {string} unitName
*/
run(unitName) {
run(/*unitName*/) {
this.mapFileReader.run();
this.deleteEverythingBut(unitName);
//this.deleteEverythingBut(unitName);
this.deleteSystemUnits();
this.shortenInt3s();
this.collectJumpsAndCalls();
@@ -122,6 +123,25 @@ export class PELabelReconstructor {
}
}
deleteSystemUnits() {
const systemUnits = new Set(['SysInit.pas', 'System.pas', 'SysUtils.pas', 'Classes.pas']);
let idx, info;
for (idx = 0; idx < this.mapFileReader.segments.length; idx++) {
info = this.mapFileReader.segments[idx];
if (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 (systemUnits.has(info.unitName)) {
this.deleteLinesBetweenAddresses(info.addressInt, info.addressInt + info.segmentLength);
}
}
}
/**
*
* @param {number} beginAddress
@@ -201,8 +221,6 @@ export class PELabelReconstructor {
* if an address doesn't have a mapped name, it is called <Laddress>
*/
insertLabels() {
const sourceFileId = this.mapFileReader.getSegmentIdByUnitName('output');
let currentSegment = false;
let lineIdx = 0;
@@ -249,12 +267,12 @@ export class PELabelReconstructor {
}
const lineInfo = this.mapFileReader.getLineInfoByAddress(false, address);
if (lineInfo && currentSegment.unitName.startsWith('output')) {
this.asmLines.splice(lineIdx, 0, '/' + sourceFileId + ':' + lineInfo.lineNumber);
if (lineInfo && currentSegment.unitName) {
this.asmLines.splice(lineIdx, 0, '/app/' + currentSegment.unitName + ':' + lineInfo.lineNumber);
lineIdx++;
}
}
lineIdx++;
}
}

View File

@@ -295,10 +295,18 @@ export class MultifileService {
return false;
}
} else {
if (file.filename === MultifileService.getDefaultMainSourceFilename(this.compilerLanguageId)) {
this.setAsMainSource(file.fileId);
if (this.compilerLanguageId === 'pascal') {
if (file.filename.endsWith('.dpr')) {
this.setAsMainSource(file.fileId);
} else {
return false;
}
} else {
return false;
if (file.filename === MultifileService.getDefaultMainSourceFilename(this.compilerLanguageId)) {
this.setAsMainSource(file.fileId);
} else {
return false;
}
}
}

View File

@@ -45,25 +45,25 @@ describe('Code Segments', function () {
reader.segments.length.should.equal(1);
let info = reader.getSegmentInfoByStartingAddress('0001', 0x2838);
info.unitName.should.equal('output');
info.unitName.should.equal('output.pas');
info = reader.getSegmentInfoByStartingAddress(false, reader.getSegmentOffset('0001') + 0x2838);
info.unitName.should.equal('output');
info.unitName.should.equal('output.pas');
info = reader.getSegmentInfoByStartingAddress('0001', '2838');
info.should.equal(false, 'Address should not be a Start for any segment');
info = reader.getSegmentInfoAddressIsIn('0001', 0x2838 + 0x10);
info.unitName.should.equal('output');
info.unitName.should.equal('output.pas');
info = reader.getSegmentInfoAddressIsIn(false, reader.getSegmentOffset('0001') + 0x2838 + 0x10);
info.unitName.should.equal('output');
info.unitName.should.equal('output.pas');
info = reader.getSegmentInfoAddressIsIn('0001', reader.getSegmentOffset('0001') + 0x2838 + 0x80 + 1);
info.should.equal(false, 'Address should not be in any segment');
info = reader.getSegmentInfoByUnitName('output');
info.unitName.should.equal('output');
info = reader.getSegmentInfoByUnitName('output.pas');
info.unitName.should.equal('output.pas');
info.addressInt.should.equal(reader.getSegmentOffset('0001') + 0x2838);
});
@@ -209,10 +209,10 @@ describe('Delphi-Map load test', function () {
reader.lineNumbers.length.should.equal(7);
reader.namedAddresses.length.should.equal(11);
let info = reader.getSegmentInfoByUnitName('output');
let info = reader.getSegmentInfoByUnitName('output.pas');
info.addressInt.should.equal(reader.getSegmentOffset('0001') + 0x2C4C);
info = reader.getICodeSegmentInfoByUnitName('output');
info = reader.getICodeSegmentInfoByUnitName('output.pas');
info.segment.should.equal('0002');
info.addressWithoutOffset.should.equal(0xB0);
info.addressInt.should.equal(0x4040B0);

View File

@@ -22,7 +22,11 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
import path from 'path';
import { FPCCompiler } from '../lib/compilers/pascal';
import { PascalUtils } from '../lib/compilers/pascal-utils';
import { PascalWinCompiler } from '../lib/compilers/pascal-win';
import { PascalDemangler } from '../lib/demangler';
import * as utils from '../lib/utils';
@@ -313,7 +317,7 @@ describe('Pascal', () => {
resolve(Promise.all([
asmLines.should.include('# [output.pas]'),
asmLines.should.include(' .file 1 "<stdin>"'),
asmLines.should.include(' .file 1 "output.pas"'),
asmLines.should.include('# [13] Square := num * num + 14;'),
asmLines.should.include(' .loc 1 13 0'),
asmLines.should.include('.Le0:'),
@@ -324,20 +328,20 @@ describe('Pascal', () => {
});
});
describe('Pascal objdump filtering', function () {
it('Should filter out most of the runtime', function () {
return new Promise(function (resolve) {
fs.readFile('test/pascal/objdump-example.s', function (err, buffer) {
const output = FPCCompiler.preProcessBinaryAsm(buffer.toString());
resolve(Promise.all([
utils.splitLines(output).length.should.be.below(500),
output.should.not.include('fpc_zeromem():'),
output.should.include('SQUARE():'),
]));
});
});
});
});
// describe('Pascal objdump filtering', function () {
// it('Should filter out most of the runtime', function () {
// return new Promise(function (resolve) {
// fs.readFile('test/pascal/objdump-example.s', function (err, buffer) {
// const output = FPCCompiler.preProcessBinaryAsm(buffer.toString());
// resolve(Promise.all([
// utils.splitLines(output).length.should.be.below(500),
// output.should.not.include('fpc_zeromem():'),
// output.should.include('SQUARE():'),
// ]));
// });
// });
// });
// });
describe('Pascal parseOutput', () => {
it('should return parsed output', () => {
@@ -355,4 +359,176 @@ describe('Pascal', () => {
});
});
});
describe('Pascal filetype detection', () => {
const pasUtils = new PascalUtils();
const progSource = fs.readFileSync('test/pascal/prog.dpr').toString('utf8');
const unitSource = fs.readFileSync('test/pascal/example.pas').toString('utf8');
it('Should detect simple program', () => {
pasUtils.isProgram(progSource).should.equal(true);
pasUtils.isProgram(unitSource).should.equal(false);
});
it('Should detect simple unit', () => {
pasUtils.isUnit(progSource).should.equal(false);
pasUtils.isUnit(unitSource).should.equal(true);
});
});
describe('Multifile writing behaviour', function () {
let compiler;
before(() => {
const ce = makeCompilationEnvironment({languages});
const info = {
exe: null,
remote: true,
lang: languages.pascal.id,
};
compiler = new FPCCompiler(info, ce);
});
it('Original behaviour (old unitname)', async function () {
const dirPath = await compiler.newTempDir();
const filters = {};
const files = [];
const source = fs.readFileSync('examples/pascal/default.pas').toString('utf8');
const writeSummary = await compiler.writeAllFiles(dirPath, source, files, filters);
return Promise.all([
writeSummary.inputFilename.should.equal(path.join(dirPath, 'output.pas')),
utils.fileExists(path.join(dirPath, 'output.pas')).should.eventually.equal(true),
utils.fileExists(path.join(dirPath, 'prog.dpr')).should.eventually.equal(false), // note: will be written somewhere else
]);
});
it('Original behaviour (just a unit file)', async function () {
const dirPath = await compiler.newTempDir();
const filters = {};
const files = [];
const source = fs.readFileSync('test/pascal/example.pas').toString('utf8');
const writeSummary = await compiler.writeAllFiles(dirPath, source, files, filters);
return Promise.all([
writeSummary.inputFilename.should.equal(path.join(dirPath, 'example.pas')),
utils.fileExists(path.join(dirPath, 'example.pas')).should.eventually.equal(true),
utils.fileExists(path.join(dirPath, 'prog.dpr')).should.eventually.equal(false), // note: will be written somewhere else
]);
});
it('Writing program instead of a unit', async function () {
const dirPath = await compiler.newTempDir();
const filters = {};
const files = [];
const source = fs.readFileSync('test/pascal/prog.dpr').toString('utf8');
const writeSummary = await compiler.writeAllFiles(dirPath, source, files, filters);
return Promise.all([
writeSummary.inputFilename.should.equal(path.join(dirPath, 'prog.dpr')),
utils.fileExists(path.join(dirPath, 'example.pas')).should.eventually.equal(false),
utils.fileExists(path.join(dirPath, 'prog.dpr')).should.eventually.equal(true),
]);
});
it('Writing program with a unit', async function () {
const dirPath = await compiler.newTempDir();
const filters = {};
const files = [{
filename: 'example.pas',
contents: '{ hello\n world }',
}];
const source = fs.readFileSync('test/pascal/prog.dpr').toString('utf8');
const writeSummary = await compiler.writeAllFiles(dirPath, source, files, filters);
return Promise.all([
writeSummary.inputFilename.should.equal(path.join(dirPath, 'prog.dpr')),
utils.fileExists(path.join(dirPath, 'example.pas')).should.eventually.equal(true),
utils.fileExists(path.join(dirPath, 'prog.dpr')).should.eventually.equal(true),
]);
});
});
describe('Multifile writing behaviour Pascal-WIN', function () {
let compiler;
before(() => {
const ce = makeCompilationEnvironment({languages});
const info = {
exe: null,
remote: true,
lang: languages.pascal.id,
};
compiler = new PascalWinCompiler(info, ce);
});
it('Original behaviour (old unitname)', async function () {
const dirPath = await compiler.newTempDir();
const filters = {};
const files = [];
const source = fs.readFileSync('examples/pascal/default.pas').toString('utf8');
const writeSummary = await compiler.writeAllFiles(dirPath, source, files, filters);
return Promise.all([
writeSummary.inputFilename.should.equal(path.join(dirPath, 'output.pas')),
utils.fileExists(path.join(dirPath, 'output.pas')).should.eventually.equal(true),
utils.fileExists(path.join(dirPath, 'prog.dpr')).should.eventually.equal(false), // note: will be written somewhere else
]);
});
it('Original behaviour (just a unit file)', async function () {
const dirPath = await compiler.newTempDir();
const filters = {};
const files = [];
const source = fs.readFileSync('test/pascal/example.pas').toString('utf8');
const writeSummary = await compiler.writeAllFiles(dirPath, source, files, filters);
return Promise.all([
writeSummary.inputFilename.should.equal(path.join(dirPath, 'example.pas')),
utils.fileExists(path.join(dirPath, 'example.pas')).should.eventually.equal(true),
utils.fileExists(path.join(dirPath, 'prog.dpr')).should.eventually.equal(false), // note: will be written somewhere else
]);
});
it('Writing program instead of a unit', async function () {
const dirPath = await compiler.newTempDir();
const filters = {};
const files = [];
const source = fs.readFileSync('test/pascal/prog.dpr').toString('utf8');
const writeSummary = await compiler.writeAllFiles(dirPath, source, files, filters);
return Promise.all([
writeSummary.inputFilename.should.equal(path.join(dirPath, 'prog.dpr')),
utils.fileExists(path.join(dirPath, 'example.pas')).should.eventually.equal(false),
utils.fileExists(path.join(dirPath, 'prog.dpr')).should.eventually.equal(true),
]);
});
it('Writing program with a unit', async function () {
const dirPath = await compiler.newTempDir();
const filters = {};
const files = [{
filename: 'example.pas',
contents: '{ hello\n world }',
}];
const source = fs.readFileSync('test/pascal/prog.dpr').toString('utf8');
const writeSummary = await compiler.writeAllFiles(dirPath, source, files, filters);
return Promise.all([
writeSummary.inputFilename.should.equal(path.join(dirPath, 'prog.dpr')),
utils.fileExists(path.join(dirPath, 'example.pas')).should.eventually.equal(true),
utils.fileExists(path.join(dirPath, 'prog.dpr')).should.eventually.equal(true),
]);
});
});
});

18
test/pascal/example.pas Normal file
View File

@@ -0,0 +1,18 @@
unit example;
interface
type
TMyClass = class
public
procedure SomeProc;
end;
implementation
procedure TMyClass.SomeProc;
begin
// hello
end;
end.

7
test/pascal/prog.dpr Normal file
View File

@@ -0,0 +1,7 @@
program prog;
uses
example in 'example.pas';
begin
end.