mirror of
https://github.com/compiler-explorer/compiler-explorer.git
synced 2025-12-27 10:33:59 -05:00
467 lines
14 KiB
TypeScript
467 lines
14 KiB
TypeScript
// 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 {LanguageKey} from '../types/languages.interfaces.js';
|
|
|
|
export class ClientStateCompilerOptions {
|
|
binary = false;
|
|
binaryObject = false;
|
|
commentOnly = true;
|
|
demangle = true;
|
|
directives = true;
|
|
execute = false;
|
|
intel = true;
|
|
labels = true;
|
|
libraryCode = false;
|
|
trim = false;
|
|
debugCalls = false;
|
|
|
|
constructor(jsondata?: any) {
|
|
if (jsondata) this.fromJsonData(jsondata);
|
|
}
|
|
|
|
fromJsonData(jsondata: any) {
|
|
if (jsondata.binary !== undefined) this.binary = jsondata.binary;
|
|
if (jsondata.binaryObject !== undefined) this.binaryObject = jsondata.binaryObject;
|
|
if (jsondata.commentOnly !== undefined) this.commentOnly = jsondata.commentOnly;
|
|
if (jsondata.demangle !== undefined) this.demangle = jsondata.demangle;
|
|
if (jsondata.directives !== undefined) this.directives = jsondata.directives;
|
|
if (jsondata.execute !== undefined) this.execute = jsondata.execute;
|
|
if (jsondata.intel !== undefined) this.intel = jsondata.intel;
|
|
if (jsondata.labels !== undefined) this.labels = jsondata.labels;
|
|
if (jsondata.libraryCode !== undefined) this.libraryCode = jsondata.libraryCode;
|
|
if (jsondata.trim !== undefined) this.trim = jsondata.trim;
|
|
if (jsondata.debugCalls !== undefined) this.debugCalls = jsondata.debugCalls;
|
|
}
|
|
}
|
|
|
|
export class ClientStateCompiler {
|
|
_internalid: number | undefined = undefined;
|
|
id: string | number | undefined = undefined;
|
|
compiler?: string;
|
|
options = '';
|
|
filters: ClientStateCompilerOptions;
|
|
libs: any[] = [];
|
|
specialoutputs: string[] = [];
|
|
tools: any[] = [];
|
|
overrides: any[] = [];
|
|
source?: number;
|
|
tree?: number;
|
|
|
|
constructor(jsondata?: any) {
|
|
if (jsondata) {
|
|
this.filters = undefined as any as ClientStateCompilerOptions;
|
|
this.fromJsonData(jsondata);
|
|
} else {
|
|
this.filters = new ClientStateCompilerOptions();
|
|
}
|
|
}
|
|
|
|
fromJsonData(jsondata: any) {
|
|
if (jsondata._internalid !== undefined) {
|
|
this._internalid = jsondata._internalid;
|
|
}
|
|
|
|
if (jsondata.id !== undefined) {
|
|
this.id = jsondata.id;
|
|
} else if (jsondata.compilerId === undefined) {
|
|
this.id = '';
|
|
} else {
|
|
this.id = jsondata.compilerId;
|
|
}
|
|
|
|
this.options = jsondata.options;
|
|
this.filters = new ClientStateCompilerOptions(jsondata.filters);
|
|
if (jsondata.libs === undefined) {
|
|
this.libs = [];
|
|
} else {
|
|
this.libs = jsondata.libs;
|
|
}
|
|
if (jsondata.specialoutputs === undefined) {
|
|
this.specialoutputs = [];
|
|
} else {
|
|
this.specialoutputs = jsondata.specialoutputs;
|
|
}
|
|
|
|
if (jsondata.tools === undefined) {
|
|
this.tools = [];
|
|
} else {
|
|
this.tools = jsondata.tools;
|
|
}
|
|
|
|
if (jsondata.overrides === undefined) {
|
|
this.overrides = [];
|
|
} else {
|
|
this.overrides = jsondata.overrides;
|
|
}
|
|
}
|
|
}
|
|
|
|
export class ClientStateExecutor {
|
|
compilerVisible = false;
|
|
compilerOutputVisible = false;
|
|
arguments = '';
|
|
argumentsVisible = false;
|
|
stdin = '';
|
|
stdinVisible = false;
|
|
compiler: ClientStateCompiler;
|
|
wrap?: boolean;
|
|
runtimeTools: any[] = [];
|
|
overrides: any[] = [];
|
|
|
|
constructor(jsondata?: any) {
|
|
if (jsondata) {
|
|
// hack so TS doesn't think this.compiler is accessed before assignment below
|
|
this.compiler = undefined as any as ClientStateCompiler;
|
|
this.fromJsonData(jsondata);
|
|
} else {
|
|
this.compiler = new ClientStateCompiler();
|
|
this.wrap = false;
|
|
}
|
|
|
|
delete this.compiler._internalid;
|
|
}
|
|
|
|
fromJsonData(jsondata: any) {
|
|
if (jsondata.compilerVisible !== undefined) this.compilerVisible = jsondata.compilerVisible;
|
|
if (jsondata.compilerOutputVisible !== undefined) this.compilerOutputVisible = jsondata.compilerOutputVisible;
|
|
if (jsondata.arguments !== undefined) this.arguments = jsondata.arguments;
|
|
if (jsondata.argumentsVisible !== undefined) this.argumentsVisible = jsondata.argumentsVisible;
|
|
if (jsondata.stdin !== undefined) this.stdin = jsondata.stdin;
|
|
if (jsondata.stdinVisible !== undefined) this.stdinVisible = jsondata.stdinVisible;
|
|
if (jsondata.wrap !== undefined) this.wrap = jsondata.wrap;
|
|
|
|
if (typeof this.arguments !== 'string') {
|
|
throw new TypeError('unexpected: executor.arguments are supposed to be a string');
|
|
}
|
|
|
|
if (jsondata.runtimeTools === undefined) {
|
|
this.runtimeTools = [];
|
|
} else {
|
|
this.runtimeTools = jsondata.runtimeTools;
|
|
}
|
|
|
|
this.compiler = new ClientStateCompiler(jsondata.compiler);
|
|
}
|
|
}
|
|
|
|
export class ClientStateConformanceView {
|
|
libs: any[] = [];
|
|
compilers: ClientStateCompiler[] = [];
|
|
|
|
constructor(jsondata?: any) {
|
|
if (jsondata) this.fromJsonData(jsondata);
|
|
}
|
|
|
|
fromJsonData(jsondata: any) {
|
|
this.libs = jsondata.libs;
|
|
if (jsondata.compilers) {
|
|
for (const compilerdata of jsondata.compilers) {
|
|
const compiler = new ClientStateCompiler(compilerdata);
|
|
delete compiler._internalid;
|
|
this.compilers.push(compiler);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
export class MultifileFile {
|
|
id: any = undefined;
|
|
fileId = 0;
|
|
isIncluded = false;
|
|
isOpen = false;
|
|
isMainSource = false;
|
|
filename: string | undefined = '';
|
|
content = '';
|
|
editorId = -1;
|
|
langId = 'c++';
|
|
|
|
constructor(jsondata?: any) {
|
|
if (jsondata) this.fromJsonData(jsondata);
|
|
}
|
|
|
|
fromJsonData(jsondata: any) {
|
|
this.fileId = jsondata.fileId;
|
|
this.isIncluded = jsondata.isIncluded;
|
|
this.isOpen = jsondata.isOpen;
|
|
this.isMainSource = jsondata.isMainSource;
|
|
this.filename = jsondata.filename;
|
|
this.content = jsondata.content;
|
|
this.editorId = jsondata.editorId;
|
|
this.langId = jsondata.langId;
|
|
}
|
|
}
|
|
|
|
export class ClientStateTree {
|
|
id = 1;
|
|
cmakeArgs = '';
|
|
customOutputFilename = '';
|
|
isCMakeProject = false;
|
|
compilerLanguageId: LanguageKey = 'c++';
|
|
files: MultifileFile[] = [];
|
|
newFileId = 1;
|
|
compilers: ClientStateCompiler[] = [];
|
|
executors: ClientStateExecutor[] = [];
|
|
|
|
constructor(jsondata?: any) {
|
|
if (jsondata) this.fromJsonData(jsondata);
|
|
}
|
|
|
|
fromJsonData(jsondata: any) {
|
|
this.id = jsondata.id;
|
|
this.cmakeArgs = jsondata.cmakeArgs;
|
|
this.customOutputFilename = jsondata.customOutputFilename;
|
|
this.isCMakeProject = jsondata.isCMakeProject;
|
|
this.compilerLanguageId = jsondata.compilerLanguageId;
|
|
|
|
let requiresFix = jsondata.newFileId === undefined;
|
|
for (const file of jsondata.files) {
|
|
const newFile = new MultifileFile(file);
|
|
this.files.push(newFile);
|
|
if (this.newFileId <= newFile.id) {
|
|
requiresFix = true;
|
|
}
|
|
}
|
|
|
|
if (requiresFix) {
|
|
this.newFileId = 1;
|
|
for (const file of this.files) {
|
|
if (file.id > this.newFileId) {
|
|
this.newFileId = file.id + 1;
|
|
}
|
|
}
|
|
} else {
|
|
this.newFileId = jsondata.newFileId;
|
|
}
|
|
|
|
if (jsondata.compilers !== undefined) {
|
|
for (const compilerdata of jsondata.compilers) {
|
|
const compiler = new ClientStateCompiler(compilerdata);
|
|
if (compiler.id) {
|
|
this.compilers.push(compiler);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (jsondata.executors !== undefined) {
|
|
for (const executor of jsondata.executors) {
|
|
this.executors.push(new ClientStateExecutor(executor));
|
|
}
|
|
}
|
|
}
|
|
|
|
findOrCreateCompiler(id: number) {
|
|
let foundCompiler;
|
|
for (const compiler of this.compilers) {
|
|
if (compiler._internalid === id) {
|
|
foundCompiler = compiler;
|
|
}
|
|
}
|
|
|
|
if (!foundCompiler) {
|
|
foundCompiler = new ClientStateCompiler();
|
|
foundCompiler._internalid = id;
|
|
this.compilers.push(foundCompiler);
|
|
}
|
|
|
|
return foundCompiler;
|
|
}
|
|
}
|
|
|
|
export class ClientStateSession {
|
|
id: number | null = null;
|
|
language = '';
|
|
source = '';
|
|
// Should default to 'null' but still afraid to break existing links
|
|
conformanceview: ClientStateConformanceView | false = false;
|
|
compilers: ClientStateCompiler[] = [];
|
|
executors: ClientStateExecutor[] = [];
|
|
filename = undefined;
|
|
|
|
constructor(jsondata?: any) {
|
|
if (jsondata) this.fromJsonData(jsondata);
|
|
}
|
|
|
|
fromJsonData(jsondata: any) {
|
|
if (jsondata.id !== undefined) this.id = jsondata.id;
|
|
this.language = jsondata.language;
|
|
this.source = jsondata.source;
|
|
if (jsondata.conformanceview !== undefined) {
|
|
if (jsondata.conformanceview) {
|
|
this.conformanceview = new ClientStateConformanceView(jsondata.conformanceview);
|
|
} else {
|
|
this.conformanceview = false;
|
|
}
|
|
}
|
|
|
|
for (const compilerdata of jsondata.compilers) {
|
|
const compiler = new ClientStateCompiler(compilerdata);
|
|
if (compiler.id) {
|
|
this.compilers.push(compiler);
|
|
}
|
|
}
|
|
|
|
if (jsondata.executors !== undefined) {
|
|
for (const executor of jsondata.executors) {
|
|
this.executors.push(new ClientStateExecutor(executor));
|
|
}
|
|
}
|
|
|
|
if (jsondata.filename !== undefined) {
|
|
this.filename = jsondata.filename;
|
|
}
|
|
}
|
|
|
|
findOrCreateCompiler(id: number) {
|
|
let foundCompiler: ClientStateCompiler | undefined;
|
|
for (const compiler of this.compilers) {
|
|
if (compiler._internalid === id) {
|
|
foundCompiler = compiler;
|
|
}
|
|
}
|
|
|
|
if (!foundCompiler) {
|
|
foundCompiler = new ClientStateCompiler();
|
|
foundCompiler._internalid = id;
|
|
this.compilers.push(foundCompiler);
|
|
}
|
|
|
|
return foundCompiler;
|
|
}
|
|
|
|
countNumberOfSpecialOutputsAndTools() {
|
|
let count = 0;
|
|
|
|
if (this.conformanceview) count++;
|
|
|
|
for (const compiler of this.compilers) {
|
|
count += compiler.specialoutputs.length;
|
|
if (compiler.tools) count += compiler.tools.length;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
}
|
|
|
|
export class ClientState {
|
|
sessions: ClientStateSession[] = [];
|
|
trees: ClientStateTree[] = [];
|
|
|
|
constructor(jsondata?: any) {
|
|
if (jsondata) this.fromJsonData(jsondata);
|
|
}
|
|
|
|
fromJsonData(jsondata: any) {
|
|
for (const sessiondata of jsondata.sessions) {
|
|
const session = new ClientStateSession(sessiondata);
|
|
this.numberCompilersIfNeeded(session);
|
|
this.sessions.push(session);
|
|
}
|
|
|
|
if (jsondata.trees) {
|
|
for (const treedata of jsondata.trees) {
|
|
this.trees.push(new ClientStateTree(treedata));
|
|
}
|
|
}
|
|
}
|
|
|
|
getNextCompilerId() {
|
|
let nextId = 1;
|
|
for (const session of this.sessions) {
|
|
for (const compiler of session.compilers) {
|
|
if (compiler._internalid && compiler._internalid >= nextId) {
|
|
nextId = compiler._internalid + 1;
|
|
}
|
|
}
|
|
}
|
|
return nextId;
|
|
}
|
|
|
|
numberCompilersIfNeeded(session: ClientStateSession, startAt?: number) {
|
|
let id = startAt;
|
|
let someIdsNeedNumbering = false;
|
|
|
|
for (const compiler of session.compilers) {
|
|
if (compiler._internalid && id && compiler._internalid >= id) {
|
|
id = compiler._internalid + 1;
|
|
} else {
|
|
someIdsNeedNumbering = true;
|
|
}
|
|
}
|
|
|
|
if (someIdsNeedNumbering) {
|
|
for (const compiler of session.compilers) {
|
|
if (!compiler._internalid) {
|
|
compiler._internalid = id;
|
|
if (id) id++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
findSessionById(id: number) {
|
|
for (const session of this.sessions) {
|
|
if (session.id === id) {
|
|
return session;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
findTreeById(id: number) {
|
|
for (let idxTree = 0; idxTree < this.trees.length; idxTree++) {
|
|
const tree = this.trees[idxTree];
|
|
|
|
if (tree.id === id) {
|
|
return tree;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
findOrCreateSession(id: number) {
|
|
let session = this.findSessionById(id);
|
|
if (session) return session;
|
|
|
|
session = new ClientStateSession();
|
|
session.id = id;
|
|
this.sessions.push(session);
|
|
|
|
return session;
|
|
}
|
|
|
|
findOrCreateTree(id: number) {
|
|
let tree = this.findTreeById(id);
|
|
if (tree) return tree;
|
|
|
|
tree = new ClientStateTree();
|
|
tree.id = id;
|
|
this.trees.push(tree);
|
|
|
|
return tree;
|
|
}
|
|
}
|