From 7cd713d9557592ff51b7ccf52dc313bdc0a66104 Mon Sep 17 00:00:00 2001 From: filip mertens Date: Wed, 13 Jul 2022 20:18:28 +0200 Subject: [PATCH] retrigger compiler --- .../parser/services/code-parser-compiler.ts | 11 ++- .../src/compiler/compiler-worker.ts | 1 + libs/remix-solidity/src/compiler/compiler.ts | 89 ++++++++++--------- libs/remix-solidity/src/compiler/types.ts | 8 ++ 4 files changed, 61 insertions(+), 48 deletions(-) diff --git a/apps/remix-ide/src/app/plugins/parser/services/code-parser-compiler.ts b/apps/remix-ide/src/app/plugins/parser/services/code-parser-compiler.ts index 48712acc18..20b944eb0e 100644 --- a/apps/remix-ide/src/app/plugins/parser/services/code-parser-compiler.ts +++ b/apps/remix-ide/src/app/plugins/parser/services/code-parser-compiler.ts @@ -6,6 +6,7 @@ import { CompilationError, CompilationResult, CompilationSource } from '@remix-p import { CodeParser } from "../code-parser"; import { fileDecoration, fileDecorationType } from '@remix-ui/file-decorators' import { sourceMappingDecoder } from '@remix-project/remix-debug' +import { CompilerRetriggerMode } from '@remix-project/remix-solidity-ts'; export default class CodeParserCompiler { plugin: CodeParser @@ -56,7 +57,6 @@ export default class CodeParserCompiler { } else { await this.plugin.call('editor', 'clearErrorMarkers', result.getSourceCode().sources) await this.clearDecorators(result.getSourceCode().sources) - } @@ -71,16 +71,15 @@ export default class CodeParserCompiler { nodesPerFile: {}, } - + this.plugin._buildIndex(data, source) if (this.gastEstimateTimeOut) { window.clearTimeout(this.gastEstimateTimeOut) } - this.gastEstimateTimeOut = window.setTimeout(async () => { - await this.plugin.gasService.showGasEstimates() - }, 1000) + await this.plugin.gasService.showGasEstimates() + console.log("INDEX", this.plugin.nodeIndex) this.plugin.emit('astFinished') @@ -107,7 +106,7 @@ export default class CodeParserCompiler { this.compiler.set('language', state.language) this.compiler.set('runs', state.runs) this.compiler.set('useFileConfiguration', true) - + this.compiler.set('compilerRetriggerMode', CompilerRetriggerMode.retrigger) const configFileContent = { "language": "Solidity", "settings": { diff --git a/libs/remix-solidity/src/compiler/compiler-worker.ts b/libs/remix-solidity/src/compiler/compiler-worker.ts index 662a03ec06..7fdeef2791 100644 --- a/libs/remix-solidity/src/compiler/compiler-worker.ts +++ b/libs/remix-solidity/src/compiler/compiler-worker.ts @@ -44,6 +44,7 @@ export default function (self) { // eslint-disable-line @typescript-eslint/expli self.postMessage({ cmd: 'compiled', job: data.job, + timestamp: data.timestamp, data: compileJSON(data.input), input: data.input, missingInputs: missingInputs diff --git a/libs/remix-solidity/src/compiler/compiler.ts b/libs/remix-solidity/src/compiler/compiler.ts index f728748a9e..70dd550eae 100644 --- a/libs/remix-solidity/src/compiler/compiler.ts +++ b/libs/remix-solidity/src/compiler/compiler.ts @@ -9,7 +9,7 @@ import { Source, SourceWithTarget, MessageFromWorker, CompilerState, CompilationResult, visitContractsCallbackParam, visitContractsCallbackInterface, CompilationError, gatherImportsCallbackInterface, - isFunctionDescription + isFunctionDescription, CompilerRetriggerMode } from './types' /* @@ -19,7 +19,7 @@ export class Compiler { event state: CompilerState - constructor (public handleImportCall?: (fileurl: string, cb) => void) { + constructor(public handleImportCall?: (fileurl: string, cb) => void) { this.event = new EventManager() this.state = { compileJSON: null, @@ -33,6 +33,7 @@ export class Compiler { target: null, useFileConfiguration: false, configFileContent: '', + compilerRetriggerMode: CompilerRetriggerMode.none, lastCompilationResult: { data: null, source: null @@ -47,7 +48,6 @@ export class Compiler { }) this.event.register('compilationStarted', () => { - this.state.compilationStartTime = new Date().getTime() }) } @@ -57,7 +57,7 @@ export class Compiler { * @param value value of key in CompilerState */ - set (key: K, value: CompilerState[K]): void { + set(key: K, value: CompilerState[K]): void { this.state[key] = value if (key === 'runs') this.state['runs'] = parseInt(value) } @@ -68,7 +68,7 @@ export class Compiler { * @param missingInputs missing import file path list */ - internalCompile (files: Source, missingInputs?: string[]): void { + internalCompile(files: Source, missingInputs?: string[]): void { this.gatherImports(files, missingInputs, (error, input) => { if (error) { this.state.lastCompilationResult = null @@ -83,8 +83,9 @@ export class Compiler { * @param target target file name (This is passed as it is to IDE) */ - compile (files: Source, target: string): void { + compile(files: Source, target: string): void { this.state.target = target + this.state.compilationStartTime = new Date().getTime() this.event.trigger('compilationStarted', []) this.internalCompile(files) } @@ -94,7 +95,7 @@ export class Compiler { * @param version compiler version */ - onCompilerLoaded (version: string): void { + onCompilerLoaded(version: string): void { this.state.currentVersion = version this.event.trigger('compilerLoaded', [version]) } @@ -103,7 +104,7 @@ export class Compiler { * @dev Called when compiler is loaded internally (without worker) */ - onInternalCompilerLoaded (): void { + onInternalCompilerLoaded(): void { if (this.state.worker === null) { const compiler: any = typeof (window) !== 'undefined' && window['Module'] ? require('solc/wrapper')(window['Module']) : require('solc') // eslint-disable-line this.state.compileJSON = (source: SourceWithTarget) => { @@ -142,7 +143,7 @@ export class Compiler { * @param source Source */ - onCompilationFinished (data: CompilationResult, missingInputs?: string[], source?: SourceWithTarget, input?: string, version?: string): void { + onCompilationFinished(data: CompilationResult, missingInputs?: string[], source?: SourceWithTarget, input?: string, version?: string): void { let noFatalErrors = true // ie warnings are ok const checkIfFatalError = (error: CompilationError) => { @@ -177,7 +178,7 @@ export class Compiler { * @param version compiler version */ - loadRemoteVersion (version: string): void { + loadRemoteVersion(version: string): void { console.log(`Loading remote solc version ${version} ...`) const compiler: any = require('solc') // eslint-disable-line compiler.loadRemoteVersion(version, (err, remoteCompiler) => { @@ -220,7 +221,7 @@ export class Compiler { * @param url URL to load compiler from */ - loadVersion (usingWorker: boolean, url: string): void { + loadVersion(usingWorker: boolean, url: string): void { console.log('Loading ' + url + ' ' + (usingWorker ? 'with worker' : 'without worker')) this.event.trigger('loadingCompiler', [url, usingWorker]) if (this.state.worker) { @@ -239,7 +240,7 @@ export class Compiler { * @param url URL to load compiler from */ - loadInternal (url: string): void { + loadInternal(url: string): void { delete window['Module'] // NOTE: workaround some browsers? window['Module'] = undefined @@ -265,38 +266,41 @@ export class Compiler { * @param url URL to load compiler from */ - loadWorker (url: string): void { + loadWorker(url: string): void { this.state.worker = webworkify(require.resolve('./compiler-worker')) - const jobs: Record<'sources', SourceWithTarget> [] = [] + const jobs: Record<'sources', SourceWithTarget>[] = [] - this.state.worker.addEventListener('message', (msg: Record <'data', MessageFromWorker>) => { + this.state.worker.addEventListener('message', (msg: Record<'data', MessageFromWorker>) => { const data: MessageFromWorker = msg.data + if (this.state.compilerRetriggerMode == CompilerRetriggerMode.retrigger && data.timestamp !== this.state.compilationStartTime) { + return + } switch (data.cmd) { case 'versionLoaded': if (data.data) this.onCompilerLoaded(data.data) break case 'compiled': - { - let result: CompilationResult - if (data.data && data.job !== undefined && data.job >= 0) { - try { - result = JSON.parse(data.data) - } catch (exception) { - result = { error: { formattedMessage: 'Invalid JSON output from the compiler: ' + exception } } - } - let sources: SourceWithTarget = {} - if (data.job in jobs !== undefined) { - sources = jobs[data.job].sources - delete jobs[data.job] + { + let result: CompilationResult + if (data.data && data.job !== undefined && data.job >= 0) { + try { + result = JSON.parse(data.data) + } catch (exception) { + result = { error: { formattedMessage: 'Invalid JSON output from the compiler: ' + exception } } + } + let sources: SourceWithTarget = {} + if (data.job in jobs !== undefined) { + sources = jobs[data.job].sources + delete jobs[data.job] + } + this.onCompilationFinished(result, data.missingInputs, sources, data.input, this.state.currentVersion) } - this.onCompilationFinished(result, data.missingInputs, sources, data.input, this.state.currentVersion) + break } - break - } } }) - this.state.worker.addEventListener('error', (msg: Record <'data', MessageFromWorker>) => { + this.state.worker.addEventListener('error', (msg: Record<'data', MessageFromWorker>) => { const formattedMessage = `Worker error: ${msg.data && msg.data !== undefined ? msg.data : msg['message']}` this.onCompilationFinished({ error: { formattedMessage } }) }) @@ -322,7 +326,8 @@ export class Compiler { this.state.worker.postMessage({ cmd: 'compile', job: jobs.length - 1, - input: input + input: input, + timestamp: this.state.compilationStartTime }) } } @@ -340,7 +345,7 @@ export class Compiler { * @param cb callback */ - gatherImports (files: Source, importHints?: string[], cb?: gatherImportsCallbackInterface): void { + gatherImports(files: Source, importHints?: string[], cb?: gatherImportsCallbackInterface): void { importHints = importHints || [] // FIXME: This will only match imports if the file begins with one '.' // It should tokenize by lines and check each. @@ -379,7 +384,7 @@ export class Compiler { * @param version version */ - truncateVersion (version: string): string { + truncateVersion(version: string): string { const tmp: RegExpExecArray | null = /^(\d+.\d+.\d+)/.exec(version) return tmp ? tmp[1] : version } @@ -389,8 +394,8 @@ export class Compiler { * @param data Compilation result */ - updateInterface (data: CompilationResult) : CompilationResult { - txHelper.visitContracts(data.contracts, (contract : visitContractsCallbackParam) => { + updateInterface(data: CompilationResult): CompilationResult { + txHelper.visitContracts(data.contracts, (contract: visitContractsCallbackParam) => { if (!contract.object.abi) contract.object.abi = [] if (this.state.language === 'Yul' && contract.object.abi.length === 0) { // yul compiler does not return any abi, @@ -422,7 +427,7 @@ export class Compiler { * @param name contract name */ - getContract (name: string): Record | null { + getContract(name: string): Record | null { if (this.state.lastCompilationResult && this.state.lastCompilationResult.data && this.state.lastCompilationResult.data.contracts) { return txHelper.getContract(name, this.state.lastCompilationResult.data.contracts) } @@ -434,7 +439,7 @@ export class Compiler { * @param cb callback */ - visitContracts (cb: visitContractsCallbackInterface) : void | null { + visitContracts(cb: visitContractsCallbackInterface): void | null { if (this.state.lastCompilationResult && this.state.lastCompilationResult.data && this.state.lastCompilationResult.data.contracts) { return txHelper.visitContracts(this.state.lastCompilationResult.data.contracts, cb) } @@ -445,7 +450,7 @@ export class Compiler { * @dev Get the compiled contracts data from last compilation result */ - getContracts () : CompilationResult['contracts'] | null { + getContracts(): CompilationResult['contracts'] | null { if (this.state.lastCompilationResult && this.state.lastCompilationResult.data && this.state.lastCompilationResult.data.contracts) { return this.state.lastCompilationResult.data.contracts } @@ -456,7 +461,7 @@ export class Compiler { * @dev Get sources from last compilation result */ - getSources () : Source | null | undefined { + getSources(): Source | null | undefined { if (this.state.lastCompilationResult && this.state.lastCompilationResult.source) { return this.state.lastCompilationResult.source.sources } @@ -468,7 +473,7 @@ export class Compiler { * @param fileName file name */ - getSource (fileName: string) : Source['filename'] | null { + getSource(fileName: string): Source['filename'] | null { if (this.state.lastCompilationResult && this.state.lastCompilationResult.source && this.state.lastCompilationResult.source.sources) { return this.state.lastCompilationResult.source.sources[fileName] } @@ -480,7 +485,7 @@ export class Compiler { * @param index - index of the source */ - getSourceName (index: number): string | null { + getSourceName(index: number): string | null { if (this.state.lastCompilationResult && this.state.lastCompilationResult.data && this.state.lastCompilationResult.data.sources) { return Object.keys(this.state.lastCompilationResult.data.sources)[index] } diff --git a/libs/remix-solidity/src/compiler/types.ts b/libs/remix-solidity/src/compiler/types.ts index c4e48dd2ff..ea9906c130 100644 --- a/libs/remix-solidity/src/compiler/types.ts +++ b/libs/remix-solidity/src/compiler/types.ts @@ -154,6 +154,11 @@ export type EVMVersion = 'homestead' | 'tangerineWhistle' | 'spuriousDragon' | ' export type Language = 'Solidity' | 'Yul' +export enum CompilerRetriggerMode { + 'none' , + 'retrigger' +} + export interface CompilerState { compileJSON: ((input: SourceWithTarget) => void) | null, worker: any, @@ -166,6 +171,7 @@ export interface CompilerState { target: string | null, useFileConfiguration: boolean, configFileContent: string, + compilerRetriggerMode: CompilerRetriggerMode, lastCompilationResult: { data: CompilationResult | null, source: SourceWithTarget | null | undefined @@ -182,6 +188,7 @@ export interface MessageToWorker { job?: number, input?: CompilerInput, data?: string + timestamp?: number } export interface MessageFromWorker { @@ -190,6 +197,7 @@ export interface MessageFromWorker { missingInputs?: string[], input?: any, data?: string + timestamp?: number } export interface visitContractsCallbackParam {