mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Source location as part of AST.
This commit is contained in:
parent
980abfe52a
commit
c55584d3e2
@ -42,12 +42,17 @@ void ASTJsonConverter::addKeyValue(Json::Value& _obj, string const& _key, string
|
|||||||
_obj[_key] = _val;
|
_obj[_key] = _val;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTJsonConverter::addJsonNode(string const& _nodeName,
|
void ASTJsonConverter::addJsonNode(
|
||||||
|
ASTNode const& _node,
|
||||||
|
string const& _nodeName,
|
||||||
initializer_list<pair<string const, string const>> _list,
|
initializer_list<pair<string const, string const>> _list,
|
||||||
bool _hasChildren = false)
|
bool _hasChildren = false
|
||||||
|
)
|
||||||
{
|
{
|
||||||
Json::Value node;
|
Json::Value node;
|
||||||
|
|
||||||
|
node["id"] = reinterpret_cast<Json::UInt64>(&_node);
|
||||||
|
node["src"] = sourceLocationToString(_node.location());
|
||||||
node["name"] = _nodeName;
|
node["name"] = _nodeName;
|
||||||
if (_list.size() != 0)
|
if (_list.size() != 0)
|
||||||
{
|
{
|
||||||
@ -68,7 +73,21 @@ void ASTJsonConverter::addJsonNode(string const& _nodeName,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ASTJsonConverter::ASTJsonConverter(ASTNode const& _ast): m_ast(&_ast)
|
string ASTJsonConverter::sourceLocationToString(SourceLocation const& _location) const
|
||||||
|
{
|
||||||
|
int sourceIndex{-1};
|
||||||
|
if (_location.sourceName && m_sourceIndices.count(*_location.sourceName))
|
||||||
|
sourceIndex = m_sourceIndices.at(*_location.sourceName);
|
||||||
|
int length = -1;
|
||||||
|
if (_location.start >= 0 && _location.end >= 0)
|
||||||
|
length = _location.end - _location.start;
|
||||||
|
return std::to_string(_location.start) + ":" + std::to_string(length) + ":" + std::to_string(sourceIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASTJsonConverter::ASTJsonConverter(
|
||||||
|
ASTNode const& _ast,
|
||||||
|
map<string, unsigned> const& _sourceIndices
|
||||||
|
): m_ast(&_ast), m_sourceIndices(_sourceIndices)
|
||||||
{
|
{
|
||||||
Json::Value children(Json::arrayValue);
|
Json::Value children(Json::arrayValue);
|
||||||
|
|
||||||
@ -91,31 +110,31 @@ Json::Value const& ASTJsonConverter::json()
|
|||||||
|
|
||||||
bool ASTJsonConverter::visit(ImportDirective const& _node)
|
bool ASTJsonConverter::visit(ImportDirective const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("Import", { make_pair("file", _node.path())});
|
addJsonNode(_node, "Import", { make_pair("file", _node.path())});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASTJsonConverter::visit(ContractDefinition const& _node)
|
bool ASTJsonConverter::visit(ContractDefinition const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("Contract", { make_pair("name", _node.name()) }, true);
|
addJsonNode(_node, "Contract", { make_pair("name", _node.name()) }, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASTJsonConverter::visit(StructDefinition const& _node)
|
bool ASTJsonConverter::visit(StructDefinition const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("Struct", { make_pair("name", _node.name()) }, true);
|
addJsonNode(_node, "Struct", { make_pair("name", _node.name()) }, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASTJsonConverter::visit(ParameterList const&)
|
bool ASTJsonConverter::visit(ParameterList const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("ParameterList", {}, true);
|
addJsonNode(_node, "ParameterList", {}, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASTJsonConverter::visit(FunctionDefinition const& _node)
|
bool ASTJsonConverter::visit(FunctionDefinition const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("Function",
|
addJsonNode(_node, "Function",
|
||||||
{ make_pair("name", _node.name()),
|
{ make_pair("name", _node.name()),
|
||||||
make_pair("public", boost::lexical_cast<std::string>(_node.isPublic())),
|
make_pair("public", boost::lexical_cast<std::string>(_node.isPublic())),
|
||||||
make_pair("const", boost::lexical_cast<std::string>(_node.isDeclaredConst())) },
|
make_pair("const", boost::lexical_cast<std::string>(_node.isDeclaredConst())) },
|
||||||
@ -125,7 +144,7 @@ bool ASTJsonConverter::visit(FunctionDefinition const& _node)
|
|||||||
|
|
||||||
bool ASTJsonConverter::visit(VariableDeclaration const& _node)
|
bool ASTJsonConverter::visit(VariableDeclaration const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("VariableDeclaration", {
|
addJsonNode(_node, "VariableDeclaration", {
|
||||||
make_pair("name", _node.name()),
|
make_pair("name", _node.name()),
|
||||||
make_pair("name", _node.name()),
|
make_pair("name", _node.name()),
|
||||||
}, true);
|
}, true);
|
||||||
@ -139,114 +158,114 @@ bool ASTJsonConverter::visit(TypeName const&)
|
|||||||
|
|
||||||
bool ASTJsonConverter::visit(ElementaryTypeName const& _node)
|
bool ASTJsonConverter::visit(ElementaryTypeName const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("ElementaryTypeName", { make_pair("name", _node.typeName().toString()) });
|
addJsonNode(_node, "ElementaryTypeName", { make_pair("name", _node.typeName().toString()) });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASTJsonConverter::visit(UserDefinedTypeName const& _node)
|
bool ASTJsonConverter::visit(UserDefinedTypeName const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("UserDefinedTypeName", {
|
addJsonNode(_node, "UserDefinedTypeName", {
|
||||||
make_pair("name", boost::algorithm::join(_node.namePath(), "."))
|
make_pair("name", boost::algorithm::join(_node.namePath(), "."))
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASTJsonConverter::visit(Mapping const&)
|
bool ASTJsonConverter::visit(Mapping const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("Mapping", {}, true);
|
addJsonNode(_node, "Mapping", {}, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASTJsonConverter::visit(InlineAssembly const&)
|
bool ASTJsonConverter::visit(InlineAssembly const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("InlineAssembly", {}, true);
|
addJsonNode(_node, "InlineAssembly", {}, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASTJsonConverter::visit(Block const&)
|
bool ASTJsonConverter::visit(Block const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("Block", {}, true);
|
addJsonNode(_node, "Block", {}, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASTJsonConverter::visit(IfStatement const&)
|
bool ASTJsonConverter::visit(IfStatement const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("IfStatement", {}, true);
|
addJsonNode(_node, "IfStatement", {}, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASTJsonConverter::visit(WhileStatement const&)
|
bool ASTJsonConverter::visit(WhileStatement const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("WhileStatement", {}, true);
|
addJsonNode(_node, "WhileStatement", {}, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASTJsonConverter::visit(ForStatement const&)
|
bool ASTJsonConverter::visit(ForStatement const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("ForStatement", {}, true);
|
addJsonNode(_node, "ForStatement", {}, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASTJsonConverter::visit(Continue const&)
|
bool ASTJsonConverter::visit(Continue const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("Continue", {});
|
addJsonNode(_node, "Continue", {});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASTJsonConverter::visit(Break const&)
|
bool ASTJsonConverter::visit(Break const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("Break", {});
|
addJsonNode(_node, "Break", {});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASTJsonConverter::visit(Return const&)
|
bool ASTJsonConverter::visit(Return const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("Return", {}, true);;
|
addJsonNode(_node, "Return", {}, true);;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASTJsonConverter::visit(Throw const&)
|
bool ASTJsonConverter::visit(Throw const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("Throw", {}, true);;
|
addJsonNode(_node, "Throw", {}, true);;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASTJsonConverter::visit(VariableDeclarationStatement const&)
|
bool ASTJsonConverter::visit(VariableDeclarationStatement const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("VariableDefinition", {}, true);
|
addJsonNode(_node, "VariableDefinition", {}, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASTJsonConverter::visit(ExpressionStatement const&)
|
bool ASTJsonConverter::visit(ExpressionStatement const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("ExpressionStatement", {}, true);
|
addJsonNode(_node, "ExpressionStatement", {}, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASTJsonConverter::visit(Conditional const&)
|
bool ASTJsonConverter::visit(Conditional const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("Conditional", {}, true);
|
addJsonNode(_node, "Conditional", {}, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASTJsonConverter::visit(Assignment const& _node)
|
bool ASTJsonConverter::visit(Assignment const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("Assignment",
|
addJsonNode(_node, "Assignment",
|
||||||
{ make_pair("operator", Token::toString(_node.assignmentOperator())),
|
{ make_pair("operator", Token::toString(_node.assignmentOperator())),
|
||||||
make_pair("type", type(_node)) },
|
make_pair("type", type(_node)) },
|
||||||
true);
|
true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASTJsonConverter::visit(TupleExpression const&)
|
bool ASTJsonConverter::visit(TupleExpression const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("TupleExpression",{}, true);
|
addJsonNode(_node, "TupleExpression",{}, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASTJsonConverter::visit(UnaryOperation const& _node)
|
bool ASTJsonConverter::visit(UnaryOperation const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("UnaryOperation",
|
addJsonNode(_node, "UnaryOperation",
|
||||||
{ make_pair("prefix", boost::lexical_cast<std::string>(_node.isPrefixOperation())),
|
{ make_pair("prefix", boost::lexical_cast<std::string>(_node.isPrefixOperation())),
|
||||||
make_pair("operator", Token::toString(_node.getOperator())),
|
make_pair("operator", Token::toString(_node.getOperator())),
|
||||||
make_pair("type", type(_node)) },
|
make_pair("type", type(_node)) },
|
||||||
@ -256,7 +275,7 @@ bool ASTJsonConverter::visit(UnaryOperation const& _node)
|
|||||||
|
|
||||||
bool ASTJsonConverter::visit(BinaryOperation const& _node)
|
bool ASTJsonConverter::visit(BinaryOperation const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("BinaryOperation", {
|
addJsonNode(_node, "BinaryOperation", {
|
||||||
make_pair("operator", Token::toString(_node.getOperator())),
|
make_pair("operator", Token::toString(_node.getOperator())),
|
||||||
make_pair("type", type(_node))
|
make_pair("type", type(_node))
|
||||||
}, true);
|
}, true);
|
||||||
@ -265,7 +284,7 @@ bool ASTJsonConverter::visit(BinaryOperation const& _node)
|
|||||||
|
|
||||||
bool ASTJsonConverter::visit(FunctionCall const& _node)
|
bool ASTJsonConverter::visit(FunctionCall const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("FunctionCall", {
|
addJsonNode(_node, "FunctionCall", {
|
||||||
make_pair("type_conversion", boost::lexical_cast<std::string>(_node.annotation().isTypeConversion)),
|
make_pair("type_conversion", boost::lexical_cast<std::string>(_node.annotation().isTypeConversion)),
|
||||||
make_pair("type", type(_node))
|
make_pair("type", type(_node))
|
||||||
}, true);
|
}, true);
|
||||||
@ -274,13 +293,13 @@ bool ASTJsonConverter::visit(FunctionCall const& _node)
|
|||||||
|
|
||||||
bool ASTJsonConverter::visit(NewExpression const& _node)
|
bool ASTJsonConverter::visit(NewExpression const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("NewExpression", { make_pair("type", type(_node)) }, true);
|
addJsonNode(_node, "NewExpression", { make_pair("type", type(_node)) }, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASTJsonConverter::visit(MemberAccess const& _node)
|
bool ASTJsonConverter::visit(MemberAccess const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("MemberAccess",
|
addJsonNode(_node, "MemberAccess",
|
||||||
{ make_pair("member_name", _node.memberName()),
|
{ make_pair("member_name", _node.memberName()),
|
||||||
make_pair("type", type(_node)) },
|
make_pair("type", type(_node)) },
|
||||||
true);
|
true);
|
||||||
@ -289,20 +308,20 @@ bool ASTJsonConverter::visit(MemberAccess const& _node)
|
|||||||
|
|
||||||
bool ASTJsonConverter::visit(IndexAccess const& _node)
|
bool ASTJsonConverter::visit(IndexAccess const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("IndexAccess", { make_pair("type", type(_node)) }, true);
|
addJsonNode(_node, "IndexAccess", { make_pair("type", type(_node)) }, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASTJsonConverter::visit(Identifier const& _node)
|
bool ASTJsonConverter::visit(Identifier const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("Identifier",
|
addJsonNode(_node, "Identifier",
|
||||||
{ make_pair("value", _node.name()), make_pair("type", type(_node)) });
|
{ make_pair("value", _node.name()), make_pair("type", type(_node)) });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASTJsonConverter::visit(ElementaryTypeNameExpression const& _node)
|
bool ASTJsonConverter::visit(ElementaryTypeNameExpression const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode("ElementaryTypenameExpression",
|
addJsonNode(_node, "ElementaryTypenameExpression",
|
||||||
{ make_pair("value", _node.typeName().toString()), make_pair("type", type(_node)) });
|
{ make_pair("value", _node.typeName().toString()), make_pair("type", type(_node)) });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -310,7 +329,7 @@ bool ASTJsonConverter::visit(ElementaryTypeNameExpression const& _node)
|
|||||||
bool ASTJsonConverter::visit(Literal const& _node)
|
bool ASTJsonConverter::visit(Literal const& _node)
|
||||||
{
|
{
|
||||||
char const* tokenString = Token::toString(_node.token());
|
char const* tokenString = Token::toString(_node.token());
|
||||||
addJsonNode("Literal",
|
addJsonNode(_node, "Literal",
|
||||||
{ make_pair("string", (tokenString) ? tokenString : "null"),
|
{ make_pair("string", (tokenString) ? tokenString : "null"),
|
||||||
make_pair("value", _node.value()),
|
make_pair("value", _node.value()),
|
||||||
make_pair("type", type(_node)) });
|
make_pair("type", type(_node)) });
|
||||||
|
@ -42,7 +42,11 @@ class ASTJsonConverter: public ASTConstVisitor
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// Create a converter to JSON for the given abstract syntax tree.
|
/// Create a converter to JSON for the given abstract syntax tree.
|
||||||
explicit ASTJsonConverter(ASTNode const& _ast);
|
/// @a _sourceIndices is used to abbreviate source names in source locations.
|
||||||
|
explicit ASTJsonConverter(
|
||||||
|
ASTNode const& _ast,
|
||||||
|
std::map<std::string, unsigned> const& _sourceIndices = std::map<std::string, unsigned>()
|
||||||
|
);
|
||||||
/// Output the json representation of the AST to _stream.
|
/// Output the json representation of the AST to _stream.
|
||||||
void print(std::ostream& _stream);
|
void print(std::ostream& _stream);
|
||||||
Json::Value const& json();
|
Json::Value const& json();
|
||||||
@ -118,9 +122,13 @@ public:
|
|||||||
private:
|
private:
|
||||||
void process();
|
void process();
|
||||||
void addKeyValue(Json::Value& _obj, std::string const& _key, std::string const& _val);
|
void addKeyValue(Json::Value& _obj, std::string const& _key, std::string const& _val);
|
||||||
void addJsonNode(std::string const& _nodeName,
|
void addJsonNode(
|
||||||
|
ASTNode const& _node,
|
||||||
|
std::string const& _nodeName,
|
||||||
std::initializer_list<std::pair<std::string const, std::string const>> _list,
|
std::initializer_list<std::pair<std::string const, std::string const>> _list,
|
||||||
bool _hasChildren);
|
bool _hasChildren
|
||||||
|
);
|
||||||
|
std::string sourceLocationToString(SourceLocation const& _location) const;
|
||||||
std::string type(Expression const& _expression);
|
std::string type(Expression const& _expression);
|
||||||
std::string type(VariableDeclaration const& _varDecl);
|
std::string type(VariableDeclaration const& _varDecl);
|
||||||
inline void goUp()
|
inline void goUp()
|
||||||
@ -132,8 +140,8 @@ private:
|
|||||||
bool processed = false;
|
bool processed = false;
|
||||||
Json::Value m_astJson;
|
Json::Value m_astJson;
|
||||||
std::stack<Json::Value*> m_jsonNodePtrs;
|
std::stack<Json::Value*> m_jsonNodePtrs;
|
||||||
std::string m_source;
|
|
||||||
ASTNode const* m_ast;
|
ASTNode const* m_ast;
|
||||||
|
std::map<std::string, unsigned> const& m_sourceIndices;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -279,6 +279,28 @@ eth::AssemblyItems const* CompilerStack::runtimeAssemblyItems(string const& _con
|
|||||||
return currentContract.compiler ? &contract(_contractName).compiler->runtimeAssemblyItems() : nullptr;
|
return currentContract.compiler ? &contract(_contractName).compiler->runtimeAssemblyItems() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string const* CompilerStack::sourceMapping(string const& _contractName) const
|
||||||
|
{
|
||||||
|
Contract const& c = contract(_contractName);
|
||||||
|
if (!c.sourceMapping)
|
||||||
|
{
|
||||||
|
if (auto items = assemblyItems(_contractName))
|
||||||
|
c.sourceMapping.reset(new string(computeSourceMapping(*items)));
|
||||||
|
}
|
||||||
|
return c.sourceMapping.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
string const* CompilerStack::runtimeSourceMapping(string const& _contractName) const
|
||||||
|
{
|
||||||
|
Contract const& c = contract(_contractName);
|
||||||
|
if (!c.runtimeSourceMapping)
|
||||||
|
{
|
||||||
|
if (auto items = runtimeAssemblyItems(_contractName))
|
||||||
|
c.runtimeSourceMapping.reset(new string(computeSourceMapping(*items)));
|
||||||
|
}
|
||||||
|
return c.runtimeSourceMapping.get();
|
||||||
|
}
|
||||||
|
|
||||||
eth::LinkerObject const& CompilerStack::object(string const& _contractName) const
|
eth::LinkerObject const& CompilerStack::object(string const& _contractName) const
|
||||||
{
|
{
|
||||||
return contract(_contractName).object;
|
return contract(_contractName).object;
|
||||||
@ -315,6 +337,22 @@ Json::Value CompilerStack::streamAssembly(ostream& _outStream, string const& _co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vector<string> CompilerStack::sourceNames() const
|
||||||
|
{
|
||||||
|
vector<string> names;
|
||||||
|
for (auto const& s: m_sources)
|
||||||
|
names.push_back(s.first);
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
|
map<string, unsigned> CompilerStack::sourceIndices() const
|
||||||
|
{
|
||||||
|
map<string, unsigned> indices;
|
||||||
|
for (auto const& s: m_sources)
|
||||||
|
indices[s.first] = indices.size();
|
||||||
|
return indices;
|
||||||
|
}
|
||||||
|
|
||||||
string const& CompilerStack::interface(string const& _contractName) const
|
string const& CompilerStack::interface(string const& _contractName) const
|
||||||
{
|
{
|
||||||
return metadata(_contractName, DocumentationType::ABIInterface);
|
return metadata(_contractName, DocumentationType::ABIInterface);
|
||||||
@ -604,3 +642,76 @@ CompilerStack::Source const& CompilerStack::source(string const& _sourceName) co
|
|||||||
|
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string CompilerStack::computeSourceMapping(eth::AssemblyItems const& _items) const
|
||||||
|
{
|
||||||
|
string ret;
|
||||||
|
map<string, unsigned> sourceIndicesMap = sourceIndices();
|
||||||
|
int prevStart = -1;
|
||||||
|
int prevLength = -1;
|
||||||
|
int prevSourceIndex = -1;
|
||||||
|
char prevJump = 0;
|
||||||
|
for (auto const& item: _items)
|
||||||
|
{
|
||||||
|
if (!ret.empty())
|
||||||
|
ret += ";";
|
||||||
|
|
||||||
|
SourceLocation const& location = item.location();
|
||||||
|
int length = location.start != -1 && location.end != -1 ? location.end - location.start : -1;
|
||||||
|
int sourceIndex =
|
||||||
|
location.sourceName && sourceIndicesMap.count(*location.sourceName) ?
|
||||||
|
sourceIndicesMap.at(*location.sourceName) :
|
||||||
|
-1;
|
||||||
|
char jump = '-';
|
||||||
|
if (item.getJumpType() == eth::AssemblyItem::JumpType::IntoFunction)
|
||||||
|
jump = 'i';
|
||||||
|
else if (item.getJumpType() == eth::AssemblyItem::JumpType::OutOfFunction)
|
||||||
|
jump = 'o';
|
||||||
|
|
||||||
|
unsigned components = 4;
|
||||||
|
if (jump == prevJump)
|
||||||
|
{
|
||||||
|
components--;
|
||||||
|
if (sourceIndex == prevSourceIndex)
|
||||||
|
{
|
||||||
|
components--;
|
||||||
|
if (length == prevLength)
|
||||||
|
{
|
||||||
|
components--;
|
||||||
|
if (location.start == prevStart)
|
||||||
|
components--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (components-- > 0)
|
||||||
|
{
|
||||||
|
if (location.start != prevStart)
|
||||||
|
ret += std::to_string(location.start);
|
||||||
|
if (components-- > 0)
|
||||||
|
{
|
||||||
|
ret += ':';
|
||||||
|
if (length != prevLength)
|
||||||
|
ret += std::to_string(length);
|
||||||
|
if (components-- > 0)
|
||||||
|
{
|
||||||
|
ret += ':';
|
||||||
|
if (sourceIndex != prevSourceIndex)
|
||||||
|
ret += std::to_string(sourceIndex);
|
||||||
|
if (components-- > 0)
|
||||||
|
{
|
||||||
|
ret += ':';
|
||||||
|
if (jump != prevJump)
|
||||||
|
ret += jump;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prevStart = location.start;
|
||||||
|
prevLength = length;
|
||||||
|
prevSourceIndex = sourceIndex;
|
||||||
|
prevJump = jump;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@ -142,6 +142,12 @@ public:
|
|||||||
eth::AssemblyItems const* assemblyItems(std::string const& _contractName = "") const;
|
eth::AssemblyItems const* assemblyItems(std::string const& _contractName = "") const;
|
||||||
/// @returns runtime contract assembly items
|
/// @returns runtime contract assembly items
|
||||||
eth::AssemblyItems const* runtimeAssemblyItems(std::string const& _contractName = "") const;
|
eth::AssemblyItems const* runtimeAssemblyItems(std::string const& _contractName = "") const;
|
||||||
|
/// @returns the string that provides a mapping between bytecode and sourcecode or a nullptr
|
||||||
|
/// if the contract does not (yet) have bytecode.
|
||||||
|
std::string const* sourceMapping(std::string const& _contractName = "") const;
|
||||||
|
/// @returns the string that provides a mapping between runtime bytecode and sourcecode.
|
||||||
|
/// if the contract does not (yet) have bytecode.
|
||||||
|
std::string const* runtimeSourceMapping(std::string const& _contractName = "") const;
|
||||||
/// @returns hash of the runtime bytecode for the contract, i.e. the code that is
|
/// @returns hash of the runtime bytecode for the contract, i.e. the code that is
|
||||||
/// returned by the constructor or the zero-h256 if the contract still needs to be linked or
|
/// returned by the constructor or the zero-h256 if the contract still needs to be linked or
|
||||||
/// does not have runtime code.
|
/// does not have runtime code.
|
||||||
@ -153,6 +159,11 @@ public:
|
|||||||
/// Prerequisite: Successful compilation.
|
/// Prerequisite: Successful compilation.
|
||||||
Json::Value streamAssembly(std::ostream& _outStream, std::string const& _contractName = "", StringMap _sourceCodes = StringMap(), bool _inJsonFormat = false) const;
|
Json::Value streamAssembly(std::ostream& _outStream, std::string const& _contractName = "", StringMap _sourceCodes = StringMap(), bool _inJsonFormat = false) const;
|
||||||
|
|
||||||
|
/// @returns the list of sources (paths) used
|
||||||
|
std::vector<std::string> sourceNames() const;
|
||||||
|
/// @returns a mapping assigning each source name its index inside the vector returned
|
||||||
|
/// by sourceNames().
|
||||||
|
std::map<std::string, unsigned> sourceIndices() const;
|
||||||
/// @returns a string representing the contract interface in JSON.
|
/// @returns a string representing the contract interface in JSON.
|
||||||
/// Prerequisite: Successful call to parse or compile.
|
/// Prerequisite: Successful call to parse or compile.
|
||||||
std::string const& interface(std::string const& _contractName = "") const;
|
std::string const& interface(std::string const& _contractName = "") const;
|
||||||
@ -196,9 +207,8 @@ private:
|
|||||||
{
|
{
|
||||||
std::shared_ptr<Scanner> scanner;
|
std::shared_ptr<Scanner> scanner;
|
||||||
std::shared_ptr<SourceUnit> ast;
|
std::shared_ptr<SourceUnit> ast;
|
||||||
std::string interface;
|
|
||||||
bool isLibrary = false;
|
bool isLibrary = false;
|
||||||
void reset() { scanner.reset(); ast.reset(); interface.clear(); }
|
void reset() { scanner.reset(); ast.reset(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Contract
|
struct Contract
|
||||||
@ -212,6 +222,8 @@ private:
|
|||||||
mutable std::unique_ptr<std::string const> solidityInterface;
|
mutable std::unique_ptr<std::string const> solidityInterface;
|
||||||
mutable std::unique_ptr<std::string const> userDocumentation;
|
mutable std::unique_ptr<std::string const> userDocumentation;
|
||||||
mutable std::unique_ptr<std::string const> devDocumentation;
|
mutable std::unique_ptr<std::string const> devDocumentation;
|
||||||
|
mutable std::unique_ptr<std::string const> sourceMapping;
|
||||||
|
mutable std::unique_ptr<std::string const> runtimeSourceMapping;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Loads the missing sources from @a _ast (named @a _path) using the callback
|
/// Loads the missing sources from @a _ast (named @a _path) using the callback
|
||||||
@ -236,6 +248,8 @@ private:
|
|||||||
Contract const& contract(std::string const& _contractName = "") const;
|
Contract const& contract(std::string const& _contractName = "") const;
|
||||||
Source const& source(std::string const& _sourceName = "") const;
|
Source const& source(std::string const& _sourceName = "") const;
|
||||||
|
|
||||||
|
std::string computeSourceMapping(eth::AssemblyItems const& _items) const;
|
||||||
|
|
||||||
struct Remapping
|
struct Remapping
|
||||||
{
|
{
|
||||||
std::string context;
|
std::string context;
|
||||||
|
@ -86,6 +86,8 @@ static set<string> const g_combinedJsonArgs{
|
|||||||
"bin",
|
"bin",
|
||||||
"bin-runtime",
|
"bin-runtime",
|
||||||
"clone-bin",
|
"clone-bin",
|
||||||
|
"srcmap",
|
||||||
|
"srcmap-runtime",
|
||||||
"opcodes",
|
"opcodes",
|
||||||
"abi",
|
"abi",
|
||||||
"interface",
|
"interface",
|
||||||
@ -658,6 +660,16 @@ void CommandLineInterface::handleCombinedJSON()
|
|||||||
ostringstream unused;
|
ostringstream unused;
|
||||||
contractData["asm"] = m_compiler->streamAssembly(unused, contractName, m_sourceCodes, true);
|
contractData["asm"] = m_compiler->streamAssembly(unused, contractName, m_sourceCodes, true);
|
||||||
}
|
}
|
||||||
|
if (requests.count("srcmap"))
|
||||||
|
{
|
||||||
|
auto map = m_compiler->sourceMapping(contractName);
|
||||||
|
contractData["srcmap"] = map ? *map : "";
|
||||||
|
}
|
||||||
|
if (requests.count("srcmap-runtime"))
|
||||||
|
{
|
||||||
|
auto map = m_compiler->runtimeSourceMapping(contractName);
|
||||||
|
contractData["srcmap"] = map ? *map : "";
|
||||||
|
}
|
||||||
if (requests.count("devdoc"))
|
if (requests.count("devdoc"))
|
||||||
contractData["devdoc"] = m_compiler->metadata(contractName, DocumentationType::NatspecDev);
|
contractData["devdoc"] = m_compiler->metadata(contractName, DocumentationType::NatspecDev);
|
||||||
if (requests.count("userdoc"))
|
if (requests.count("userdoc"))
|
||||||
@ -665,12 +677,22 @@ void CommandLineInterface::handleCombinedJSON()
|
|||||||
output["contracts"][contractName] = contractData;
|
output["contracts"][contractName] = contractData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool needsSourceList = requests.count("ast") || requests.count("srcmap") || requests.count("srcmap-runtime");
|
||||||
|
if (needsSourceList)
|
||||||
|
{
|
||||||
|
// Indices into this array are used to abbreviate source names in source locations.
|
||||||
|
output["sourceList"] = Json::Value(Json::arrayValue);
|
||||||
|
|
||||||
|
for (auto const& source: m_compiler->sourceNames())
|
||||||
|
output["sourceList"].append(source);
|
||||||
|
}
|
||||||
|
|
||||||
if (requests.count("ast"))
|
if (requests.count("ast"))
|
||||||
{
|
{
|
||||||
output["sources"] = Json::Value(Json::objectValue);
|
output["sources"] = Json::Value(Json::objectValue);
|
||||||
for (auto const& sourceCode: m_sourceCodes)
|
for (auto const& sourceCode: m_sourceCodes)
|
||||||
{
|
{
|
||||||
ASTJsonConverter converter(m_compiler->ast(sourceCode.first));
|
ASTJsonConverter converter(m_compiler->ast(sourceCode.first), m_compiler->sourceIndices());
|
||||||
output["sources"][sourceCode.first] = Json::Value(Json::objectValue);
|
output["sources"][sourceCode.first] = Json::Value(Json::objectValue);
|
||||||
output["sources"][sourceCode.first]["AST"] = converter.json();
|
output["sources"][sourceCode.first]["AST"] = converter.json();
|
||||||
}
|
}
|
||||||
|
@ -214,6 +214,10 @@ string compile(StringMap const& _sources, bool _optimize, CStyleReadFileCallback
|
|||||||
contractData["opcodes"] = solidity::disassemble(compiler.object(contractName).bytecode);
|
contractData["opcodes"] = solidity::disassemble(compiler.object(contractName).bytecode);
|
||||||
contractData["functionHashes"] = functionHashes(compiler.contractDefinition(contractName));
|
contractData["functionHashes"] = functionHashes(compiler.contractDefinition(contractName));
|
||||||
contractData["gasEstimates"] = estimateGas(compiler, contractName);
|
contractData["gasEstimates"] = estimateGas(compiler, contractName);
|
||||||
|
auto sourceMap = compiler.sourceMapping(contractName);
|
||||||
|
contractData["srcmap"] = sourceMap ? *sourceMap : "";
|
||||||
|
auto runtimeSourceMap = compiler.sourceMapping(contractName);
|
||||||
|
contractData["srcmap-runtime"] = runtimeSourceMap ? *runtimeSourceMap : "";
|
||||||
ostringstream unused;
|
ostringstream unused;
|
||||||
contractData["assembly"] = compiler.streamAssembly(unused, contractName, _sources, true);
|
contractData["assembly"] = compiler.streamAssembly(unused, contractName, _sources, true);
|
||||||
output["contracts"][contractName] = contractData;
|
output["contracts"][contractName] = contractData;
|
||||||
@ -235,12 +239,13 @@ string compile(StringMap const& _sources, bool _optimize, CStyleReadFileCallback
|
|||||||
output["formal"]["errors"] = errors;
|
output["formal"]["errors"] = errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Indices into this array are used to abbreviate source names in source locations.
|
||||||
|
output["sourceList"] = Json::Value(Json::arrayValue);
|
||||||
|
for (auto const& source: compiler.sourceNames())
|
||||||
|
output["sourceList"].append(source);
|
||||||
output["sources"] = Json::Value(Json::objectValue);
|
output["sources"] = Json::Value(Json::objectValue);
|
||||||
for (auto const& source: _sources)
|
for (auto const& source: compiler.sourceNames())
|
||||||
{
|
output["sources"][source]["AST"] = ASTJsonConverter(compiler.ast(source), compiler.sourceIndices()).json();
|
||||||
output["sources"][source.first] = Json::Value(Json::objectValue);
|
|
||||||
output["sources"][source.first]["AST"] = ASTJsonConverter(compiler.ast(source.first)).json();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Json::FastWriter().write(output);
|
return Json::FastWriter().write(output);
|
||||||
|
69
test/libsolidity/ASTJSON.cpp
Normal file
69
test/libsolidity/ASTJSON.cpp
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
This file is part of cpp-ethereum.
|
||||||
|
|
||||||
|
cpp-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
cpp-ethereum is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @author Christian <c@ethdev.com>
|
||||||
|
* @date 2016
|
||||||
|
* Tests for the json ast output.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#include <libsolidity/interface/Exceptions.h>
|
||||||
|
#include <libsolidity/interface/CompilerStack.h>
|
||||||
|
#include <libsolidity/ast/ASTJsonConverter.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace dev
|
||||||
|
{
|
||||||
|
namespace solidity
|
||||||
|
{
|
||||||
|
namespace test
|
||||||
|
{
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE(SolidityASTJSON)
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(smoke_test)
|
||||||
|
{
|
||||||
|
CompilerStack c;
|
||||||
|
c.addSource("a", "contract C {}");
|
||||||
|
c.parse();
|
||||||
|
map<string, unsigned> sourceIndices;
|
||||||
|
sourceIndices["a"] = 1;
|
||||||
|
Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
|
||||||
|
BOOST_CHECK_EQUAL(astJson["name"], "root");
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(source_location)
|
||||||
|
{
|
||||||
|
CompilerStack c;
|
||||||
|
c.addSource("a", "contract C { function f() { var x = 2; x++; } }");
|
||||||
|
c.parse();
|
||||||
|
map<string, unsigned> sourceIndices;
|
||||||
|
sourceIndices["a"] = 1;
|
||||||
|
Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
|
||||||
|
BOOST_CHECK_EQUAL(astJson["name"], "root");
|
||||||
|
BOOST_CHECK_EQUAL(astJson["children"][0]["name"], "Contract");
|
||||||
|
BOOST_CHECK_EQUAL(astJson["children"][0]["children"][0]["name"], "Function");
|
||||||
|
BOOST_CHECK_EQUAL(astJson["children"][0]["children"][0]["src"], "13:32:1");
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // end namespaces
|
Loading…
Reference in New Issue
Block a user