Merge pull request #22 from sc-forks/refactor-node-handling

Remove parse.js dummy node list, order nodes alphabetically

Note: This change exposes the fact that a number of cases aren't actually being checked in the parse table. Possible test-deficits / parse-table logic defects here.
pull/23/head
c-g-e-w-e-k-e- 8 years ago committed by GitHub
commit ec3135ef5c
  1. 250
      lib/parse.js

@ -1,220 +1,168 @@
/**
* Methods in this file walk the AST and call the instrumenter
* functions where appropriate, which determine where to inject events.
* (Listed in alphabetical order)
*/
const parse = {};
const instrumenter = require('./instrumenter');
// All the functions in this file do is walk the AST and call the instrumenter
// functions where appropriate, which determine where to inject events.
// Assign a dummy function to everything we might see in the AST
['AssemblyAssignment',
'AssemblyItem',
'AssemblyLocalBinding',
'AssignmentExpression',
'BinaryExpression',
'BlockStatement',
'BreakStatement',
'CallExpression',
'ConditionalExpression',
'ContinueStatement',
'ContractStatement',
'DebuggerStatement',
'DeclarativeExpression',
'DeclarativeExpressionList',
'DenominationLiteral',
'DoWhileStatement',
'EmptyStatement',
'EnumDeclaration',
'EventDeclaration',
'ExpressionStatement',
'ForInStatement',
'ForStatement',
'FunctionalAssemblyExpression',
'FunctionDeclaration',
'FunctionName',
'Identifier',
'IfStatement',
'ImportStatement',
'InformalParameter',
'InlineAssemblyBlock',
'InlineAssemblyStatement',
'IsStatement',
'LibraryStatement',
'Literal',
'MappingExpression',
'MemberExpression',
'ModifierArgument',
'ModifierDeclaration',
'ModifierName',
'Modifiers',
'NewExpression',
'PlaceholderStatement',
'PragmaStatement',
'Program',
'ReturnStatement',
'SequenceExpression',
'StateVariableDeclaration',
'StructDeclaration',
'ThisExpression',
'ThrowStatement',
'Type',
'UnaryExpression',
'UpdateExpression',
'UsingStatement',
'VariableDeclaration',
'VariableDeclarationTuple',
'VariableDeclarator',
'WhileStatement'].forEach(key => {
parse[key] = function dummyFunction() {};
});
// Override the dummy functions where we know we can do better.
parse.AssignmentExpression = function parseAssignmentExpression(contract, expression) {
instrumenter.instrumentStatement(contract, expression);
instrumenter.instrumentAssignmentExpression(contract, expression);
};
parse.ConditionalExpression = function parseConditionalExpression(contract, expression) {
instrumenter.instrumentStatement(contract, expression);
instrumenter.instrumentConditionalExpression(contract, expression);
};
parse.Modifiers = function parseModifier(contract, modifiers) {
if (modifiers) {
modifiers.forEach(modifier => {
parse[modifier.type](contract, modifier);
});
parse.BlockStatement = function parseBlockStatement(contract, expression) {
for (let x = 0; x < expression.body.length; x++) {
instrumenter.instrumentLine(contract, expression.body[x]);
parse[expression.body[x].type] &&
parse[expression.body[x].type](contract, expression.body[x]);
}
};
parse.ReturnStatement = function parseReturnStatement(contract, expression) {
instrumenter.instrumentStatement(contract, expression);
};
parse.NewExpression = function parseNewExpression(contract, expression) {
parse[expression.callee.type](contract, expression.callee);
};
parse.MemberExpression = function parseMemberExpression(contract, expression) {
parse[expression.object.type](contract, expression.object);
};
parse.CallExpression = function parseCallExpression(contract, expression) {
// It looks like in any given chain of call expressions, only the head callee is an Identifier
// node ... and we only want to instrument the statement once.
// In any given chain of call expressions, only the head callee is an Identifier node
if (expression.callee.type === 'Identifier') {
instrumenter.instrumentStatement(contract, expression);
parse[expression.callee.type] &&
parse[expression.callee.type](contract, expression.callee);
} else {
parse[expression.callee.type] &&
parse[expression.callee.type](contract, expression.callee);
}
};
parse.UnaryExpression = function parseUnaryExpression(contract, expression) {
parse[expression.argument.type](contract, expression.argument);
parse.ConditionalExpression = function parseConditionalExpression(contract, expression) {
instrumenter.instrumentStatement(contract, expression);
instrumenter.instrumentConditionalExpression(contract, expression);
};
parse.ThrowStatement = function parseThrowStatement(contract, expression) {
instrumenter.instrumentStatement(contract, expression);
parse.ContractStatement = function ParseContractStatement(contract, expression) {
parse.ContractOrLibraryStatement(contract, expression);
};
parse.IfStatement = function parseIfStatement(contract, expression) {
instrumenter.instrumentStatement(contract, expression);
instrumenter.instrumentIfStatement(contract, expression);
// We can't instrument
// if (x==1)
//
// So don't count x==1 as a statement - just the if as a whole.
// parse[expression.test.type](contract, expression.test)
parse[expression.consequent.type](contract, expression.consequent);
if (expression.alternate) {
parse[expression.alternate.type](contract, expression.alternate);
parse.ContractOrLibraryStatement = function parseContractOrLibraryStatement(contract, expression) {
// From the start of this contract statement, find the first '{', and inject there.
const injectionPoint = expression.start + contract.instrumented.slice(expression.start).indexOf('{') + 2;
if (contract.injectionPoints[injectionPoint]) {
contract.injectionPoints[expression.start + contract.instrumented.slice(expression.start).indexOf('{') + 2].push({
type: 'eventDefinition',
});
} else {
contract.injectionPoints[expression.start + contract.instrumented.slice(expression.start).indexOf('{') + 2] = [{
type: 'eventDefinition',
}];
}
if (expression.body) {
expression.body.forEach(construct => {
parse[construct.type] &&
parse[construct.type](contract, construct);
});
}
};
parse.ExpressionStatement = function parseExpressionStatement(contract, content) {
parse[content.expression.type] &&
parse[content.expression.type](contract, content.expression);
};
parse.VariableDeclarationTuple = function parseVariableDeclarationTuple(contract, expression) {
parse[expression.init.type](contract, expression.init);
};
parse.BlockStatement = function parseBlockStatement(contract, expression) {
for (let x = 0; x < expression.body.length; x++) {
instrumenter.instrumentLine(contract, expression.body[x]);
parse[expression.body[x].type](contract, expression.body[x]);
}
};
parse.VariableDeclaration = function parseVariableDeclaration(contract, expression) {
parse.ForStatement = function parseForStatement(contract, expression) {
instrumenter.instrumentStatement(contract, expression);
if (expression.declarations.length > 1) {
console.log('more than one declaration');
}
parse[expression.declarations[0].id.type](contract, expression.declarations[0].id);
};
parse.UsingStatement = function parseUsingStatement(contract, expression) {
parse[expression.for.type](contract, expression.for);
parse[expression.body.type] &&
parse[expression.body.type](contract, expression.body);
};
parse.FunctionDeclaration = function parseFunctionDeclaration(contract, expression) {
parse.Modifiers(contract, expression.modifiers);
if (expression.body) {
instrumenter.instrumentFunctionDeclaration(contract, expression);
parse[expression.body.type] &&
parse[expression.body.type](contract, expression.body);
}
};
parse.ContractOrLibraryStatement = function parseContractOrLibraryStatement(contract, expression) {
// Inject our coverage event if we're covering
// This is harder because of where .start and .end represent, and how documented comments are validated
// by solc upon compilation. From the start of this contract statement, find the first '{', and inject
// there.
const injectionPoint = expression.start + contract.instrumented.slice(expression.start).indexOf('{') + 2;
if (contract.injectionPoints[injectionPoint]) {
contract.injectionPoints[expression.start + contract.instrumented.slice(expression.start).indexOf('{') + 2].push({
type: 'eventDefinition',
});
} else {
contract.injectionPoints[expression.start + contract.instrumented.slice(expression.start).indexOf('{') + 2] = [{
type: 'eventDefinition',
}];
}
parse.IfStatement = function parseIfStatement(contract, expression) {
instrumenter.instrumentStatement(contract, expression);
instrumenter.instrumentIfStatement(contract, expression);
parse[expression.consequent.type] &&
parse[expression.consequent.type](contract, expression.consequent);
if (expression.body) {
expression.body.forEach(construct => {
parse[construct.type](contract, construct);
});
if (expression.alternate) {
parse[expression.alternate.type] &&
parse[expression.alternate.type](contract, expression.alternate);
}
};
parse.ContractStatement = function ParseContractStatement(contract, expression) {
parse.LibraryStatement = function parseLibraryStatement(contract, expression) {
parse.ContractOrLibraryStatement(contract, expression);
};
parse.LibraryStatement = function parseLibraryStatement(contract, expression) {
parse.ContractOrLibraryStatement(contract, expression);
parse.MemberExpression = function parseMemberExpression(contract, expression) {
parse[expression.object.type] &&
parse[expression.object.type](contract, expression.object);
};
parse.Modifiers = function parseModifier(contract, modifiers) {
if (modifiers) {
modifiers.forEach(modifier => {
parse[modifier.type] && parse[modifier.type](contract, modifier);
});
}
};
parse.ModifierDeclaration = function parseModifierDeclaration(contract, expression) {
instrumenter.instrumentFunctionDeclaration(contract, expression);
parse[expression.body.type] &&
parse[expression.body.type](contract, expression.body);
};
parse.NewExpression = function parseNewExpression(contract, expression) {
parse[expression.callee.type] &&
parse[expression.callee.type](contract, expression.callee);
};
parse.Program = function parseProgram(contract, expression) {
expression.body.forEach(construct => {
parse[construct.type] &&
parse[construct.type](contract, construct);
});
};
parse.WhileStatement = function parseWhileStatement(contract, expression) {
parse.ReturnStatement = function parseReturnStatement(contract, expression) {
instrumenter.instrumentStatement(contract, expression);
parse[expression.body.type](contract, expression.body);
};
parse.ForStatement = function parseForStatement(contract, expression) {
parse.ThrowStatement = function parseThrowStatement(contract, expression) {
instrumenter.instrumentStatement(contract, expression);
};
parse.UnaryExpression = function parseUnaryExpression(contract, expression) {
parse[expression.argument.type] &&
parse[expression.argument.type](contract, expression.argument);
};
parse.UsingStatement = function parseUsingStatement(contract, expression) {
parse[expression.for.type] &&
parse[expression.for.type](contract, expression.for);
};
parse.VariableDeclaration = function parseVariableDeclaration(contract, expression) {
instrumenter.instrumentStatement(contract, expression);
parse[expression.declarations[0].id.type] &&
parse[expression.declarations[0].id.type](contract, expression.declarations[0].id);
};
parse.VariableDeclarationTuple = function parseVariableDeclarationTuple(contract, expression) {
parse[expression.init.type] &&
parse[expression.init.type](contract, expression.init);
};
parse.WhileStatement = function parseWhileStatement(contract, expression) {
instrumenter.instrumentStatement(contract, expression);
parse[expression.body.type] &&
parse[expression.body.type](contract, expression.body);
};

Loading…
Cancel
Save