Merge pull request #259 from h3ph4est7s/h3ph4est7s-patch-1
Honor excluded files & work towards fixing performance problem at preprocessor.preprocessor-improvements
commit
5b71c44708
@ -1,92 +1,125 @@ |
|||||||
const SolExplore = require('sol-explore'); |
const SolExplore = require('sol-explore'); |
||||||
const SolidityParser = require('solidity-parser-sc'); |
const SolidityParser = require('solidity-parser-sc'); |
||||||
|
|
||||||
const crRegex = /[\r\n ]+$/g; |
|
||||||
/** |
/** |
||||||
* Splices enclosing brackets into `contract` around `expression`; |
* Splices enclosing brackets into `contract` around `expression`; |
||||||
* @param {String} contract solidity source |
* @param {String} contract solidity source |
||||||
* @param {Object} node AST node to bracket |
* @param {Object} expression AST node to bracket |
||||||
* @return {String} contract |
* @return {String} contract |
||||||
*/ |
*/ |
||||||
function blockWrap(contract, expression) { |
function blockWrap(contract, expression) { |
||||||
return contract.slice(0, expression.start) + '{' + contract.slice(expression.start, expression.end) + '}' + contract.slice(expression.end); |
return contract.slice(0, expression.start) + '{' + contract.slice(expression.start, expression.end) + '}' + contract.slice(expression.end); |
||||||
} |
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Parses the AST tree to remove pure, constant and view modifiers |
||||||
|
* @param {Object} ast AST tree |
||||||
|
* @param {String} contract solidity code |
||||||
|
* @return {String} contract |
||||||
|
*/ |
||||||
|
function removeViewPureConst(ast, contract) { |
||||||
|
SolExplore.traverse(ast, { |
||||||
|
enter(node, parent) { |
||||||
|
if (node.type === 'FunctionDeclaration' && node.modifiers) { |
||||||
|
// We want to remove constant / pure / view from functions
|
||||||
|
for (let i = 0; i < node.modifiers.length; i++) { |
||||||
|
if (['pure', 'constant', 'view'].indexOf(node.modifiers[i].name) > -1) { |
||||||
|
contract = contract.slice(0, node.modifiers[i].start) + |
||||||
|
' '.repeat(node.modifiers[i].end - node.modifiers[i].start) + |
||||||
|
contract.slice(node.modifiers[i].end); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
}); |
||||||
|
return contract; |
||||||
|
} |
||||||
|
|
||||||
/** |
/** |
||||||
* Captures carriage returns at modifiers we'll remove. These need to be re-injected into the |
* Parses the AST tree to locate unbracketed singleton statements attached to if, else, for and while statements |
||||||
* source to keep line report alignments accurate. |
* and brackets them |
||||||
* @param {String} contract solidity source |
* @param {Object} ast AST tree product of SolidityParser |
||||||
* @param {Object} modifier AST node |
* @param {String} contract solidity code |
||||||
* @return {String} whitespace around the modifier |
* @return {String} contract |
||||||
*/ |
*/ |
||||||
function getModifierWhitespace(contract, modifier){ |
function bracketUnbStatements(ast, contract) { |
||||||
const source = contract.slice(modifier.start, modifier.end); |
const brkList = []; |
||||||
const whitespace = source.match(crRegex) || []; |
let offset = 0; |
||||||
return whitespace.join(''); |
SolExplore.traverse(ast, { |
||||||
|
enter(node, parent) { // eslint-disable-line no-loop-func
|
||||||
|
// If consequents
|
||||||
|
if (node.type === 'IfStatement' && node.consequent.type !== 'BlockStatement') { |
||||||
|
brkList.push({ |
||||||
|
start: node.consequent.start, end: node.consequent.end, |
||||||
|
}); |
||||||
|
// If alternates
|
||||||
|
} else if ( |
||||||
|
node.type === 'IfStatement' && |
||||||
|
node.alternate && |
||||||
|
node.alternate.type !== 'BlockStatement') { |
||||||
|
brkList.push({ |
||||||
|
start: node.alternate.start, end: node.alternate.end, |
||||||
|
}); |
||||||
|
// Loops
|
||||||
|
} else if ( |
||||||
|
(node.type === 'ForStatement' || node.type === 'WhileStatement') && |
||||||
|
node.body.type !== 'BlockStatement') { |
||||||
|
brkList.push({ |
||||||
|
start: node.body.start, end: node.body.end, |
||||||
|
}); |
||||||
|
} |
||||||
|
}, |
||||||
|
}); |
||||||
|
brkList.sort((a, b) => { |
||||||
|
if (a.start < b.start) { |
||||||
|
return -1; |
||||||
|
} |
||||||
|
if (a.start > b.start) { |
||||||
|
return 1; |
||||||
|
} |
||||||
|
return 0; |
||||||
|
}); |
||||||
|
for (let i = 0; i < brkList.length; i++) { |
||||||
|
let check = null; |
||||||
|
if (i > 0 && i < brkList.length - 1) { |
||||||
|
check = |
||||||
|
brkList[i].end >= brkList[i + 1].end || |
||||||
|
brkList[i].end <= brkList[i - 1].end; |
||||||
|
if (i > 1) { |
||||||
|
check = check || brkList[i].end <= brkList[i - 2].end; |
||||||
|
} |
||||||
|
} else if (i === 0) { |
||||||
|
check = brkList[i].end >= brkList[i + 1].end; |
||||||
|
} else if (i === brkList.length - 1) { |
||||||
|
check = brkList[i].end <= brkList[i - 1].end; |
||||||
|
} |
||||||
|
brkList[i].nested = check; |
||||||
|
const elem = Object.assign(brkList[i]); |
||||||
|
elem.start += offset; |
||||||
|
elem.end += offset; |
||||||
|
contract = blockWrap(contract, elem); |
||||||
|
offset += 2; |
||||||
|
} |
||||||
|
return contract; |
||||||
} |
} |
||||||
|
|
||||||
/** |
/** |
||||||
* Locates unbracketed singleton statements attached to if, else, for and while statements |
* Locates unbracketed singleton statements attached to if, else, for and while statements |
||||||
* and brackets them. Instrumenter needs to inject events at these locations and having |
* and brackets them. Instrumenter needs to inject events at these locations and having |
||||||
* them pre-bracketed simplifies the process. Each time a modification is made the contract |
* them pre-bracketed simplifies the process. The process is broken down to 3 stages: |
||||||
* is passed back to the parser and re-walked because all the starts and ends get shifted. |
* 1. Parse the contract to get the AST tree |
||||||
* |
* 2. Remove all the view, pure and constant modifiers |
||||||
* Also removes pure and view modifiers. |
* 3. Bracket all related unbracketed singleton statements |
||||||
* |
|
||||||
* @param {String} contract solidity code |
* @param {String} contract solidity code |
||||||
* @return {String} contract |
* @return {String} contract |
||||||
*/ |
*/ |
||||||
module.exports.run = function r(contract) { |
module.exports.run = function r(contract) { |
||||||
let keepRunning = true; |
try { |
||||||
|
const ast = SolidityParser.parse(contract); |
||||||
while (keepRunning) { |
contract = removeViewPureConst(ast, contract); |
||||||
try { |
contract = bracketUnbStatements(ast, contract); |
||||||
const ast = SolidityParser.parse(contract); |
} catch (err) { |
||||||
keepRunning = false; |
contract = err; |
||||||
SolExplore.traverse(ast, { |
|
||||||
enter(node, parent) { // eslint-disable-line no-loop-func
|
|
||||||
// If consequents
|
|
||||||
if (node.type === 'IfStatement' && node.consequent.type !== 'BlockStatement') { |
|
||||||
contract = blockWrap(contract, node.consequent); |
|
||||||
keepRunning = true; |
|
||||||
this.stopTraversal(); |
|
||||||
// If alternates
|
|
||||||
} else if ( |
|
||||||
node.type === 'IfStatement' && |
|
||||||
node.alternate && |
|
||||||
node.alternate.type !== 'BlockStatement') { |
|
||||||
contract = blockWrap(contract, node.alternate); |
|
||||||
keepRunning = true; |
|
||||||
this.stopTraversal(); |
|
||||||
// Loops
|
|
||||||
} else if ( |
|
||||||
(node.type === 'ForStatement' || node.type === 'WhileStatement') && |
|
||||||
node.body.type !== 'BlockStatement') { |
|
||||||
contract = blockWrap(contract, node.body); |
|
||||||
keepRunning = true; |
|
||||||
this.stopTraversal(); |
|
||||||
} else if (node.type === 'FunctionDeclaration' && node.modifiers) { |
|
||||||
// We want to remove constant / pure / view from functions
|
|
||||||
for (let i = 0; i < node.modifiers.length; i++) { |
|
||||||
if (['pure', 'constant', 'view'].indexOf(node.modifiers[i].name) > -1) { |
|
||||||
let whitespace = getModifierWhitespace(contract, node.modifiers[i]); |
|
||||||
|
|
||||||
contract = contract.slice(0, node.modifiers[i].start) + |
|
||||||
whitespace + |
|
||||||
contract.slice(node.modifiers[i].end); |
|
||||||
|
|
||||||
keepRunning = true; |
|
||||||
this.stopTraversal(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
}, |
|
||||||
}); |
|
||||||
} catch (err) { |
|
||||||
contract = err; |
|
||||||
keepRunning = false; |
|
||||||
} |
|
||||||
} |
} |
||||||
return contract; |
return contract; |
||||||
}; |
}; |
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue