Skip to content

Commit

Permalink
Move url expansion to files (#4602)
Browse files Browse the repository at this point in the history
  • Loading branch information
partouf committed Feb 2, 2023
1 parent c022ca8 commit a15c725
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 55 deletions.
6 changes: 1 addition & 5 deletions lib/base-compiler.ts
Expand Up @@ -2429,11 +2429,7 @@ export class BaseCompiler implements ICompiler {
.pipe(new compilerOptInfo.LLVMOptTransformer());

for await (const opt of optStream) {
if (
opt.DebugLoc &&
opt.DebugLoc.File &&
(opt.DebugLoc.File === '<stdin>' || opt.DebugLoc.File.includes(this.compileFilename))
) {
if (opt.DebugLoc && opt.DebugLoc.File && opt.DebugLoc.File.includes(this.compileFilename)) {
output.push(opt);
}
}
Expand Down
34 changes: 20 additions & 14 deletions static/compiler-service.ts
Expand Up @@ -35,8 +35,9 @@ import {ResultLine} from '../types/resultline/resultline.interfaces';
import jqXHR = JQuery.jqXHR;
import ErrorTextStatus = JQuery.Ajax.ErrorTextStatus;
import {CompilerInfo} from '../types/compiler.interfaces';
import {CompilationResult} from '../types/compilation/compilation.interfaces';
import {CompilationResult, FiledataPair} from '../types/compilation/compilation.interfaces';
import {CompilationStatus} from './compiler-service.interfaces';
import {IncludeDownloads, SourceAndFiles} from './download-service';

const ASCII_COLORS_RE = new RegExp(/\x1B\[[\d;]*m(.\[K)?/g);

Expand Down Expand Up @@ -310,27 +311,32 @@ export class CompilerService {
});
}

public async expand(source: string) {
private getFilenameFromUrl(url: string): string {
const jsurl = new URL(url);
const urlpath = jsurl.pathname;
return urlpath.substring(urlpath.lastIndexOf('/') + 1);
}

public async expandToFiles(source: string): Promise<SourceAndFiles> {
const includes = new IncludeDownloads();

const includeFind = /^\s*#\s*include\s*["<](https?:\/\/[^">]+)[">]/;
const lines = source.split('\n');
const promises: Promise<null>[] = [];
for (const idx in lines) {
const lineNumZeroBased = Number(idx);
const line = lines[idx];
const match = line.match(includeFind);
if (match) {
promises.push(
new Promise(resolve => {
const req = $.get(match[1], data => {
lines[idx] = `#line 1 "${match[1]}"\n${data}\n\n#line ${lineNumZeroBased + 1} "<stdin>"\n`;
resolve(null);
});
req.fail(() => resolve(null));
})
);
const download = includes.include(match[1]);
lines[idx] = `#include "${download.filename}"`;
}
}
return Promise.all(promises).then(() => lines.join('\n'));

const files: FiledataPair[] = await includes.allDownloadsAsFileDataPairs();

return {
source: lines.join('\n'),
files: files,
};
}

public static getSelectizerOrder() {
Expand Down
106 changes: 106 additions & 0 deletions static/download-service.ts
@@ -0,0 +1,106 @@
// Copyright (c) 2023, 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 {FiledataPair} from '../types/compilation/compilation.interfaces';

export type SourceAndFiles = {
files: FiledataPair[];
source: string;
};

export type FileToDownload = {
url: string;
filename: string;
contents?: string;
downloadFailed?: boolean;
};

export class IncludeDownloads {
private toDownload: FileToDownload[] = [];
private downloadPromises: Promise<FileToDownload>[] = [];

private async doDownload(download): Promise<FileToDownload> {
try {
const response = await fetch(download.url);
if (response.status >= 400) {
download.downloadFailed = true;
} else {
download.contents = await response.text();
}
} catch {
// exceptions happens on for example dns errors
download.downloadFailed = true;
}
return download;
}

private async startDownload(download) {
this.downloadPromises.push(this.doDownload(download));
}

private getFilenameFromUrl(url: string): string {
const jsurl = new URL(url);
const urlpath = jsurl.pathname;
return jsurl.host + urlpath;
}

include(url: string): FileToDownload {
let found = this.toDownload.find(prev => prev.url === url);
if (!found) {
try {
const filename = this.getFilenameFromUrl(url);
found = {
url: url,
filename: filename,
};
this.toDownload.push(found);
this.startDownload(found);
} catch (err: any) {
return {
url: 'Unknown url',
filename: err.message,
downloadFailed: true,
};
}
}
return found;
}

async allDownloads(): Promise<FileToDownload[]> {
return Promise.all(this.downloadPromises);
}

async allDownloadsAsFileDataPairs(): Promise<FiledataPair[]> {
const downloads = await Promise.all(this.downloadPromises);

return downloads
.filter(file => !file.downloadFailed)
.map(file => {
return {
filename: file.filename,
contents: file.contents || '',
};
});
}
}
6 changes: 1 addition & 5 deletions static/multifile-service.ts
Expand Up @@ -27,6 +27,7 @@ import path from 'path-browserify';
import JSZip from 'jszip';
import {Hub} from './hub';
import {unwrap} from './assert';
import {FiledataPair} from '../types/compilation/compilation.interfaces';
const languages = require('./options').options.languages;

export interface MultifileFile {
Expand All @@ -40,11 +41,6 @@ export interface MultifileFile {
langId: string;
}

export interface FiledataPair {
filename: string;
contents: string;
}

export interface MultifileServiceState {
isCMakeProject: boolean;
compilerLanguageId: string;
Expand Down
22 changes: 13 additions & 9 deletions static/panes/compiler.ts
Expand Up @@ -49,15 +49,14 @@ import {Hub} from '../hub';
import {Container} from 'golden-layout';
import {CompilerState} from './compiler.interfaces';
import {ComponentConfig, ToolViewState} from '../components.interfaces';
import {FiledataPair} from '../multifile-service';
import {LanguageLibs} from '../options.interfaces';
import {GccDumpFiltersState, GccDumpViewSelectedPass} from './gccdump-view.interfaces';
import {AssemblyInstructionInfo} from '../../lib/asm-docs/base';
import {PPOptions} from './pp-view.interfaces';
import {CompilationStatus} from '../compiler-service.interfaces';
import {WidgetState} from '../widgets/libs-widget.interfaces';
import {LLVMOptPipelineBackendOptions} from '../../types/compilation/llvm-opt-pipeline-output.interfaces';
import {CompilationResult} from '../../types/compilation/compilation.interfaces';
import {CompilationResult, FiledataPair} from '../../types/compilation/compilation.interfaces';
import {ResultLine} from '../../types/resultline/resultline.interfaces';
import * as utils from '../utils';
import * as Sentry from '@sentry/browser';
Expand All @@ -67,6 +66,7 @@ import {Tool, ArtifactType} from '../../types/tool.interfaces';
import {assert, unwrap, unwrapString} from '../assert';
import {CompilerOutputOptions} from '../../types/features/filters.interfaces';
import {AssemblyDocumentationInstructionSet} from '../../types/features/assembly-documentation.interfaces';
import {SourceAndFiles} from '../download-service';

const toolIcons = require.context('../../views/resources/logos', false, /\.(png|svg)$/);

Expand Down Expand Up @@ -1266,19 +1266,23 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co

const fetches: Promise<void>[] = [];
fetches.push(
this.compilerService.expand(request.source).then(contents => {
request.source = contents;
this.compilerService.expandToFiles(request.source).then((sourceAndFiles: SourceAndFiles) => {
request.source = sourceAndFiles.source;
request.files.push(...sourceAndFiles.files);
})
);

const moreFiles: FiledataPair[] = [];
for (let i = 0; i < request.files.length; i++) {
const file = request.files[i];
fetches.push(
this.compilerService.expand(file.contents).then(contents => {
file.contents = contents;
this.compilerService.expandToFiles(file.contents).then((sourceAndFiles: SourceAndFiles) => {
file.contents = sourceAndFiles.source;
moreFiles.push(...sourceAndFiles.files);
})
);
}
request.files.push(...moreFiles);

Promise.all(fetches).then(() => {
const treeState = tree.currentState();
Expand All @@ -1302,13 +1306,13 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
}

compileFromEditorSource(options: CompileRequestOptions, bypassCache: boolean) {
this.compilerService.expand(this.source).then(expanded => {
this.compilerService.expandToFiles(this.source).then((sourceAndFiles: SourceAndFiles) => {
const request: CompileRequest = {
source: expanded || '',
source: sourceAndFiles.source || '',
compiler: this.compiler ? this.compiler.id : '',
options: options,
lang: this.currentLangId,
files: [],
files: sourceAndFiles.files,
bypassCache: false,
};
if (bypassCache) request.bypassCache = true;
Expand Down
26 changes: 13 additions & 13 deletions static/panes/conformance-view.ts
Expand Up @@ -42,6 +42,7 @@ import {Library, LibraryVersion} from '../options.interfaces';
import {CompilerInfo} from '../../types/compiler.interfaces';
import {CompilationResult} from '../../types/compilation/compilation.interfaces';
import {Lib} from '../widgets/libs-widget.interfaces';
import {SourceAndFiles} from '../download-service';

type ConformanceStatus = {
allowCompile: boolean;
Expand Down Expand Up @@ -74,7 +75,7 @@ export class Conformance extends Pane<ConformanceViewState> {
private source: string;
private sourceNeedsExpanding: boolean;
private compilerPickers: CompilerEntry[];
private expandedSource: string | null;
private expandedSourceAndFiles: SourceAndFiles | null;
private currentLibs: Lib[];
private status: ConformanceStatus;
private readonly stateByLang: Record<string, ConformanceViewState>;
Expand All @@ -92,7 +93,7 @@ export class Conformance extends Pane<ConformanceViewState> {
this.langId = state.langId || _.keys(options.languages)[0];
this.source = state.source ?? '';
this.sourceNeedsExpanding = true;
this.expandedSource = null;
this.expandedSourceAndFiles = null;

this.status = {
allowCompile: false,
Expand Down Expand Up @@ -352,15 +353,14 @@ export class Conformance extends Pane<ConformanceViewState> {
this.saveState();
}

expandSource(): Promise<string> {
if (this.sourceNeedsExpanding || !this.expandedSource) {
return this.compilerService.expand(this.source).then(expandedSource => {
this.expandedSource = expandedSource;
this.sourceNeedsExpanding = false;
return expandedSource;
});
async expandToFiles(): Promise<SourceAndFiles> {
if (this.sourceNeedsExpanding || !this.expandedSourceAndFiles) {
const expanded = await this.compilerService.expandToFiles(this.source);
this.expandedSourceAndFiles = expanded;
this.sourceNeedsExpanding = false;
return expanded;
}
return Promise.resolve(this.expandedSource);
return Promise.resolve(this.expandedSourceAndFiles);
}

onEditorChange(editorId: number, newSource: string, langId: string): void {
Expand Down Expand Up @@ -421,9 +421,9 @@ export class Conformance extends Pane<ConformanceViewState> {
// Hide previous status icons
this.handleStatusIcon(compilerEntry.statusIcon, {code: 4});

this.expandSource().then(expandedSource => {
this.expandToFiles().then(expanded => {
const request = {
source: expandedSource,
source: expanded.source,
compiler: compilerId,
options: {
userArguments: compilerEntry.optionsField.val() || '',
Expand All @@ -432,7 +432,7 @@ export class Conformance extends Pane<ConformanceViewState> {
libraries: [] as CompileChildLibraries[],
},
lang: this.langId,
files: [],
files: expanded.files,
};

this.currentLibs.forEach(item => {
Expand Down
22 changes: 13 additions & 9 deletions static/panes/executor.ts
Expand Up @@ -47,12 +47,12 @@ import {Language} from '../../types/languages.interfaces';
import {LanguageLibs} from '../options.interfaces';
import {LLVMOptPipelineBackendOptions} from '../../types/compilation/llvm-opt-pipeline-output.interfaces';
import {PPOptions} from './pp-view.interfaces';
import {FiledataPair} from '../multifile-service';
import {CompilationResult} from '../../types/compilation/compilation.interfaces';
import {FiledataPair, CompilationResult} from '../../types/compilation/compilation.interfaces';
import {ResultLine} from '../../types/resultline/resultline.interfaces';
import {CompilationStatus as CompilerServiceCompilationStatus} from '../compiler-service.interfaces';
import {CompilerPicker} from '../widgets/compiler-picker';
import {GccDumpViewSelectedPass} from './gccdump-view.interfaces';
import {SourceAndFiles} from '../download-service';

const languages = options.languages;

Expand Down Expand Up @@ -363,13 +363,13 @@ export class Executor extends Pane<ExecutorState> {
});
return;
}
this.hub.compilerService.expand(this.source).then(expanded => {
this.hub.compilerService.expandToFiles(this.source).then((sourceAndFiles: SourceAndFiles) => {
const request: CompilationRequest = {
source: expanded || '',
source: sourceAndFiles.source || '',
compiler: this.compiler ? this.compiler.id : '',
options: options,
lang: this.currentLangId,
files: [],
files: sourceAndFiles.files,
};
if (bypassCache) request.bypassCache = true;
if (!this.compiler) {
Expand Down Expand Up @@ -398,19 +398,23 @@ export class Executor extends Pane<ExecutorState> {

const fetches: Promise<void>[] = [];
fetches.push(
this.hub.compilerService.expand(request.source).then(contents => {
request.source = contents;
this.hub.compilerService.expandToFiles(request.source).then((sourceAndFiles: SourceAndFiles) => {
request.source = sourceAndFiles.source;
request.files.push(...sourceAndFiles.files);
})
);

const moreFiles: FiledataPair[] = [];
for (let i = 0; i < request.files.length; i++) {
const file = request.files[i];
fetches.push(
this.hub.compilerService.expand(file.contents).then(contents => {
file.contents = contents;
this.hub.compilerService.expandToFiles(file.contents).then((sourceAndFiles: SourceAndFiles) => {
file.contents = sourceAndFiles.source;
moreFiles.push(...sourceAndFiles.files);
})
);
}
request.files.push(...moreFiles);

Promise.all(fetches).then(() => {
const treeState = tree.currentState();
Expand Down

0 comments on commit a15c725

Please sign in to comment.