optimize config for compiler

pull/5370/head
filip mertens 3 years ago
parent 583b4dc09d
commit 0902bc7f7f
  1. 21
      apps/remix-ide/src/app/plugins/parser/code-parser.tsx
  2. 15
      apps/remix-ide/src/app/plugins/parser/services/code-parser-antlr-service.ts
  3. 177
      apps/remix-ide/src/app/plugins/parser/services/code-parser-compiler.ts
  4. 3
      libs/remix-core-plugin/src/lib/offset-line-to-column-converter.ts
  5. 49
      libs/remix-ui/editor/src/lib/providers/completionProvider.ts
  6. 1
      libs/remix-ui/editor/src/lib/remix-ui-editor.tsx

@ -56,6 +56,7 @@ export class CodeParser extends Plugin {
getLastNodeInLine: (ast: string) => Promise<any>
listAstNodes: () => Promise<any>
getBlockAtPosition: (position: any, text?: string) => Promise<any>
getCurrentFileAST: (text?: string) => Promise<any>
constructor(astWalker) {
super(profile)
@ -73,10 +74,11 @@ export class CodeParser extends Plugin {
this.antlrService = new CodeParserAntlrService(this)
this.nodeHelper = new CodeParserNodeHelper(this)
this.parseSolidity = this.antlrService.parseSolidity
this.getLastNodeInLine = this.antlrService.getLastNodeInLine
this.listAstNodes = this.antlrService.listAstNodes
this.getBlockAtPosition = this.antlrService.getBlockAtPosition
this.parseSolidity = this.antlrService.parseSolidity.bind(this.antlrService)
this.getLastNodeInLine = this.antlrService.getLastNodeInLine.bind(this.antlrService)
this.listAstNodes = this.antlrService.listAstNodes.bind(this.antlrService)
this.getBlockAtPosition = this.antlrService.getBlockAtPosition.bind(this.antlrService)
this.getCurrentFileAST = this.antlrService.getCurrentFileAST.bind(this.antlrService)
this.on('editor', 'didChangeFile', async (file) => {
console.log('contentChanged', file)
@ -143,6 +145,7 @@ export class CodeParser extends Plugin {
}
}
}
// NODE HELPERS
@ -512,17 +515,19 @@ export class CodeParser extends Plugin {
* @returns
*/
async getVariableDeclaration(node: any) {
const nodeVisibility = node.visibility && node.visibility.length ? node.visibility + ' ' : ''
const nodeName = node.name && node.name.length ? node.name : ''
if (node.typeDescriptions && node.typeDescriptions.typeString) {
return `${node.typeDescriptions.typeString} ${node.visibility}${node.name && node.name.length ? ` ${node.name}` : ''}`
return `${node.typeDescriptions.typeString} ${nodeVisibility}${nodeName}`
} else {
if (node.typeName && node.typeName.name) {
return `${node.typeName.name} ${node.visibility}${node.name && node.name.length ? ` ${node.name}` : ''}`
return `${node.typeName.name} ${nodeVisibility}${nodeName}`
}
else if (node.typeName && node.typeName.namePath) {
return `${node.typeName.namePath} ${node.visibility}${node.name && node.name.length ? ` ${node.name}` : ''}`
return `${node.typeName.namePath} ${nodeVisibility}${nodeName}`
}
else {
return `${node.visibility}${node.name && node.name.length ? ` ${node.name}` : ''}`
return `${nodeName}${nodeName}`
}
}
}

@ -31,6 +31,7 @@ export default class CodeParserAntlrService {
*/
async getCurrentFileAST(text: string | null = null) {
this.plugin.currentFile = await this.plugin.call('fileManager', 'file')
if(this.plugin.currentFile && this.plugin.currentFile.endsWith('.sol')) {
if (!this.plugin.currentFile) return
const fileContent = text || await this.plugin.call('fileManager', 'readFile', this.plugin.currentFile)
try {
@ -41,6 +42,7 @@ export default class CodeParserAntlrService {
}
return this.plugin.currentFileAST
}
}
/**
* Lists the AST nodes from the current file parser
@ -84,7 +86,14 @@ export default class CodeParserAntlrService {
},
InvalidNode: function (node) {
nodes.push({ ...node, nodeType: node.type })
},
EnumDefinition: function (node) {
nodes.push({ ...node, nodeType: node.type })
},
StructDefinition: function (node) {
nodes.push({ ...node, nodeType: node.type })
}
})
console.log("LIST NODES", nodes)
return nodes
@ -117,8 +126,8 @@ export default class CodeParserAntlrService {
}
})
if (lastNode && lastNode.expression && lastNode.expression.expression) {
console.log('lastNode with expression', lastNode, lastNode.expression)
return lastNode.expression.expression
console.log('lastNode with expression', lastNode, lastNode.expression, lastNode.expression.expression)
// return lastNode.expression.expression
}
if (lastNode && lastNode.expression) {
console.log('lastNode with expression', lastNode, lastNode.expression)
@ -138,9 +147,7 @@ export default class CodeParserAntlrService {
async getBlockAtPosition(position: any, text: string = null) {
await this.getCurrentFileAST(text)
const allowedTypes = ['SourceUnit', 'ContractDefinition', 'FunctionDefinition']
const walkAst = (node) => {
console.log(node)
if (node.loc.start.line <= position.lineNumber && node.loc.end.line >= position.lineNumber) {
const children = node.children || node.subNodes
if (children && allowedTypes.indexOf(node.type) !== -1) {

@ -2,10 +2,10 @@
import { CompilerAbstract } from '@remix-project/remix-solidity'
import { Compiler } from '@remix-project/remix-solidity'
import { AstNode, CompilationError, CompilationResult, CompilationSource } from '@remix-project/remix-solidity'
import { helper } from '@remix-project/remix-solidity'
import { CompilationError, CompilationResult, CompilationSource } from '@remix-project/remix-solidity'
import { CodeParser } from "../code-parser";
import { fileDecoration, fileDecorationType } from '@remix-ui/file-decorators'
import { sourceMappingDecoder } from '@remix-project/remix-debug'
export default class CodeParserCompiler {
plugin: CodeParser
@ -22,7 +22,9 @@ export default class CodeParserCompiler {
init() {
this.onAstFinished = async (success, data: CompilationResult, source: CompilationSource, input: any, version) => {
console.log('compile success', success, data, this)
console.log('compile success', success, data)
this.plugin.call('editor', 'clearAnnotations')
this.errorState = true
const checkIfFatalError = (error: CompilationError) => {
@ -40,21 +42,102 @@ export default class CodeParserCompiler {
if (data.errors) {
const sources = result.getSourceCode().sources
for (const error of data.errors) {
const pos = helper.getPositionDetails(error.formattedMessage)
const filePosition = Object.keys(sources).findIndex((fileName) => fileName === error.sourceLocation.file)
const lineColumn = await this.plugin.call('offsetToLineColumnConverter', 'offsetToLineColumn',
{
const lineBreaks = sourceMappingDecoder.getLinebreakPositions(sources[error.sourceLocation.file].content)
const lineColumn = sourceMappingDecoder.convertOffsetToLineColumn({
start: error.sourceLocation.start,
length: error.sourceLocation.end - error.sourceLocation.start
},
filePosition,
result.getSourceCode().sources,
null)
}, lineBreaks)
allErrors.push({ error, lineColumn })
}
console.log('allErrors', allErrors)
await this.plugin.call('editor', 'addErrorMarker', allErrors)
this.addDecorators(allErrors, sources)
} else {
await this.plugin.call('editor', 'clearErrorMarkers', result.getSourceCode().sources)
await this.clearDecorators(result.getSourceCode().sources)
}
if (!data.sources) return
if (data.sources && Object.keys(data.sources).length === 0) return
this.plugin.lastCompilationResult = new CompilerAbstract('soljson', data, source, input)
this.errorState = false
this.plugin._index = {
Declarations: {},
FlatReferences: {},
NodesPerFile: {},
}
this.plugin._buildIndex(data, source)
if (this.gastEstimateTimeOut) {
window.clearTimeout(this.gastEstimateTimeOut)
}
this.gastEstimateTimeOut = window.setTimeout(async () => {
await this.plugin.gasService.showGasEstimates()
}, 1000)
console.log("INDEX", this.plugin._index)
this.plugin.emit('astFinished')
}
this.compiler = new Compiler((url, cb) => this.plugin.call('contentImport', 'resolveAndSave', url, undefined, true).then((result) => cb(null, result)).catch((error) => cb(error.message)))
this.compiler.event.register('compilationFinished', this.onAstFinished)
}
// COMPILER
/**
*
* @returns
*/
async compile() {
try {
this.plugin.currentFile = await this.plugin.call('fileManager', 'file')
if (this.plugin.currentFile && this.plugin.currentFile.endsWith('.sol')) {
const state = await this.plugin.call('solidity', 'getCompilerState')
console.log('COMPILER STATE', state)
this.compiler.set('optimize', state.optimize)
this.compiler.set('evmVersion', state.evmVersion)
this.compiler.set('language', state.language)
this.compiler.set('runs', state.runs)
this.compiler.set('useFileConfiguration', true)
const configFileContent = {
"language": "Solidity",
"settings": {
"optimizer": {
"enabled": false,
"runs": 200
},
"outputSelection": {
"*": {
"": ["ast"],
"*": ["evm.gasEstimates"]
}
},
"evmVersion": state.evmVersion && state.evmVersion.toString() || "byzantium",
}
}
this.compiler.set('configFileContent', JSON.stringify(configFileContent))
this.plugin.currentFile = await this.plugin.call('fileManager', 'file')
console.log(this.plugin.currentFile)
if (!this.plugin.currentFile) return
const content = await this.plugin.call('fileManager', 'readFile', this.plugin.currentFile)
const sources = { [this.plugin.currentFile]: { content } }
this.compiler.compile(sources, this.plugin.currentFile)
}
} catch (e) {
console.log(e)
}
}
async addDecorators(allErrors: any[], sources: any) {
const errorsPerFiles = {}
for (const error of allErrors) {
if (!errorsPerFiles[error.error.sourceLocation.file]) {
@ -78,11 +161,7 @@ export default class CodeParserCompiler {
)
sortedErrorsPerFiles[fileName] = errors
}
console.log('sortedErrorsPerFiles', sortedErrorsPerFiles)
const filesWithOutErrors = Object.keys(sources).filter((fileName) => !sortedErrorsPerFiles[fileName])
console.log('filesWithOutErrors', filesWithOutErrors)
// add decorators
const decorators: fileDecoration[] = []
for (const fileName in sortedErrorsPerFiles) {
@ -115,13 +194,14 @@ export default class CodeParserCompiler {
}
decorators.push(decorator)
}
console.log(decorators)
await this.plugin.call('fileDecorator', 'setFileDecorators', decorators)
await this.plugin.call('editor', 'clearErrorMarkers', filesWithOutErrors)
} else {
await this.plugin.call('editor', 'clearErrorMarkers', result.getSourceCode().sources)
}
async clearDecorators(sources: any) {
const decorators: fileDecoration[] = []
for (const fileName of Object.keys(result.getSourceCode().sources)) {
for (const fileName of Object.keys(sources)) {
const decorator: fileDecoration = {
path: fileName,
isDirectory: false,
@ -135,64 +215,9 @@ export default class CodeParserCompiler {
}
decorators.push(decorator)
}
console.log(decorators)
await this.plugin.call('fileDecorator', 'setFileDecorators', decorators)
}
if (!data.sources) return
if (data.sources && Object.keys(data.sources).length === 0) return
this.plugin.lastCompilationResult = new CompilerAbstract('soljson', data, source, input)
this.errorState = false
this.plugin._index = {
Declarations: {},
FlatReferences: {},
NodesPerFile: {},
}
this.plugin._buildIndex(data, source)
if (this.gastEstimateTimeOut) {
window.clearTimeout(this.gastEstimateTimeOut)
}
this.gastEstimateTimeOut = window.setTimeout(async () => {
await this.plugin.gasService.showGasEstimates()
}, 1000)
console.log("INDEX", this.plugin._index)
this.plugin.emit('astFinished')
}
this.compiler = new Compiler((url, cb) => this.plugin.call('contentImport', 'resolveAndSave', url, undefined, true).then((result) => cb(null, result)).catch((error) => cb(error.message)))
this.compiler.event.register('compilationFinished', this.onAstFinished)
}
// COMPILER
/**
*
* @returns
*/
async compile() {
try {
const state = await this.plugin.call('solidity', 'getCompilerState')
this.compiler.set('optimize', state.optimize)
this.compiler.set('evmVersion', state.evmVersion)
this.compiler.set('language', state.language)
this.compiler.set('runs', state.runs)
this.compiler.set('useFileConfiguration', state.useFileConfiguration)
this.plugin.currentFile = await this.plugin.call('fileManager', 'file')
console.log(this.plugin.currentFile)
if (!this.plugin.currentFile) return
const content = await this.plugin.call('fileManager', 'readFile', this.plugin.currentFile)
const sources = { [this.plugin.currentFile]: { content } }
this.compiler.compile(sources, this.plugin.currentFile)
} catch (e) {
console.log(e)
}
await this.plugin.call('fileDecorator', 'setFileDecorators', decorators)
}
}

@ -30,15 +30,12 @@ export class OffsetToLineColumnConverter extends Plugin {
* @param {Object.<string, {ast, id}>} asts - Map of content sources
*/
offsetToLineColumn (rawLocation, file, sources, asts) {
console.log('offsetToLineColumn', sources)
//if (!this.lineBreakPositionsByContent[file]) {
const sourcesArray = Object.keys(sources)
if (!asts || (file === 0 && sourcesArray.length === 1) || !Array.isArray(asts)) {
console.log("no asts or only one file", sourcesArray, sources, sources[sourcesArray[file || 0]].content)
// if we don't have ast, we process the only one available content (applicable also for compiler older than 0.4.12)
this.lineBreakPositionsByContent[file || 0] = this.sourceMappingDecoder.getLinebreakPositions(sources[sourcesArray[file || 0]].content)
} else {
console.log("have asts")
for (const filename in asts) {
const source = asts[filename]
if (source.id === file) {

@ -48,7 +48,7 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
console.log('expression elements', expressionElements)
let dotCompleted = false
if (expressionElements.length === 2) {
//if (expressionElements.length === 2) {
const globalCompletion = getContextualAutoCompleteByGlobalVariable(lastNodeInExpression.name, range, this.monaco)
if (globalCompletion) {
dotCompleted = true
@ -58,7 +58,7 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
dotCompleted = true
nodes = [...nodes, ...await this.getContractCompletions(nodes, position)]
}
}
//}
if (expressionElements.length > 1 && !dotCompleted) {
const last = lastNodeInExpression.name || lastNodeInExpression.memberName
@ -72,7 +72,7 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
if (block) {
nodesAtPosition = await this.props.plugin.call('codeParser', 'nodesAtPosition', block.body ? block.body.range[0] : block.range[0])
console.log('NODES AT POSITION WITH BLOCK', nodesAtPosition)
} else{
} else {
nodesAtPosition = await this.props.plugin.call('codeParser', 'nodesAtPosition', cursorPosition)
console.log('NODES AT POSITION', nodesAtPosition)
}
@ -87,7 +87,7 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
console.log('FOUND NODE', nodeOfScope)
if (nodeOfScope.typeName && nodeOfScope.typeName.nodeType === 'UserDefinedTypeName') {
const declarationOf = await this.props.plugin.call('codeParser', 'declarationOf', nodeOfScope.typeName)
console.log('HAS DECLARATION OF', declarationOf)
console.log('METHOD 1 HAS DECLARATION OF', declarationOf)
nodes = [...nodes, ...declarationOf.nodes || declarationOf.members]
const baseContracts = await this.getlinearizedBaseContracts(declarationOf)
for (const baseContract of baseContracts) {
@ -98,7 +98,7 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
}
}
// anything within the block statements might provide a clue to what it is
if (!nodes.length) {
// if (!nodes.length) {
for (const node of nodesAtPosition) {
if (node.statements) {
for (const statement of node.statements) {
@ -106,7 +106,7 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
const declarationOf = await this.props.plugin.call('codeParser', 'declarationOf', statement.expression)
if (declarationOf.typeName && declarationOf.typeName.nodeType === 'UserDefinedTypeName') {
const baseDeclaration = await this.props.plugin.call('codeParser', 'declarationOf', declarationOf.typeName)
console.log('HAS BASE DECLARATION OF', baseDeclaration)
console.log('METHOD 2 HAS BASE DECLARATION OF', baseDeclaration)
nodes = [...nodes, ...baseDeclaration.nodes || baseDeclaration.members]
}
}
@ -114,10 +114,10 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
}
}
}
}
// }
// brute force search in all nodes with the name
if (!nodes.length) {
if (!nodes.length || 1) {
const nodesOfScope = await this.props.plugin.call('codeParser', 'getNodesWithName', last)
console.log('NODES WITHE NAME ', last, nodesOfScope)
for (const nodeOfScope of nodesOfScope) {
@ -125,8 +125,8 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
console.log('FOUND NODE', nodeOfScope)
if (nodeOfScope.typeName && nodeOfScope.typeName.nodeType === 'UserDefinedTypeName') {
const declarationOf = await this.props.plugin.call('codeParser', 'declarationOf', nodeOfScope.typeName)
console.log('HAS DECLARATION OF', declarationOf)
// nodes = [...nodes, ...declarationOf.nodes || declarationOf.members]
console.log('METHOD 3 HAS DECLARATION OF', declarationOf)
nodes = [...nodes, ...declarationOf.nodes || declarationOf.members]
//const baseContracts = await this.getlinearizedBaseContracts(declarationOf)
//for (const baseContract of baseContracts) {
//nodes = [...nodes, ...baseContract.nodes]
@ -153,6 +153,18 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
console.log('WORD', word, wordAt)
console.log('NODES', nodes)
// remove duplicates
const nodeIds = {};
const filteredNodes = nodes.filter((node) => {
if (node.id) {
if (nodeIds[node.id]) {
return false;
}
nodeIds[node.id] = true;
}
return true;
});
const getNodeLink = async (node: any) => {
return await this.props.plugin.call('codeParser', 'getNodeLink', node)
}
@ -166,7 +178,7 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
}
const completeParameters = async (parameters: any) => {
const localParam = ( parameters && parameters.parameters ) || (parameters)
const localParam = (parameters && parameters.parameters) || (parameters)
if (localParam) {
const params = []
for (const key in localParam) {
@ -178,11 +190,18 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
const getVariableDeclaration = async (node: any) => {
return await this.props.plugin.call('codeParser', 'getVariableDeclaration', node)
let variableDeclaration = await this.props.plugin.call('codeParser', 'getVariableDeclaration', node)
if (node.scope) {
const scopeNode = await this.props.plugin.call('codeParser', 'getNodeById', node.scope)
if (scopeNode) {
variableDeclaration = `${scopeNode.name}.${variableDeclaration}`
}
}
return variableDeclaration
}
for (const node of Object.values(nodes) as any[]) {
for (const node of Object.values(filteredNodes) as any[]) {
if (!node.name) continue
if (node.nodeType === 'VariableDeclaration') {
const completion = {
@ -327,7 +346,7 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
*/
private async getLastNodeInExpression(lineTextBeforeCursor: string) {
const wrapLineInFunction = async(text: string) => {
const wrapLineInFunction = async (text: string) => {
return `function() {
${text}
}`
@ -351,7 +370,7 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
try {
const lineAst = await this.props.plugin.call('codeParser', 'parseSolidity', line)
const lastNode = await this.props.plugin.call('codeParser', 'getLastNodeInLine', lineAst)
if(lastNode) {
if (lastNode) {
lastNodeInExpression = lastNode
break
}

@ -429,7 +429,6 @@ export const EditorUI = (props: EditorUIProps) => {
props.editorAPI.clearErrorMarkers = async (sources: any) => {
if (sources) {
console.log('clear', sources)
for (const source of (Array.isArray(sources) ? sources : Object.keys(sources))) {
const filePath = source
const model = editorModelsState[filePath]?.model

Loading…
Cancel
Save