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 SolidityParser = require('solidity-parser-sc'); |
||||
|
||||
const crRegex = /[\r\n ]+$/g; |
||||
/** |
||||
* Splices enclosing brackets into `contract` around `expression`; |
||||
* @param {String} contract solidity source |
||||
* @param {Object} node AST node to bracket |
||||
* @return {String} contract |
||||
* @param {String} contract solidity source |
||||
* @param {Object} expression AST node to bracket |
||||
* @return {String} contract |
||||
*/ |
||||
function blockWrap(contract, expression) { |
||||
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 |
||||
* source to keep line report alignments accurate. |
||||
* @param {String} contract solidity source |
||||
* @param {Object} modifier AST node |
||||
* @return {String} whitespace around the modifier |
||||
* Parses the AST tree to locate unbracketed singleton statements attached to if, else, for and while statements |
||||
* and brackets them |
||||
* @param {Object} ast AST tree product of SolidityParser |
||||
* @param {String} contract solidity code |
||||
* @return {String} contract |
||||
*/ |
||||
function getModifierWhitespace(contract, modifier){ |
||||
const source = contract.slice(modifier.start, modifier.end); |
||||
const whitespace = source.match(crRegex) || []; |
||||
return whitespace.join(''); |
||||
function bracketUnbStatements(ast, contract) { |
||||
const brkList = []; |
||||
let offset = 0; |
||||
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 |
||||
* 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 |
||||
* is passed back to the parser and re-walked because all the starts and ends get shifted. |
||||
* |
||||
* Also removes pure and view modifiers. |
||||
* |
||||
* them pre-bracketed simplifies the process. The process is broken down to 3 stages: |
||||
* 1. Parse the contract to get the AST tree |
||||
* 2. Remove all the view, pure and constant modifiers |
||||
* 3. Bracket all related unbracketed singleton statements |
||||
* @param {String} contract solidity code |
||||
* @return {String} contract |
||||
* @return {String} contract |
||||
*/ |
||||
module.exports.run = function r(contract) { |
||||
let keepRunning = true; |
||||
|
||||
while (keepRunning) { |
||||
try { |
||||
const ast = SolidityParser.parse(contract); |
||||
keepRunning = false; |
||||
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; |
||||
} |
||||
try { |
||||
const ast = SolidityParser.parse(contract); |
||||
contract = removeViewPureConst(ast, contract); |
||||
contract = bracketUnbStatements(ast, contract); |
||||
} catch (err) { |
||||
contract = err; |
||||
} |
||||
return contract; |
||||
}; |
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue