Make argument parsers instances instead of static classes (#8017)

- Made parsers stateful instances instead of shared static state (for
mllvm options). Fixes #8011 as this is caused by multiple clang-based
compilers being run concurrently and stomping over each others' state.
- passes `Compiler` to the constructor, which removes some param passing
- Added some missing awaits
- Tried to get things less dependent on `examples`, only `go` needs it
- Spotted that `zig` c++ might have issues in discovery
- Fly-by fixed a broken go path in ppc64le_gl122
- removed a redundant override in coccinelle
- made the mojo parser actually use the parser it defined
- canonified tablegen's special method
- 

I changed the zig parser too but as best I can tell it was broken before
(the `1` return value from the command it runs:)

```
ubuntu@ip-172-30-0-164:/infra/.deploy$ /opt/compiler-explorer/zig-0.14.1/zig c++ -mllvm --help-list-hidden /infra/.deploy/examples/c++/default.cpp -S -o /tmp/output.s
...
  --x86-use-vzeroupper                                                       - Minimize AVX to SSE transition penalty
  --xcore-max-threads=<number>                                               - Maximum number of threads (for emulation thread-local storage)
/infra/.deploy/examples/c++/default.cpp:1:1: error: FileNotFound
```
return code 1 (means it's not cached)

---------

Co-authored-by: Partouf <partouf@gmail.com>
This commit is contained in:
Matt Godbolt
2025-08-11 12:14:13 -05:00
committed by GitHub
parent bea6e67715
commit 2ae38a0c3f
14 changed files with 450 additions and 409 deletions

View File

@@ -29,6 +29,7 @@ import {CompilerArguments} from './lib/compiler-arguments.js';
import * as Parsers from './lib/compilers/argument-parsers.js'; import * as Parsers from './lib/compilers/argument-parsers.js';
import {executeDirect} from './lib/exec.js'; import {executeDirect} from './lib/exec.js';
import {logger} from './lib/logger.js'; import {logger} from './lib/logger.js';
import {BaseParser} from './lib/compilers/argument-parsers.js';
const program = new Command(); const program = new Command();
program program
@@ -90,6 +91,13 @@ class CompilerArgsApp {
execCompilerCached: async (command: string, args: string[]) => { execCompilerCached: async (command: string, args: string[]) => {
return executeDirect(command, args, {}, fn => fn); return executeDirect(command, args, {}, fn => fn);
}, },
getDefaultExecOptions: () => {
return {
env: process.env,
cwd: process.cwd(),
timeout: 10000,
};
}
}; };
if (this.parserName === 'juliawrapper') { if (this.parserName === 'juliawrapper') {
@@ -99,22 +107,22 @@ class CompilerArgsApp {
async getPossibleStdvers() { async getPossibleStdvers() {
const parser = this.getParser(); const parser = this.getParser();
return await parser.getPossibleStdvers(this.compiler); return await parser.getPossibleStdvers();
} }
async getPossibleTargets() { async getPossibleTargets() {
const parser = this.getParser(); const parser = this.getParser();
return await parser.getPossibleTargets(this.compiler); return await parser.getPossibleTargets();
} }
async getPossibleEditions() { async getPossibleEditions() {
const parser = this.getParser(); const parser = this.getParser();
return await parser.getPossibleEditions(this.compiler); return await parser.getPossibleEditions();
} }
getParser() { getParser(): BaseParser {
if (compilerParsers[this.parserName as keyof typeof compilerParsers]) { if (compilerParsers[this.parserName as keyof typeof compilerParsers]) {
return compilerParsers[this.parserName as keyof typeof compilerParsers]; return new (compilerParsers[this.parserName as keyof typeof compilerParsers])(this.compiler);
} }
console.error('Unknown parser type'); console.error('Unknown parser type');
process.exit(1); process.exit(1);
@@ -122,7 +130,7 @@ class CompilerArgsApp {
async doTheParsing() { async doTheParsing() {
const parser = this.getParser(); const parser = this.getParser();
await parser.parse(this.compiler); await parser.parse();
const options = this.compiler.possibleArguments.possibleArguments; const options = this.compiler.possibleArguments.possibleArguments;
if (parser.hasSupportStartsWith(options, '--target=')) { if (parser.hasSupportStartsWith(options, '--target=')) {
console.log('supportsTargetIs'); console.log('supportsTargetIs');
@@ -150,6 +158,11 @@ class CompilerArgsApp {
console.log(await this.getPossibleTargets()); console.log(await this.getPossibleTargets());
console.log('Editions:'); console.log('Editions:');
console.log(await this.getPossibleEditions()); console.log(await this.getPossibleEditions());
console.log('supportsOptOutput:', !!this.compiler.compiler.supportsOptOutput);
console.log('supportsStackUsageOutput', !!this.compiler.compiler.supportsStackUsageOutput);
console.log('optPipeline:', this.compiler.compiler.optPipeline);
console.log('supportsGccDump', !!this.compiler.compiler.supportsGccDump);
} }
} }

View File

@@ -448,7 +448,7 @@ compiler.ppc64le_gl120.exe=/opt/compiler-explorer/golang-1.20/go/bin/go
compiler.ppc64le_gl120.semver=1.20 compiler.ppc64le_gl120.semver=1.20
compiler.ppc64le_gl121.exe=/opt/compiler-explorer/golang-1.21.13/go/bin/go compiler.ppc64le_gl121.exe=/opt/compiler-explorer/golang-1.21.13/go/bin/go
compiler.ppc64le_gl121.semver=1.21.13 compiler.ppc64le_gl121.semver=1.21.13
compiler.ppc64le_gl122.exe=/opt/compiler-explorer/golang-1.22.1)/go/bin/go compiler.ppc64le_gl122.exe=/opt/compiler-explorer/golang-1.22.1/go/bin/go
compiler.ppc64le_gl122.semver=1.22.12 compiler.ppc64le_gl122.semver=1.22.12
compiler.ppc64le_gl123.exe=/opt/compiler-explorer/golang-1.23.8/go/bin/go compiler.ppc64le_gl123.exe=/opt/compiler-explorer/golang-1.23.8/go/bin/go
compiler.ppc64le_gl123.semver=1.23.8 compiler.ppc64le_gl123.semver=1.23.8

View File

@@ -217,6 +217,7 @@ export class BaseCompiler {
labelNames: [], labelNames: [],
}); });
protected executionEnvironmentClass: any; protected executionEnvironmentClass: any;
protected readonly argParser: BaseParser;
constructor(compilerInfo: PreliminaryCompilerInfo & {disabledFilters?: string[]}, env: CompilationEnvironment) { constructor(compilerInfo: PreliminaryCompilerInfo & {disabledFilters?: string[]}, env: CompilationEnvironment) {
// Information about our compiler // Information about our compiler
@@ -306,6 +307,7 @@ export class BaseCompiler {
} }
this.packager = new Packager(); this.packager = new Packager();
this.argParser = new (this.getArgumentParserClass())(this);
} }
copyAndFilterLibraries(allLibraries: Record<string, OptionsHandlerLibrary>, filter: string[]) { copyAndFilterLibraries(allLibraries: Record<string, OptionsHandlerLibrary>, filter: string[]) {
@@ -3598,8 +3600,7 @@ but nothing was dumped. Possible causes are:
async getTargetsAsOverrideValues(): Promise<CompilerOverrideOption[]> { async getTargetsAsOverrideValues(): Promise<CompilerOverrideOption[]> {
if (!this.buildenvsetup || !this.buildenvsetup.getCompilerArch()) { if (!this.buildenvsetup || !this.buildenvsetup.getCompilerArch()) {
const parserCls = this.getArgumentParserClass(); const targets = await this.argParser.getPossibleTargets();
const targets = await parserCls.getPossibleTargets(this);
return targets.map(target => { return targets.map(target => {
return { return {
@@ -3612,8 +3613,7 @@ but nothing was dumped. Possible causes are:
} }
async getPossibleStdversAsOverrideValues(): Promise<CompilerOverrideOption[]> { async getPossibleStdversAsOverrideValues(): Promise<CompilerOverrideOption[]> {
const parser = this.getArgumentParserClass(); return await this.argParser.getPossibleStdvers();
return await parser.getPossibleStdvers(this);
} }
async populatePossibleRuntimeTools() { async populatePossibleRuntimeTools() {
@@ -3794,7 +3794,7 @@ but nothing was dumped. Possible causes are:
} }
return this; return this;
} }
const initResult = await this.getArgumentParserClass().parse(this); const initResult = await this.argParser.parse();
this.possibleArguments.possibleArguments = {}; this.possibleArguments.possibleArguments = {};
await this.populatePossibleOverrides(); await this.populatePossibleOverrides();

File diff suppressed because it is too large Load Diff

View File

@@ -133,10 +133,6 @@ export class CoccinelleCCompiler extends BaseCompiler {
return super.getIrOutputFilename(inputFilename, filters); return super.getIrOutputFilename(inputFilename, filters);
} }
override getArgumentParserClass() {
return super.getArgumentParserClass();
}
override isCfgCompiler() { override isCfgCompiler() {
return false; return false;
} }

View File

@@ -27,6 +27,7 @@ import path from 'node:path';
import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js'; import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
import {BaseCompiler} from '../base-compiler.js'; import {BaseCompiler} from '../base-compiler.js';
import {changeExtension} from '../utils.js'; import {changeExtension} from '../utils.js';
import {MojoParser} from './argument-parsers.js';
export class MojoCompiler extends BaseCompiler { export class MojoCompiler extends BaseCompiler {
static get key() { static get key() {
@@ -95,4 +96,8 @@ export class MojoCompiler extends BaseCompiler {
const irText = await fs.readFile(llPath, 'utf8'); const irText = await fs.readFile(llPath, 'utf8');
return {asm: irText.split('\n').map(text => ({text}))}; return {asm: irText.split('\n').map(text => ({text}))};
} }
override getArgumentParserClass() {
return MojoParser;
}
} }

View File

@@ -117,7 +117,7 @@ export class RustCompiler extends BaseCompiler {
} }
override async populatePossibleOverrides() { override async populatePossibleOverrides() {
const possibleEditions = await RustParser.getPossibleEditions(this); const possibleEditions = await this.argParser.getPossibleEditions();
if (possibleEditions.length > 0) { if (possibleEditions.length > 0) {
let defaultEdition: undefined | string; let defaultEdition: undefined | string;
if (!this.compiler.semver || this.isNightly()) { if (!this.compiler.semver || this.isNightly()) {

View File

@@ -26,7 +26,7 @@ export class TableGenCompiler extends BaseCompiler {
} }
override async populatePossibleOverrides() { override async populatePossibleOverrides() {
const possibleActions = await TableGenParser.getPossibleActions(this); const possibleActions = await this.argParser.getPossibleActions();
if (possibleActions.length > 0) { if (possibleActions.length > 0) {
this.compiler.possibleOverrides?.push({ this.compiler.possibleOverrides?.push({
name: CompilerOverrideType.action, name: CompilerOverrideType.action,

View File

@@ -100,6 +100,7 @@ describe('LLVM-mca tool definition', () => {
}, },
lang: 'analysis', lang: 'analysis',
disabledFilters: 'labels,directives,debugCalls' as any, disabledFilters: 'labels,directives,debugCalls' as any,
exe: 'clang',
}); });
expect(new AnalysisTool(info, ce).getInfo().disabledFilters).toEqual(['labels', 'directives', 'debugCalls']); expect(new AnalysisTool(info, ce).getInfo().disabledFilters).toEqual(['labels', 'directives', 'debugCalls']);
}); });

View File

@@ -40,13 +40,13 @@ const languages = {
}; };
const androidJavaInfo = { const androidJavaInfo = {
exe: null, exe: 'java',
remote: true, remote: true,
lang: languages.androidJava.id, lang: languages.androidJava.id,
} as unknown as CompilerInfo; } as unknown as CompilerInfo;
const androidKotlinInfo = { const androidKotlinInfo = {
exe: null, exe: 'kotlin',
remote: true, remote: true,
lang: languages.androidKotlin.id, lang: languages.androidKotlin.id,
} as unknown as CompilerInfo; } as unknown as CompilerInfo;

View File

@@ -129,6 +129,7 @@ describe('Compiler execution', () => {
supportsExecute: true, supportsExecute: true,
supportsBinary: true, supportsBinary: true,
options: '--hello-abc -I"/opt/some thing 1.0/include" -march="magic 8bit"', options: '--hello-abc -I"/opt/some thing 1.0/include" -march="magic 8bit"',
exe: 'compiler-exe',
}); });
const win32CompilerInfo = makeFakeCompilerInfo({ const win32CompilerInfo = makeFakeCompilerInfo({
remote: { remote: {
@@ -142,6 +143,7 @@ describe('Compiler execution', () => {
supportsExecute: true, supportsExecute: true,
supportsBinary: true, supportsBinary: true,
options: '/std=c++17 /I"C:/program files (x86)/Company name/Compiler 1.2.3/include" /D "MAGIC=magic 8bit"', options: '/std=c++17 /I"C:/program files (x86)/Company name/Compiler 1.2.3/include" /D "MAGIC=magic 8bit"',
exe: 'compiler.exe',
}); });
const noExecuteSupportCompilerInfo = makeFakeCompilerInfo({ const noExecuteSupportCompilerInfo = makeFakeCompilerInfo({
remote: { remote: {
@@ -153,6 +155,7 @@ describe('Compiler execution', () => {
lang: 'c++', lang: 'c++',
ldPath: [], ldPath: [],
libPath: [], libPath: [],
exe: 'g++',
}); });
const someOptionsCompilerInfo = makeFakeCompilerInfo({ const someOptionsCompilerInfo = makeFakeCompilerInfo({
remote: { remote: {
@@ -167,6 +170,7 @@ describe('Compiler execution', () => {
supportsExecute: true, supportsExecute: true,
supportsBinary: true, supportsBinary: true,
options: '--hello-abc -I"/opt/some thing 1.0/include"', options: '--hello-abc -I"/opt/some thing 1.0/include"',
exe: 'clang++',
}); });
beforeAll(() => { beforeAll(() => {
@@ -681,6 +685,7 @@ describe('getDefaultExecOptions', () => {
ldPath: [], ldPath: [],
libPath: [], libPath: [],
extraPath: ['/tmp/p1', '/tmp/p2'], extraPath: ['/tmp/p1', '/tmp/p2'],
exe: 'g++',
}); });
beforeAll(() => { beforeAll(() => {

View File

@@ -49,13 +49,18 @@ function makeCompiler(stdout?: string, stderr?: string, code?: number) {
describe('option parser', () => { describe('option parser', () => {
it('should do nothing for the base parser', async () => { it('should do nothing for the base parser', async () => {
const compiler = makeCompiler(); const compiler = makeCompiler();
await expect(BaseParser.parse(compiler)).resolves.toEqual(compiler); const parser = new BaseParser(compiler);
await expect(parser.parse()).resolves.toEqual(compiler);
}); });
it('should handle empty options', async () => { it('should handle empty options', async () => {
await expect(BaseParser.getOptions(makeCompiler(), '')).resolves.toEqual({}); const compiler = makeCompiler();
const parser = new BaseParser(compiler);
await expect(parser.getOptions('')).resolves.toEqual({});
}); });
it('should parse single-dash options', async () => { it('should parse single-dash options', async () => {
await expect(BaseParser.getOptions(makeCompiler('-foo\n'), '')).resolves.toEqual({ const compiler = makeCompiler('-foo\n');
const parser = new BaseParser(compiler);
await expect(parser.getOptions('')).resolves.toEqual({
'-foo': { '-foo': {
description: '', description: '',
timesused: 0, timesused: 0,
@@ -63,7 +68,9 @@ describe('option parser', () => {
}); });
}); });
it('should parse double-dash options', async () => { it('should parse double-dash options', async () => {
await expect(BaseParser.getOptions(makeCompiler('--foo\n'), '')).resolves.toEqual({ const compiler = makeCompiler('--foo\n');
const parser = new BaseParser(compiler);
await expect(parser.getOptions('')).resolves.toEqual({
'--foo': { '--foo': {
description: '', description: '',
timesused: 0, timesused: 0,
@@ -71,7 +78,9 @@ describe('option parser', () => {
}); });
}); });
it('should parse stderr options', async () => { it('should parse stderr options', async () => {
await expect(BaseParser.getOptions(makeCompiler('', '--bar=monkey\n'), '')).resolves.toEqual({ const compiler = makeCompiler('', '--bar=monkey\n');
const parser = new BaseParser(compiler);
await expect(parser.getOptions('')).resolves.toEqual({
'--bar=monkey': { '--bar=monkey': {
description: '', description: '',
timesused: 0, timesused: 0,
@@ -79,46 +88,56 @@ describe('option parser', () => {
}); });
}); });
it('handles non-option text', async () => { it('handles non-option text', async () => {
await expect(BaseParser.getOptions(makeCompiler('-foo=123\nthis is a fish\n-badger=123'), '')).resolves.toEqual( const compiler = makeCompiler('-foo=123\nthis is a fish\n-badger=123');
{ const parser = new BaseParser(compiler);
'-foo=123': {description: 'this is a fish', timesused: 0}, await expect(parser.getOptions('')).resolves.toEqual({
'-badger=123': {description: '', timesused: 0}, '-foo=123': {description: 'this is a fish', timesused: 0},
}, '-badger=123': {description: '', timesused: 0},
); });
}); });
it('should ignore if errors occur', async () => { it('should ignore if errors occur', async () => {
await expect(BaseParser.getOptions(makeCompiler('--foo\n', '--bar\n', 1), '')).resolves.toEqual({}); const compiler = makeCompiler('--foo\n', '--bar\n', 1);
const parser = new BaseParser(compiler);
await expect(parser.getOptions('')).resolves.toEqual({});
}); });
}); });
describe('gcc parser', () => { describe('gcc parser', () => {
it('should handle empty options', async () => { it('should handle empty options', async () => {
const result = await GCCParser.parse(makeCompiler()); const compiler = makeCompiler();
const parser = new GCCParser(compiler);
const result = await parser.parse();
expect(result.compiler).not.toHaveProperty('supportsGccDump'); expect(result.compiler).not.toHaveProperty('supportsGccDump');
expect(result.compiler.options).toEqual(''); expect(result.compiler.options).toEqual('');
}); });
it('should handle options', async () => { it('should handle options', async () => {
const result = await GCCParser.parse(makeCompiler('-masm=intel\n-fdiagnostics-color=[blah]\n-fdump-tree-all')); const compiler = makeCompiler('-masm=intel\n-fdiagnostics-color=[blah]\n-fdump-tree-all');
const parser = new GCCParser(compiler);
const result = await parser.parse();
expect(result.compiler.supportsGccDump).toBe(true); expect(result.compiler.supportsGccDump).toBe(true);
expect(result.compiler.supportsIntel).toBe(true); expect(result.compiler.supportsIntel).toBe(true);
expect(result.compiler.intelAsm).toEqual('-masm=intel'); expect(result.compiler.intelAsm).toEqual('-masm=intel');
expect(result.compiler.options).toEqual('-fdiagnostics-color=always'); expect(result.compiler.options).toEqual('-fdiagnostics-color=always');
}); });
it('should handle undefined options', async () => { it('should handle undefined options', async () => {
const result = await GCCParser.parse(makeCompiler('-fdiagnostics-color=[blah]')); const compiler = makeCompiler('-fdiagnostics-color=[blah]');
const parser = new GCCParser(compiler);
const result = await parser.parse();
expect(result.compiler.options).toEqual('-fdiagnostics-color=always'); expect(result.compiler.options).toEqual('-fdiagnostics-color=always');
}); });
}); });
describe('clang parser', () => { describe('clang parser', () => {
it('should handle empty options', async () => { it('should handle empty options', async () => {
const result = await ClangParser.parse(makeCompiler()); const compiler = makeCompiler();
const parser = new ClangParser(compiler);
const result = await parser.parse();
expect(result.compiler.options).toEqual(''); expect(result.compiler.options).toEqual('');
}); });
it('should handle options', async () => { it('should handle options', async () => {
const result = await ClangParser.parse( const compiler = makeCompiler(' -fno-crash-diagnostics\n -fsave-optimization-record\n -fcolor-diagnostics');
makeCompiler(' -fno-crash-diagnostics\n -fsave-optimization-record\n -fcolor-diagnostics'), const parser = new ClangParser(compiler);
); const result = await parser.parse();
expect(result.compiler.supportsOptOutput).toBe(true); expect(result.compiler.supportsOptOutput).toBe(true);
expect(result.compiler.optArg).toEqual('-fsave-optimization-record'); expect(result.compiler.optArg).toEqual('-fsave-optimization-record');
expect(result.compiler.options).toContain('-fcolor-diagnostics'); expect(result.compiler.options).toContain('-fcolor-diagnostics');
@@ -129,7 +148,9 @@ describe('clang parser', () => {
describe('pascal parser', () => { describe('pascal parser', () => {
it('should handle empty options', async () => { it('should handle empty options', async () => {
const result = await PascalParser.parse(makeCompiler()); const compiler = makeCompiler();
const parser = new PascalParser(compiler);
const result = await parser.parse();
expect(result.compiler.options).toEqual(''); expect(result.compiler.options).toEqual('');
}); });
}); });
@@ -144,7 +165,8 @@ describe('popular compiler arguments', () => {
}); });
it('should return 5 arguments', async () => { it('should return 5 arguments', async () => {
const result = await ClangParser.parse(compiler); const parser = new ClangParser(compiler);
const result = await parser.parse();
expect(result.possibleArguments.getPopularArguments()).toEqual({ expect(result.possibleArguments.getPopularArguments()).toEqual({
'-O<number>': {description: 'Optimization level', timesused: 0}, '-O<number>': {description: 'Optimization level', timesused: 0},
'-fcolor-diagnostics': {description: '', timesused: 0}, '-fcolor-diagnostics': {description: '', timesused: 0},
@@ -155,7 +177,8 @@ describe('popular compiler arguments', () => {
}); });
it('should return arguments except the ones excluded', async () => { it('should return arguments except the ones excluded', async () => {
const result = await ClangParser.parse(compiler); const parser = new ClangParser(compiler);
const result = await parser.parse();
expect(result.possibleArguments.getPopularArguments(['-O3', '--hello'])).toEqual({ expect(result.possibleArguments.getPopularArguments(['-O3', '--hello'])).toEqual({
'-fcolor-diagnostics': {description: '', timesused: 0}, '-fcolor-diagnostics': {description: '', timesused: 0},
'-fsave-optimization-record': {description: '', timesused: 0}, '-fsave-optimization-record': {description: '', timesused: 0},
@@ -166,7 +189,8 @@ describe('popular compiler arguments', () => {
}); });
it('should be able to exclude special params with assignments', async () => { it('should be able to exclude special params with assignments', async () => {
const result = await ClangParser.parse(compiler); const parser = new ClangParser(compiler);
const result = await parser.parse();
expect(result.possibleArguments.getPopularArguments(['-std=c++14', '-g', '--hello'])).toEqual({ expect(result.possibleArguments.getPopularArguments(['-std=c++14', '-g', '--hello'])).toEqual({
'-O<number>': {description: 'Optimization level', timesused: 0}, '-O<number>': {description: 'Optimization level', timesused: 0},
'-fcolor-diagnostics': {description: '', timesused: 0}, '-fcolor-diagnostics': {description: '', timesused: 0},
@@ -188,7 +212,9 @@ describe('VC argument parser', () => {
' /something:<else> Something Else', ' /something:<else> Something Else',
' /etc Etcetera', ' /etc Etcetera',
]; ];
const stdvers = VCParser.extractPossibleStdvers(lines); const compiler = makeCompiler();
const parser = new VCParser(compiler);
const stdvers = parser.extractPossibleStdvers(lines);
expect(stdvers).toEqual([ expect(stdvers).toEqual([
{ {
name: 'c++14: ISO/IEC 14882:2014 (default)', name: 'c++14: ISO/IEC 14882:2014 (default)',
@@ -221,7 +247,9 @@ describe('ICC argument parser', () => {
' gnu++98 conforms to 1998 ISO C++ standard plus GNU extensions', ' gnu++98 conforms to 1998 ISO C++ standard plus GNU extensions',
'-etc', '-etc',
]; ];
const stdvers = ICCParser.extractPossibleStdvers(lines); const compiler = makeCompiler();
const parser = new ICCParser(compiler);
const stdvers = parser.extractPossibleStdvers(lines);
expect(stdvers).toEqual([ expect(stdvers).toEqual([
{ {
name: 'c99: conforms to ISO/IEC 9899:1999 standard for C programs', name: 'c99: conforms to ISO/IEC 9899:1999 standard for C programs',
@@ -255,7 +283,9 @@ describe('TableGen argument parser', () => {
' --gen-x86-mnemonic-tables - Generate X86...', ' --gen-x86-mnemonic-tables - Generate X86...',
' --no-warn-on-unused-template-args - Disable...', ' --no-warn-on-unused-template-args - Disable...',
]; ];
const actions = TableGenParser.extractPossibleActions(lines); const compiler = makeCompiler();
const parser = new TableGenParser(compiler);
const actions = parser.extractPossibleActions(lines);
expect(actions).toEqual([ expect(actions).toEqual([
{name: 'gen-attrs: Generate attributes', value: '--gen-attrs'}, {name: 'gen-attrs: Generate attributes', value: '--gen-attrs'},
{name: 'print-detailed-records: Print full details...', value: '--print-detailed-records'}, {name: 'print-detailed-records: Print full details...', value: '--print-detailed-records'},
@@ -278,7 +308,8 @@ describe('Rust editions parser', () => {
' stable edition is 2024.', ' stable edition is 2024.',
]; ];
const compiler = makeCompiler(lines.join('\n')); const compiler = makeCompiler(lines.join('\n'));
const editions = await RustParser.getPossibleEditions(compiler); const parser = new RustParser(compiler);
const editions = await parser.getPossibleEditions();
expect(editions).toEqual(['2015', '2018', '2021', '2024', 'future']); expect(editions).toEqual(['2015', '2018', '2021', '2024', 'future']);
}); });
@@ -294,7 +325,8 @@ describe('Rust editions parser', () => {
' compiling code.', ' compiling code.',
]; ];
const compiler = makeCompiler(lines.join('\n')); const compiler = makeCompiler(lines.join('\n'));
const editions = await RustParser.getPossibleEditions(compiler); const parser = new RustParser(compiler);
const editions = await parser.getPossibleEditions();
expect(editions).toEqual(['2015', '2018']); expect(editions).toEqual(['2015', '2018']);
}); });
}); });
@@ -312,9 +344,10 @@ describe('Rust help message parser', () => {
' -W, --warn OPT Set lint warnings', ' -W, --warn OPT Set lint warnings',
]; ];
const compiler = makeCompiler(lines.join('\n')); const compiler = makeCompiler(lines.join('\n'));
await RustParser.parse(compiler); const parser = new RustParser(compiler);
await parser.parse();
expect(compiler.compiler.supportsTarget).toBe(true); expect(compiler.compiler.supportsTarget).toBe(true);
await expect(RustParser.getOptions(compiler, '--help')).resolves.toEqual({ await expect(parser.getOptions('--help')).resolves.toEqual({
'-l [KIND[:MODIFIERS]=]NAME[:RENAME]': { '-l [KIND[:MODIFIERS]=]NAME[:RENAME]': {
description: description:
'Link the generated crate(s) to the specified native library NAME. The optional KIND can be one of', 'Link the generated crate(s) to the specified native library NAME. The optional KIND can be one of',
@@ -344,9 +377,10 @@ describe('Rust help message parser', () => {
' -W, --warn <LINT> Set lint warnings', ' -W, --warn <LINT> Set lint warnings',
]; ];
const compiler = makeCompiler(lines.join('\n')); const compiler = makeCompiler(lines.join('\n'));
await RustParser.parse(compiler); const parser = new RustParser(compiler);
await parser.parse();
expect(compiler.compiler.supportsTarget).toBe(true); expect(compiler.compiler.supportsTarget).toBe(true);
await expect(RustParser.getOptions(compiler, '--help')).resolves.toEqual({ await expect(parser.getOptions('--help')).resolves.toEqual({
'-l [<KIND>[:<MODIFIERS>]=]<NAME>[:<RENAME>]': { '-l [<KIND>[:<MODIFIERS>]=]<NAME>[:<RENAME>]': {
description: description:
'Link the generated crate(s) to the specified native library NAME. The optional KIND can be one of', 'Link the generated crate(s) to the specified native library NAME. The optional KIND can be one of',

View File

@@ -52,7 +52,7 @@ class DummyCompiler extends BaseCompiler {
} as unknown as CompilationEnvironment; } as unknown as CompilationEnvironment;
// using c++ as the compiler needs at least one language // using c++ as the compiler needs at least one language
const compiler = makeFakeCompilerInfo({lang: 'c++'}); const compiler = makeFakeCompilerInfo({lang: 'c++', exe: 'gcc'});
super(compiler, env); super(compiler, env);
} }

View File

@@ -44,7 +44,7 @@ describe('Pascal', () => {
beforeAll(() => { beforeAll(() => {
const ce = makeCompilationEnvironment({languages}); const ce = makeCompilationEnvironment({languages});
const info = { const info = {
exe: null, exe: 'pascal-compiler',
remote: true, remote: true,
lang: languages.pascal.id, lang: languages.pascal.id,
}; };
@@ -498,7 +498,7 @@ describe('Pascal', () => {
beforeAll(() => { beforeAll(() => {
const ce = makeCompilationEnvironment({languages}); const ce = makeCompilationEnvironment({languages});
const info = { const info = {
exe: null, exe: 'pascal.exe',
remote: true, remote: true,
lang: languages.pascal.id, lang: languages.pascal.id,
}; };