From dea7b864e6bbd80b913abf44dc4748868c5d6975 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 20 Mar 2017 19:06:17 +0100 Subject: [PATCH 1/9] Compact format for AST-Json with backwards compatibility --- libsolidity/ast/AST.h | 9 +- libsolidity/ast/ASTJsonConverter.cpp | 812 +++++++++++---------- libsolidity/ast/ASTJsonConverter.h | 98 +-- libsolidity/ast/Types.cpp | 2 + libsolidity/interface/StandardCompiler.cpp | 2 +- solc/CommandLineInterface.cpp | 10 +- solc/jsonCompiler.cpp | 2 +- test/libsolidity/ASTJSON.cpp | 24 +- test/libsolidity/StandardCompiler.cpp | 6 +- 9 files changed, 494 insertions(+), 471 deletions(-) diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 02234ffce..71b81a695 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -583,8 +583,7 @@ public: bool isPayable() const { return m_isPayable; } std::vector> const& modifiers() const { return m_functionModifiers; } std::vector> const& returnParameters() const { return m_returnParameters->parameters(); } - Block const& body() const { return *m_body; } - + Block const& body() const { solAssert(m_body, ""); return *m_body; } virtual bool isVisibleInContract() const override { return Declaration::isVisibleInContract() && !isConstructor() && !name().empty(); @@ -1314,7 +1313,7 @@ private: /** * Tuple, parenthesized expression, or bracketed expression. - * Examples: (1, 2), (x,), (x), (), [1, 2], + * Examples: (1, 2), (x,), (x), (), [1, 2], * Individual components might be empty shared pointers (as in the second example). * The respective types in lvalue context are: 2-tuple, 2-tuple (with wildcard), type of x, 0-tuple * Not in lvalue context: 2-tuple, _1_-tuple, type of x, 0-tuple. @@ -1327,8 +1326,8 @@ public: std::vector> const& _components, bool _isArray ): - Expression(_location), - m_components(_components), + Expression(_location), + m_components(_components), m_isArray(_isArray) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index 9ea23687d..c6abab54d 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -25,6 +25,8 @@ #include #include #include +#include +#include using namespace std; @@ -33,49 +35,86 @@ namespace dev namespace solidity { -void ASTJsonConverter::addJsonNode( +ASTJsonConverter::ASTJsonConverter(bool _legacy, map _sourceIndices): + m_legacy(_legacy), + m_sourceIndices(_sourceIndices) +{ +} + + +void ASTJsonConverter::setJsonNode( ASTNode const& _node, string const& _nodeName, - initializer_list> _attributes, - bool _hasChildren = false + initializer_list>&& _attributes ) { - ASTJsonConverter::addJsonNode( + ASTJsonConverter::setJsonNode( _node, _nodeName, - std::vector>(_attributes), - _hasChildren + std::vector>(std::move(_attributes)) ); } - -void ASTJsonConverter::addJsonNode( + +void ASTJsonConverter::setJsonNode( ASTNode const& _node, - string const& _nodeName, - std::vector> const& _attributes, - bool _hasChildren = false + string const& _nodeType, + std::vector>&& _attributes ) { - Json::Value node; - - node["id"] = Json::UInt64(_node.id()); - node["src"] = sourceLocationToString(_node.location()); - node["name"] = _nodeName; - if (_attributes.size() != 0) + m_currentValue = Json::objectValue; + m_currentValue["id"] = nodeId(_node); + m_currentValue["src"] = sourceLocationToString(_node.location()); + if (!m_legacy) { - Json::Value attrs; + m_currentValue["nodeType"] = _nodeType; for (auto& e: _attributes) - attrs[e.first] = e.second; - node["attributes"] = attrs; + m_currentValue[e.first] = std::move(e.second); } - - m_jsonNodePtrs.top()->append(node); - - if (_hasChildren) + else { - Json::Value& addedNode = (*m_jsonNodePtrs.top())[m_jsonNodePtrs.top()->size() - 1]; - Json::Value children(Json::arrayValue); - addedNode["children"] = children; - m_jsonNodePtrs.push(&addedNode["children"]); + m_currentValue["name"] = _nodeType; + Json::Value attrs(Json::objectValue); + if ( + //these nodeTypes need to have a children-node even if it is empty + (_nodeType == "VariableDeclaration") || + (_nodeType == "ParameterList") || + (_nodeType == "Block") || + (_nodeType == "InlineAssembly") || + (_nodeType == "Throw") + ) + { + Json::Value children(Json::arrayValue); + m_currentValue["children"] = children; + } + + for (auto& e: _attributes) + { + if ( + (!e.second.isNull()) && + ( + (e.second.isObject() && e.second.isMember("name")) || + (e.second.isArray() && e.second[0].isObject() && e.second[0].isMember("name")) || + (e.first == "declarations") // (in the case (_,x)= ... there's a nullpointer at [0] + ) + ) + { + if (e.second.isObject()) + m_currentValue["children"].append(std::move(e.second)); + if (e.second.isArray()) + for (auto& child : e.second) + if (!child.isNull()) + m_currentValue["children"].append(std::move(child)); + } + else + { + if (e.first == "typeDescriptions") + attrs["type"] = Json::Value(e.second["typeString"]); + else + attrs[e.first] = std::move(e.second); + } + } + if (!attrs.empty()) + m_currentValue["attributes"] = std::move(attrs); } } @@ -90,34 +129,79 @@ string ASTJsonConverter::sourceLocationToString(SourceLocation const& _location) return std::to_string(_location.start) + ":" + std::to_string(length) + ":" + std::to_string(sourceIndex); } -ASTJsonConverter::ASTJsonConverter( - ASTNode const& _ast, - map _sourceIndices -): m_ast(&_ast), m_sourceIndices(_sourceIndices) +string ASTJsonConverter::namePathToString(std::vector const& _namePath) const { + return boost::algorithm::join(_namePath, "."); } -void ASTJsonConverter::print(ostream& _stream) +Json::Value ASTJsonConverter::typePointerToJson(TypePointer _tp) { - process(); - _stream << m_astJson; + Json::Value typeDescriptions(Json::objectValue); + typeDescriptions["typeString"] = _tp ? Json::Value(_tp->toString()) : Json::nullValue; + typeDescriptions["typeIdentifier"] = _tp ? Json::Value(_tp->identifier()) : Json::nullValue; + return typeDescriptions; + +} +Json::Value ASTJsonConverter::typePointerToJson(std::shared_ptr> _tps) +{ + if (_tps) + { + Json::Value arguments(Json::arrayValue); + for (auto const& tp : *_tps) + arguments.append(typePointerToJson(tp)); + return arguments; + } + else + return Json::nullValue; } -Json::Value const& ASTJsonConverter::json() +void ASTJsonConverter::appendExpressionAttributes( + std::vector> * _attributes, + ExpressionAnnotation const& _annotation +) { - process(); - return m_astJson; + std::vector> exprAttributes = { + make_pair("typeDescriptions", typePointerToJson(_annotation.type)), + make_pair("isConstant", _annotation.isConstant), + make_pair("isPure", _annotation.isPure), + make_pair("isLValue", _annotation.isLValue), + make_pair("lValueRequested", _annotation.lValueRequested), + make_pair("argumentTypes", typePointerToJson(_annotation.argumentTypes)) + }; + _attributes->insert(_attributes->end(), exprAttributes.begin(), exprAttributes.end()); } -bool ASTJsonConverter::visit(SourceUnit const&) + +void ASTJsonConverter::print(ostream& _stream, ASTNode const& _node) { - Json::Value children(Json::arrayValue); + _stream << toJson(_node); +} - m_astJson["name"] = "SourceUnit"; - m_astJson["children"] = children; - m_jsonNodePtrs.push(&m_astJson["children"]); +Json::Value ASTJsonConverter::toJson(ASTNode const& _node) +{ + _node.accept(*this); + return std::move(m_currentValue); +} - return true; +bool ASTJsonConverter::visit(SourceUnit const& _node) +{ + Json::Value exportedSymbols = Json::objectValue; + for (auto const& sym: _node.annotation().exportedSymbols) + { + exportedSymbols[sym.first] = Json::arrayValue; + for (Declaration const* overload: sym.second) + exportedSymbols[sym.first].append(nodeId(*overload)); + } + setJsonNode( + _node, + "SourceUnit", + { + make_pair("absolutePath", _node.annotation().path), + make_pair("exportedSymbols", move(exportedSymbols)), + make_pair("nodes", toJson(_node.nodes())) + } + ); + return false; } bool ASTJsonConverter::visit(PragmaDirective const& _node) @@ -125,313 +209,493 @@ bool ASTJsonConverter::visit(PragmaDirective const& _node) Json::Value literals(Json::arrayValue); for (auto const& literal: _node.literals()) literals.append(literal); - addJsonNode(_node, "PragmaDirective", { make_pair("literals", literals) }); - return true; + setJsonNode( _node, "PragmaDirective", { + make_pair("literals", std::move(literals)) + }); + return false; } bool ASTJsonConverter::visit(ImportDirective const& _node) { - addJsonNode(_node, "ImportDirective", { make_pair("file", _node.path())}); - return true; + std::vector> attributes = { + make_pair("file", _node.path()), + make_pair("absolutePath", _node.annotation().absolutePath), + make_pair("SourceUnit", nodeId(*_node.annotation().sourceUnit)), + make_pair("scope", idOrNull(_node.scope())) + }; + attributes.push_back(make_pair("unitAlias", _node.name())); + Json::Value symbolAliases(Json::arrayValue); + for (auto const& symbolAlias: _node.symbolAliases()) + { + Json::Value tuple(Json::objectValue); + solAssert(symbolAlias.first, ""); + tuple["foreign"] = nodeId(*symbolAlias.first); + tuple["local"] = symbolAlias.second ? Json::Value(*symbolAlias.second) : Json::nullValue; + symbolAliases.append(tuple); + } + attributes.push_back( make_pair("symbolAliases", std::move(symbolAliases))); + setJsonNode(_node, "ImportDirective", std::move(attributes)); + return false; } bool ASTJsonConverter::visit(ContractDefinition const& _node) { Json::Value linearizedBaseContracts(Json::arrayValue); for (auto const& baseContract: _node.annotation().linearizedBaseContracts) - linearizedBaseContracts.append(Json::UInt64(baseContract->id())); - addJsonNode(_node, "ContractDefinition", { + linearizedBaseContracts.append(nodeId(*baseContract)); + Json::Value contractDependencies(Json::arrayValue); + for (auto const& dependentContract: _node.annotation().contractDependencies) + contractDependencies.append(nodeId(*dependentContract)); + setJsonNode(_node, "ContractDefinition", { make_pair("name", _node.name()), make_pair("isLibrary", _node.isLibrary()), make_pair("fullyImplemented", _node.annotation().isFullyImplemented), - make_pair("linearizedBaseContracts", linearizedBaseContracts), - }, true); - return true; + make_pair("linearizedBaseContracts", std::move(linearizedBaseContracts)), + make_pair("baseContracts", toJson(_node.baseContracts())), + make_pair("contractDependencies", std::move(contractDependencies)), + make_pair("nodes", toJson(_node.subNodes())), + make_pair("scope", idOrNull(_node.scope())) + }); + return false; } bool ASTJsonConverter::visit(InheritanceSpecifier const& _node) { - addJsonNode(_node, "InheritanceSpecifier", {}, true); - return true; + setJsonNode(_node, "InheritanceSpecifier", { + make_pair("baseName", toJson(_node.name())), + make_pair("arguments", toJson(_node.arguments())) + }); + return false; } bool ASTJsonConverter::visit(UsingForDirective const& _node) { - addJsonNode(_node, "UsingForDirective", {}, true); - return true; + setJsonNode(_node, "UsingForDirective", { + make_pair("libraryNames", toJson(_node.libraryName())), + make_pair("typeName", _node.typeName() ? toJson(*_node.typeName()) : Json::nullValue) + }); + return false; } bool ASTJsonConverter::visit(StructDefinition const& _node) { - addJsonNode(_node, "StructDefinition", { make_pair("name", _node.name()) }, true); - return true; + setJsonNode(_node, "StructDefinition", { + make_pair("name", _node.name()), + make_pair("visibility", visibility(_node.visibility())), + make_pair("canonicalName", _node.annotation().canonicalName), + make_pair("members", toJson(_node.members())), + make_pair("scope", idOrNull(_node.scope())) + }); + return false; } bool ASTJsonConverter::visit(EnumDefinition const& _node) { - addJsonNode(_node, "EnumDefinition", { make_pair("name", _node.name()) }, true); - return true; + setJsonNode(_node, "EnumDefinition", { + make_pair("name", _node.name()), + make_pair("canonicalName", _node.annotation().canonicalName), + make_pair("members", toJson(_node.members())) + }); + return false; } bool ASTJsonConverter::visit(EnumValue const& _node) { - addJsonNode(_node, "EnumValue", { make_pair("name", _node.name()) }); - return true; + setJsonNode(_node, "EnumValue", { + make_pair("name", _node.name()) + }); + return false; } bool ASTJsonConverter::visit(ParameterList const& _node) { - addJsonNode(_node, "ParameterList", {}, true); - return true; + setJsonNode(_node, "ParameterList", { + make_pair("parameters", toJson(_node.parameters())) + }); + return false; } bool ASTJsonConverter::visit(FunctionDefinition const& _node) { - addJsonNode(_node, "FunctionDefinition", { + std::vector> attributes = { make_pair("name", _node.name()), make_pair("constant", _node.isDeclaredConst()), make_pair("payable", _node.isPayable()), - make_pair("visibility", visibility(_node.visibility())) - }, true); - return true; + make_pair("visibility", visibility(_node.visibility())), + make_pair("parameters", toJson(_node.parameterList())), + make_pair("isConstructor", _node.isConstructor()), + make_pair("returnParameters", toJson((*_node.returnParameterList()))), + make_pair("modifiers", toJson(_node.modifiers())), + make_pair("body", _node.isImplemented() ? toJson(_node.body()) : Json::nullValue), + make_pair("isImplemented", _node.isImplemented()), + make_pair("scope", idOrNull(_node.scope())) + }; + setJsonNode(_node, "FunctionDefinition", std::move(attributes)); + return false; } bool ASTJsonConverter::visit(VariableDeclaration const& _node) { - std::vector> attributes = { + std::vector> attributes = { make_pair("name", _node.name()), - make_pair("type", type(_node)), + make_pair("typeName", toJsonOrNull(_node.typeName())), make_pair("constant", _node.isConstant()), make_pair("storageLocation", location(_node.referenceLocation())), - make_pair("visibility", visibility(_node.visibility())) - }; + make_pair("visibility", visibility(_node.visibility())), + make_pair("value", _node.value() ? toJson(*_node.value()) : Json::nullValue), + make_pair("scope", idOrNull(_node.scope())), + make_pair("typeDescriptions", typePointerToJson(_node.annotation().type)) + }; if (m_inEvent) attributes.push_back(make_pair("indexed", _node.isIndexed())); - addJsonNode(_node, "VariableDeclaration", attributes, true); - return true; - + setJsonNode(_node, "VariableDeclaration", std::move(attributes)); + return false; } bool ASTJsonConverter::visit(ModifierDefinition const& _node) { - addJsonNode(_node, "ModifierDefinition", { make_pair("name", _node.name()) }, true); - return true; + setJsonNode(_node, "ModifierDefinition", { + make_pair("name", _node.name()), + make_pair("visibility", visibility(_node.visibility())), + make_pair("parameters", toJson(_node.parameterList())), + make_pair("body", toJson(_node.body())) + }); + return false; } bool ASTJsonConverter::visit(ModifierInvocation const& _node) { - addJsonNode(_node, "ModifierInvocation", {}, true); - return true; + setJsonNode(_node, "ModifierInvocation", { + make_pair("modifierName", toJson(*_node.name())), + make_pair("arguments", toJson(_node.arguments())) + }); + return false; } bool ASTJsonConverter::visit(TypeName const&) { - return true; + return false; } bool ASTJsonConverter::visit(EventDefinition const& _node) { m_inEvent = true; - addJsonNode(_node, "EventDefinition", { make_pair("name", _node.name()) }, true); - return true; + setJsonNode(_node, "EventDefinition", { + make_pair("name", _node.name()), + make_pair("parameters", toJson(_node.parameterList())), + make_pair("isAnonymous", _node.isAnonymous()) + }); + return false; } bool ASTJsonConverter::visit(ElementaryTypeName const& _node) { - addJsonNode(_node, "ElementaryTypeName", { make_pair("name", _node.typeName().toString()) }); - return true; + setJsonNode(_node, "ElementaryTypeName", { + make_pair("name", _node.typeName().toString()), + make_pair("typeDescriptions", typePointerToJson(_node.annotation().type)) + }); + return false; } bool ASTJsonConverter::visit(UserDefinedTypeName const& _node) { - addJsonNode(_node, "UserDefinedTypeName", { - make_pair("name", boost::algorithm::join(_node.namePath(), ".")) + setJsonNode(_node, "UserDefinedTypeName", { + make_pair("name", namePathToString(_node.namePath())), + make_pair("referencedDeclaration", idOrNull(_node.annotation().referencedDeclaration)), + make_pair("contractScope", idOrNull(_node.annotation().contractScope)), + make_pair("typeDescriptions", typePointerToJson(_node.annotation().type)) }); - return true; + return false; } bool ASTJsonConverter::visit(FunctionTypeName const& _node) { - addJsonNode(_node, "FunctionTypeName", { + setJsonNode(_node, "FunctionTypeName", { make_pair("payable", _node.isPayable()), make_pair("visibility", visibility(_node.visibility())), - make_pair("constant", _node.isDeclaredConst()) - }, true); - return true; + make_pair("constant", _node.isDeclaredConst()), + make_pair("parameterTypes", toJson(_node.parameterTypes())), + make_pair("returnParameterTypes", toJson(_node.returnParameterTypes())), + make_pair("typeDescriptions", typePointerToJson(_node.annotation().type)) + }); + return false; } bool ASTJsonConverter::visit(Mapping const& _node) { - addJsonNode(_node, "Mapping", {}, true); - return true; + setJsonNode(_node, "Mapping", { + make_pair("keyType", toJson(_node.keyType())), + make_pair("valueType", toJson(_node.valueType())), + make_pair("typeDescriptions", typePointerToJson(_node.annotation().type)) + }); + return false; } bool ASTJsonConverter::visit(ArrayTypeName const& _node) { - addJsonNode(_node, "ArrayTypeName", {}, true); - return true; + setJsonNode(_node, "ArrayTypeName", { + make_pair("baseType", toJson(_node.baseType())), + make_pair("length", toJsonOrNull(_node.length())), + make_pair("typeDescriptions", typePointerToJson(_node.annotation().type)) + }); + return false; } bool ASTJsonConverter::visit(InlineAssembly const& _node) { - addJsonNode(_node, "InlineAssembly", {}, true); - return true; + std::map::iterator it; + Json::Value externalReferences(Json::arrayValue); + for ( + it = _node.annotation().externalReferences.begin(); + it != _node.annotation().externalReferences.end(); + it++ + ) + { + if (it->first && it->second) + { + Json::Value tuple(Json::objectValue); + tuple[it->first->name] = nodeId(*it->second); + externalReferences.append(tuple); + } + } + setJsonNode(_node, "InlineAssembly", { + make_pair("operations", Json::Value(assembly::AsmPrinter()(_node.operations()))), + make_pair("externalReferences", std::move(externalReferences)) + }); + return false; } bool ASTJsonConverter::visit(Block const& _node) { - addJsonNode(_node, "Block", {}, true); - return true; + setJsonNode(_node, "Block", { + make_pair("statements", toJson(_node.statements())) + }); + return false; } bool ASTJsonConverter::visit(PlaceholderStatement const& _node) { - addJsonNode(_node, "PlaceholderStatement", {}); - return true; + setJsonNode(_node, "PlaceholderStatement", {}); + return false; } bool ASTJsonConverter::visit(IfStatement const& _node) { - addJsonNode(_node, "IfStatement", {}, true); - return true; + setJsonNode(_node, "IfStatement", { + make_pair("condition", toJson(_node.condition())), + make_pair("trueBody", toJson(_node.trueStatement())), + make_pair("falseBody", toJsonOrNull(_node.falseStatement())) + }); + return false; } bool ASTJsonConverter::visit(WhileStatement const& _node) { - addJsonNode( + setJsonNode( _node, _node.isDoWhile() ? "DoWhileStatement" : "WhileStatement", - {}, - true); - return true; + { + make_pair("condition", toJson(_node.condition())), + make_pair("body", toJson(_node.body())) + } + ); + return false; } bool ASTJsonConverter::visit(ForStatement const& _node) { - addJsonNode(_node, "ForStatement", {}, true); - return true; + setJsonNode(_node, "ForStatement", { + make_pair("initExpression", toJsonOrNull(_node.initializationExpression())), + make_pair("condition", toJsonOrNull(_node.condition())), + make_pair("loopExpression", toJsonOrNull(_node.loopExpression())), + make_pair("body", toJson(_node.body())) + }); + return false; } bool ASTJsonConverter::visit(Continue const& _node) { - addJsonNode(_node, "Continue", {}); - return true; + setJsonNode(_node, "Continue", {}); + return false; } bool ASTJsonConverter::visit(Break const& _node) { - addJsonNode(_node, "Break", {}); - return true; + setJsonNode(_node, "Break", {}); + return false; } bool ASTJsonConverter::visit(Return const& _node) { - addJsonNode(_node, "Return", {}, true);; - return true; + setJsonNode(_node, "Return", { + make_pair("expression", toJsonOrNull(_node.expression())), + make_pair("functionReturnParameters", idOrNull(_node.annotation().functionReturnParameters)) + }); + return false; } bool ASTJsonConverter::visit(Throw const& _node) { - addJsonNode(_node, "Throw", {}, true);; - return true; + setJsonNode(_node, "Throw", {});; + return false; } bool ASTJsonConverter::visit(VariableDeclarationStatement const& _node) { - addJsonNode(_node, "VariableDeclarationStatement", {}, true); - return true; + Json::Value varDecs(Json::arrayValue); + for (auto const& v: _node.annotation().assignments) + { + varDecs.append(idOrNull(v)); + } + setJsonNode(_node, "VariableDeclarationStatement", { + make_pair("assignments", std::move(varDecs)), + make_pair("declarations", toJson(_node.declarations())), + make_pair("initialValue", toJsonOrNull(_node.initialValue())) + }); + return false; } bool ASTJsonConverter::visit(ExpressionStatement const& _node) { - addJsonNode(_node, "ExpressionStatement", {}, true); - return true; + setJsonNode(_node, "ExpressionStatement", { + make_pair("expression", toJson(_node.expression())) + }); + return false; } bool ASTJsonConverter::visit(Conditional const& _node) { - addJsonNode(_node, "Conditional", {}, true); - return true; + std::vector> attributes = { + make_pair("condition", toJson(_node.condition())), + make_pair("trueExpression", toJson(_node.trueExpression())), + make_pair("falseExpression", toJson(_node.falseExpression())) + }; + appendExpressionAttributes(&attributes, _node.annotation()); + setJsonNode(_node, "Conditional", std::move(attributes)); + return false; } bool ASTJsonConverter::visit(Assignment const& _node) { - addJsonNode(_node, "Assignment", - { make_pair("operator", Token::toString(_node.assignmentOperator())), - make_pair("type", type(_node)) }, - true); - return true; + std::vector> attributes = { + make_pair("operator", Token::toString(_node.assignmentOperator())), + make_pair("leftHandSide", toJson(_node.leftHandSide())), + make_pair("rightHandSide", toJson(_node.rightHandSide())) + }; + appendExpressionAttributes(&attributes, _node.annotation()); + setJsonNode( _node, "Assignment", std::move(attributes)); + return false; } bool ASTJsonConverter::visit(TupleExpression const& _node) { - addJsonNode(_node, "TupleExpression",{}, true); - return true; + std::vector> attributes = { + make_pair("isInlineArray", Json::Value(_node.isInlineArray())), + make_pair("components", toJson(_node.components())), + }; + appendExpressionAttributes(&attributes, _node.annotation()); + setJsonNode(_node, "TupleExpression", std::move(attributes)); + return false; } bool ASTJsonConverter::visit(UnaryOperation const& _node) { - addJsonNode(_node, "UnaryOperation", - { make_pair("prefix", _node.isPrefixOperation()), - make_pair("operator", Token::toString(_node.getOperator())), - make_pair("type", type(_node)) }, - true); - return true; + std::vector> attributes = { + make_pair("prefix", _node.isPrefixOperation()), + make_pair("operator", Token::toString(_node.getOperator())), + make_pair("subExpression", toJson(_node.subExpression())) + }; + appendExpressionAttributes(&attributes, _node.annotation()); + setJsonNode(_node, "UnaryOperation", std::move(attributes)); + return false; } bool ASTJsonConverter::visit(BinaryOperation const& _node) { - addJsonNode(_node, "BinaryOperation", { + std::vector> attributes = { make_pair("operator", Token::toString(_node.getOperator())), - make_pair("type", type(_node)) - }, true); - return true; + make_pair("leftExpression", toJson(_node.leftExpression())), + make_pair("rightExpression", toJson(_node.rightExpression())), + make_pair("commonType", typePointerToJson(_node.annotation().commonType)), + }; + appendExpressionAttributes(&attributes, _node.annotation()); + setJsonNode(_node, "BinaryOperation", std::move(attributes)); + return false; } bool ASTJsonConverter::visit(FunctionCall const& _node) { - addJsonNode(_node, "FunctionCall", { + Json::Value names(Json::arrayValue); + for (auto const& name: _node.names()) + names.append(Json::Value(*name)); + std::vector> attributes = { make_pair("type_conversion", _node.annotation().isTypeConversion), - make_pair("type", type(_node)) - }, true); - return true; + make_pair("isStructContstructorCall", _node.annotation().isStructConstructorCall), + make_pair("expression", toJson(_node.expression())), + make_pair("names", std::move(names)), + make_pair("arguments", toJson(_node.arguments())) + }; + appendExpressionAttributes(&attributes, _node.annotation()); + setJsonNode(_node, "FunctionCall", std::move(attributes)); + return false; } bool ASTJsonConverter::visit(NewExpression const& _node) { - addJsonNode(_node, "NewExpression", { make_pair("type", type(_node)) }, true); - return true; + std::vector> attributes = { + make_pair("typeName", toJson(_node.typeName())) + }; + appendExpressionAttributes(&attributes, _node.annotation()); + setJsonNode(_node, "NewExpression", std::move(attributes)); + return false; } bool ASTJsonConverter::visit(MemberAccess const& _node) { - addJsonNode(_node, "MemberAccess", { + std::vector> attributes = { make_pair("member_name", _node.memberName()), - make_pair("type", type(_node)) - }, true); - return true; + make_pair("expression", toJson(_node.expression())), + make_pair("referencedDeclaration", idOrNull(_node.annotation().referencedDeclaration)), + }; + appendExpressionAttributes(&attributes, _node.annotation()); + setJsonNode(_node, "MemberAccess", std::move(attributes)); + return false; } bool ASTJsonConverter::visit(IndexAccess const& _node) { - addJsonNode(_node, "IndexAccess", { make_pair("type", type(_node)) }, true); - return true; + std::vector> attributes = { + make_pair("baseExpression", toJson(_node.baseExpression())), + make_pair("indexExpression", toJsonOrNull(_node.indexExpression())), + }; + appendExpressionAttributes(&attributes, _node.annotation()); + setJsonNode(_node, "IndexAccess", std::move(attributes)); + return false; } bool ASTJsonConverter::visit(Identifier const& _node) { - addJsonNode(_node, "Identifier", - { make_pair("value", _node.name()), make_pair("type", type(_node)) }); - return true; + Json::Value overloads(Json::arrayValue); + for (auto const& dec: _node.annotation().overloadedDeclarations) + overloads.append(nodeId(*dec)); + setJsonNode(_node, "Identifier", { + make_pair("value", _node.name()), + make_pair("referencedDeclaration", idOrNull(_node.annotation().referencedDeclaration)), + make_pair("overloadedDeclarations", overloads), + make_pair("typeDescriptions", typePointerToJson(_node.annotation().type)), + make_pair("argumentTypes", typePointerToJson(_node.annotation().argumentTypes)) + }); + return false; } bool ASTJsonConverter::visit(ElementaryTypeNameExpression const& _node) { - addJsonNode(_node, "ElementaryTypeNameExpression", { - make_pair("value", _node.typeName().toString()), - make_pair("type", type(_node)) - }); - return true; + std::vector> attributes = { + make_pair("value", _node.typeName().toString()) + }; + appendExpressionAttributes(&attributes, _node.annotation()); + setJsonNode(_node, "ElementaryTypeNameExpression", std::move(attributes)); + return false; } bool ASTJsonConverter::visit(Literal const& _node) @@ -441,7 +705,7 @@ bool ASTJsonConverter::visit(Literal const& _node) if (!dev::validateUTF8(_node.value())) value = Json::nullValue; Token::Value subdenomination = Token::Value(_node.subDenomination()); - addJsonNode(_node, "Literal", { + std::vector> attributes = { make_pair("token", tokenString ? tokenString : Json::Value()), make_pair("value", value), make_pair("hexvalue", toHex(_node.value())), @@ -450,231 +714,17 @@ bool ASTJsonConverter::visit(Literal const& _node) subdenomination == Token::Illegal ? Json::nullValue : Json::Value{Token::toString(subdenomination)} - ), - make_pair("type", type(_node)) - }); - return true; + ) + }; + appendExpressionAttributes(&attributes, _node.annotation()); + setJsonNode(_node, "Literal", std::move(attributes)); + return false; } -void ASTJsonConverter::endVisit(SourceUnit const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(PragmaDirective const&) -{ -} - -void ASTJsonConverter::endVisit(ImportDirective const&) -{ -} - -void ASTJsonConverter::endVisit(ContractDefinition const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(InheritanceSpecifier const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(UsingForDirective const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(StructDefinition const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(EnumDefinition const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(EnumValue const&) -{ -} - -void ASTJsonConverter::endVisit(ParameterList const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(FunctionDefinition const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(VariableDeclaration const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(ModifierDefinition const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(ModifierInvocation const&) -{ - goUp(); -} void ASTJsonConverter::endVisit(EventDefinition const&) { m_inEvent = false; - goUp(); -} - -void ASTJsonConverter::endVisit(TypeName const&) -{ -} - -void ASTJsonConverter::endVisit(ElementaryTypeName const&) -{ -} - -void ASTJsonConverter::endVisit(UserDefinedTypeName const&) -{ -} - -void ASTJsonConverter::endVisit(FunctionTypeName const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(Mapping const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(ArrayTypeName const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(InlineAssembly const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(Block const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(PlaceholderStatement const&) -{ -} - -void ASTJsonConverter::endVisit(IfStatement const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(WhileStatement const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(ForStatement const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(Continue const&) -{ -} - -void ASTJsonConverter::endVisit(Break const&) -{ -} - -void ASTJsonConverter::endVisit(Return const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(Throw const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(VariableDeclarationStatement const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(ExpressionStatement const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(Conditional const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(Assignment const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(TupleExpression const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(UnaryOperation const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(BinaryOperation const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(FunctionCall const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(NewExpression const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(MemberAccess const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(IndexAccess const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(Identifier const&) -{ -} - -void ASTJsonConverter::endVisit(ElementaryTypeNameExpression const&) -{ -} - -void ASTJsonConverter::endVisit(Literal const&) -{ -} - -void ASTJsonConverter::process() -{ - if (!processed) - m_ast->accept(*this); - processed = true; } string ASTJsonConverter::visibility(Declaration::Visibility const& _visibility) diff --git a/libsolidity/ast/ASTJsonConverter.h b/libsolidity/ast/ASTJsonConverter.h index bd5e65604..eee1086e0 100644 --- a/libsolidity/ast/ASTJsonConverter.h +++ b/libsolidity/ast/ASTJsonConverter.h @@ -42,15 +42,23 @@ class ASTJsonConverter: public ASTConstVisitor { public: /// Create a converter to JSON for the given abstract syntax tree. + /// @a _legacy if true, use legacy format /// @a _sourceIndices is used to abbreviate source names in source locations. explicit ASTJsonConverter( - ASTNode const& _ast, + bool _legacy, std::map _sourceIndices = std::map() ); /// Output the json representation of the AST to _stream. - void print(std::ostream& _stream); - Json::Value const& json(); - + void print(std::ostream& _stream, ASTNode const& _node); + Json::Value toJson(ASTNode const& _node); + template + Json::Value toJson(std::vector> const& _nodes) + { + Json::Value ret(Json::arrayValue); + for (auto const& n: _nodes) + ret.append(n ? toJson(*n) : Json::nullValue); + return ret; + } bool visit(SourceUnit const& _node) override; bool visit(PragmaDirective const& _node) override; bool visit(ImportDirective const& _node) override; @@ -97,82 +105,46 @@ public: bool visit(ElementaryTypeNameExpression const& _node) override; bool visit(Literal const& _node) override; - void endVisit(SourceUnit const&) override; - void endVisit(PragmaDirective const&) override; - void endVisit(ImportDirective const&) override; - void endVisit(ContractDefinition const&) override; - void endVisit(InheritanceSpecifier const&) override; - void endVisit(UsingForDirective const&) override; - void endVisit(StructDefinition const&) override; - void endVisit(EnumDefinition const&) override; - void endVisit(EnumValue const&) override; - void endVisit(ParameterList const&) override; - void endVisit(FunctionDefinition const&) override; - void endVisit(VariableDeclaration const&) override; - void endVisit(ModifierDefinition const&) override; - void endVisit(ModifierInvocation const&) override; void endVisit(EventDefinition const&) override; - void endVisit(TypeName const&) override; - void endVisit(ElementaryTypeName const&) override; - void endVisit(UserDefinedTypeName const&) override; - void endVisit(FunctionTypeName const&) override; - void endVisit(Mapping const&) override; - void endVisit(ArrayTypeName const&) override; - void endVisit(InlineAssembly const&) override; - void endVisit(Block const&) override; - void endVisit(PlaceholderStatement const&) override; - void endVisit(IfStatement const&) override; - void endVisit(WhileStatement const&) override; - void endVisit(ForStatement const&) override; - void endVisit(Continue const&) override; - void endVisit(Break const&) override; - void endVisit(Return const&) override; - void endVisit(Throw const&) override; - void endVisit(VariableDeclarationStatement const&) override; - void endVisit(ExpressionStatement const&) override; - void endVisit(Conditional const&) override; - void endVisit(Assignment const&) override; - void endVisit(TupleExpression const&) override; - void endVisit(UnaryOperation const&) override; - void endVisit(BinaryOperation const&) override; - void endVisit(FunctionCall const&) override; - void endVisit(NewExpression const&) override; - void endVisit(MemberAccess const&) override; - void endVisit(IndexAccess const&) override; - void endVisit(Identifier const&) override; - void endVisit(ElementaryTypeNameExpression const&) override; - void endVisit(Literal const&) override; private: - void process(); - void addJsonNode( + void setJsonNode( ASTNode const& _node, std::string const& _nodeName, - std::initializer_list> _attributes, - bool _hasChildren + std::initializer_list>&& _attributes ); - void addJsonNode( + void setJsonNode( ASTNode const& _node, std::string const& _nodeName, - std::vector> const& _attributes, - bool _hasChildren + std::vector>&& _attributes ); std::string sourceLocationToString(SourceLocation const& _location) const; + std::string namePathToString(std::vector const& _namePath) const; + Json::Value idOrNull(ASTNode const* _pt) + { + return _pt ? Json::Value(nodeId(*_pt)) : Json::nullValue; + } + Json::Value toJsonOrNull(ASTNode const* _node) + { + return _node ? toJson(*_node) : Json::nullValue; + } std::string visibility(Declaration::Visibility const& _visibility); std::string location(VariableDeclaration::Location _location); std::string type(Expression const& _expression); std::string type(VariableDeclaration const& _varDecl); - inline void goUp() + int nodeId(ASTNode const& _node) { - solAssert(!m_jsonNodePtrs.empty(), "Uneven json nodes stack. Internal error."); - m_jsonNodePtrs.pop(); + return _node.id(); } - + Json::Value typePointerToJson(TypePointer _tp); + Json::Value typePointerToJson(std::shared_ptr> _tps); + void appendExpressionAttributes( + std::vector> * _attributes, + ExpressionAnnotation const& _annotation + ); + bool m_legacy = false; ///< if true, use legacy format bool m_inEvent = false; ///< whether we are currently inside an event or not - bool processed = false; - Json::Value m_astJson; - std::stack m_jsonNodePtrs; - ASTNode const* m_ast; + Json::Value m_currentValue; std::map m_sourceIndices; }; diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 41ee64984..cfee041ec 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -2183,6 +2183,8 @@ string FunctionType::identifier() const case Kind::ArrayPush: id += "arraypush"; break; case Kind::ByteArrayPush: id += "bytearraypush"; break; case Kind::ObjectCreation: id += "objectcreation"; break; + case Kind::Assert: id += "assert"; break; + case Kind::Require: id += "require";break; default: solAssert(false, "Unknown function location."); break; } if (isConstant()) diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 223cc15db..4ca1fd098 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -377,7 +377,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) { Json::Value sourceResult = Json::objectValue; sourceResult["id"] = sourceIndex++; - sourceResult["legacyAST"] = ASTJsonConverter(m_compilerStack.ast(source), m_compilerStack.sourceIndices()).json(); + sourceResult["legacyAST"] = ASTJsonConverter(true, m_compilerStack.sourceIndices()).toJson(m_compilerStack.ast(source)); output["sources"][source] = sourceResult; } diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 0f2e83dce..ebd16fd3d 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -835,9 +835,9 @@ void CommandLineInterface::handleCombinedJSON() output[g_strSources] = Json::Value(Json::objectValue); for (auto const& sourceCode: m_sourceCodes) { - ASTJsonConverter converter(m_compiler->ast(sourceCode.first), m_compiler->sourceIndices()); + ASTJsonConverter converter(true, m_compiler->sourceIndices()); output[g_strSources][sourceCode.first] = Json::Value(Json::objectValue); - output[g_strSources][sourceCode.first]["AST"] = converter.json(); + output[g_strSources][sourceCode.first]["AST"] = converter.toJson(m_compiler->ast(sourceCode.first)); } } cout << dev::jsonCompactPrint(output) << endl; @@ -880,8 +880,7 @@ void CommandLineInterface::handleAst(string const& _argStr) } else { - ASTJsonConverter converter(m_compiler->ast(sourceCode.first)); - converter.print(data); + ASTJsonConverter(true).print(data, m_compiler->ast(sourceCode.first)); postfix += "_json"; } boost::filesystem::path path(sourceCode.first); @@ -905,8 +904,7 @@ void CommandLineInterface::handleAst(string const& _argStr) } else { - ASTJsonConverter converter(m_compiler->ast(sourceCode.first)); - converter.print(cout); + ASTJsonConverter(true).print(cout, m_compiler->ast(sourceCode.first)); } } } diff --git a/solc/jsonCompiler.cpp b/solc/jsonCompiler.cpp index 42c25de04..2501c8e84 100644 --- a/solc/jsonCompiler.cpp +++ b/solc/jsonCompiler.cpp @@ -245,7 +245,7 @@ string compile(StringMap const& _sources, bool _optimize, CStyleReadFileCallback output["sourceList"].append(source); output["sources"] = Json::Value(Json::objectValue); for (auto const& source: compiler.sourceNames()) - output["sources"][source]["AST"] = ASTJsonConverter(compiler.ast(source), compiler.sourceIndices()).json(); + output["sources"][source]["AST"] = ASTJsonConverter(true, compiler.sourceIndices()).toJson(compiler.ast(source)); } catch (...) { diff --git a/test/libsolidity/ASTJSON.cpp b/test/libsolidity/ASTJSON.cpp index d23815b48..8a7903471 100644 --- a/test/libsolidity/ASTJSON.cpp +++ b/test/libsolidity/ASTJSON.cpp @@ -44,7 +44,7 @@ BOOST_AUTO_TEST_CASE(smoke_test) c.parseAndAnalyze(); map sourceIndices; sourceIndices["a"] = 1; - Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); + Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); BOOST_CHECK_EQUAL(astJson["name"], "SourceUnit"); } @@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(source_location) c.parseAndAnalyze(); map sourceIndices; sourceIndices["a"] = 1; - Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); + Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); BOOST_CHECK_EQUAL(astJson["name"], "SourceUnit"); BOOST_CHECK_EQUAL(astJson["children"][0]["name"], "ContractDefinition"); BOOST_CHECK_EQUAL(astJson["children"][0]["children"][0]["name"], "FunctionDefinition"); @@ -69,7 +69,7 @@ BOOST_AUTO_TEST_CASE(inheritance_specifier) c.parseAndAnalyze(); map sourceIndices; sourceIndices["a"] = 1; - Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); + Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); BOOST_CHECK_EQUAL(astJson["children"][1]["attributes"]["name"], "C2"); BOOST_CHECK_EQUAL(astJson["children"][1]["children"][0]["name"], "InheritanceSpecifier"); BOOST_CHECK_EQUAL(astJson["children"][1]["children"][0]["src"], "30:2:1"); @@ -84,7 +84,7 @@ BOOST_AUTO_TEST_CASE(using_for_directive) c.parseAndAnalyze(); map sourceIndices; sourceIndices["a"] = 1; - Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); + Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); Json::Value usingFor = astJson["children"][1]["children"][0]; BOOST_CHECK_EQUAL(usingFor["name"], "UsingForDirective"); BOOST_CHECK_EQUAL(usingFor["src"], "26:17:1"); @@ -101,7 +101,7 @@ BOOST_AUTO_TEST_CASE(enum_value) c.parseAndAnalyze(); map sourceIndices; sourceIndices["a"] = 1; - Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); + Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); Json::Value enumDefinition = astJson["children"][0]["children"][0]; BOOST_CHECK_EQUAL(enumDefinition["children"][0]["name"], "EnumValue"); BOOST_CHECK_EQUAL(enumDefinition["children"][0]["attributes"]["name"], "A"); @@ -118,7 +118,7 @@ BOOST_AUTO_TEST_CASE(modifier_definition) c.parseAndAnalyze(); map sourceIndices; sourceIndices["a"] = 1; - Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); + Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); Json::Value modifier = astJson["children"][0]["children"][0]; BOOST_CHECK_EQUAL(modifier["name"], "ModifierDefinition"); BOOST_CHECK_EQUAL(modifier["attributes"]["name"], "M"); @@ -132,7 +132,7 @@ BOOST_AUTO_TEST_CASE(modifier_invocation) c.parseAndAnalyze(); map sourceIndices; sourceIndices["a"] = 1; - Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); + Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); Json::Value modifier = astJson["children"][0]["children"][1]["children"][2]; BOOST_CHECK_EQUAL(modifier["name"], "ModifierInvocation"); BOOST_CHECK_EQUAL(modifier["src"], "52:4:1"); @@ -148,7 +148,7 @@ BOOST_AUTO_TEST_CASE(event_definition) c.parseAndAnalyze(); map sourceIndices; sourceIndices["a"] = 1; - Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); + Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); Json::Value event = astJson["children"][0]["children"][0]; BOOST_CHECK_EQUAL(event["name"], "EventDefinition"); BOOST_CHECK_EQUAL(event["attributes"]["name"], "E"); @@ -162,7 +162,7 @@ BOOST_AUTO_TEST_CASE(array_type_name) c.parseAndAnalyze(); map sourceIndices; sourceIndices["a"] = 1; - Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); + Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); Json::Value array = astJson["children"][0]["children"][0]["children"][0]; BOOST_CHECK_EQUAL(array["name"], "ArrayTypeName"); BOOST_CHECK_EQUAL(array["src"], "13:6:1"); @@ -175,7 +175,7 @@ BOOST_AUTO_TEST_CASE(placeholder_statement) c.parseAndAnalyze(); map sourceIndices; sourceIndices["a"] = 1; - Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); + Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); Json::Value placeholder = astJson["children"][0]["children"][0]["children"][1]["children"][0]; BOOST_CHECK_EQUAL(placeholder["name"], "PlaceholderStatement"); BOOST_CHECK_EQUAL(placeholder["src"], "26:1:1"); @@ -188,7 +188,7 @@ BOOST_AUTO_TEST_CASE(non_utf8) c.parseAndAnalyze(); map sourceIndices; sourceIndices["a"] = 1; - Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); + Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); Json::Value literal = astJson["children"][0]["children"][0]["children"][2]["children"][0]["children"][1]; BOOST_CHECK_EQUAL(literal["name"], "Literal"); BOOST_CHECK_EQUAL(literal["attributes"]["hexvalue"], "ff"); @@ -207,7 +207,7 @@ BOOST_AUTO_TEST_CASE(function_type) c.parseAndAnalyze(); map sourceIndices; sourceIndices["a"] = 1; - Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); + Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); Json::Value fun = astJson["children"][0]["children"][0]; BOOST_CHECK_EQUAL(fun["name"], "FunctionDefinition"); Json::Value argument = fun["children"][0]["children"][0]; diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp index ec2f69d92..f4d277bd2 100644 --- a/test/libsolidity/StandardCompiler.cpp +++ b/test/libsolidity/StandardCompiler.cpp @@ -215,8 +215,10 @@ BOOST_AUTO_TEST_CASE(basic_compilation) BOOST_CHECK(result["sources"]["fileA"].isObject()); BOOST_CHECK(result["sources"]["fileA"]["legacyAST"].isObject()); BOOST_CHECK(dev::jsonCompactPrint(result["sources"]["fileA"]["legacyAST"]) == - "{\"children\":[{\"attributes\":{\"fullyImplemented\":true,\"isLibrary\":false,\"linearizedBaseContracts\":[1]," - "\"name\":\"A\"},\"children\":[],\"id\":1,\"name\":\"ContractDefinition\",\"src\":\"0:14:0\"}],\"name\":\"SourceUnit\"}"); + "{\"attributes\":{\"absolutePath\":\"fileA\",\"exportedSymbols\":{\"A\":[1]}},\"children\":" + "[{\"attributes\":{\"baseContracts\":[null],\"contractDependencies\":[null],\"fullyImplemented\":true," + "\"isLibrary\":false,\"linearizedBaseContracts\":[1],\"name\":\"A\",\"nodes\":[null],\"scope\":2}," + "\"id\":1,\"name\":\"ContractDefinition\",\"src\":\"0:14:0\"}],\"id\":2,\"name\":\"SourceUnit\",\"src\":\"0:14:0\"}"); } BOOST_AUTO_TEST_SUITE_END() From f2a6331ffbf0fb37bd9d05aed28a625fe366fa4c Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 21 Apr 2017 13:34:26 +0100 Subject: [PATCH 2/9] Support the new AST in StandardCompiler --- libsolidity/interface/StandardCompiler.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 4ca1fd098..0afa9ae1c 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -377,6 +377,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) { Json::Value sourceResult = Json::objectValue; sourceResult["id"] = sourceIndex++; + sourceResult["ast"] = ASTJsonConverter(false, m_compilerStack.sourceIndices()).toJson(m_compilerStack.ast(source)); sourceResult["legacyAST"] = ASTJsonConverter(true, m_compilerStack.sourceIndices()).toJson(m_compilerStack.ast(source)); output["sources"][source] = sourceResult; } From 487eef18ccb5202461130e91a9b93981bcbf1a5d Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 21 Apr 2017 13:46:53 +0100 Subject: [PATCH 3/9] Use different AST node names in legacy and new format --- libsolidity/ast/ASTJsonConverter.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index c6abab54d..3388d6cc5 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -220,7 +220,7 @@ bool ASTJsonConverter::visit(ImportDirective const& _node) std::vector> attributes = { make_pair("file", _node.path()), make_pair("absolutePath", _node.annotation().absolutePath), - make_pair("SourceUnit", nodeId(*_node.annotation().sourceUnit)), + make_pair(m_legacy ? "SourceUnit" : "sourceUnit", nodeId(*_node.annotation().sourceUnit)), make_pair("scope", idOrNull(_node.scope())) }; attributes.push_back(make_pair("unitAlias", _node.name())); @@ -319,7 +319,7 @@ bool ASTJsonConverter::visit(FunctionDefinition const& _node) { std::vector> attributes = { make_pair("name", _node.name()), - make_pair("constant", _node.isDeclaredConst()), + make_pair(m_legacy ? "constant" : "isDeclaredConst", _node.isDeclaredConst()), make_pair("payable", _node.isPayable()), make_pair("visibility", visibility(_node.visibility())), make_pair("parameters", toJson(_node.parameterList())), @@ -339,7 +339,7 @@ bool ASTJsonConverter::visit(VariableDeclaration const& _node) std::vector> attributes = { make_pair("name", _node.name()), make_pair("typeName", toJsonOrNull(_node.typeName())), - make_pair("constant", _node.isConstant()), + make_pair(m_legacy ? "constant" : "isConstant", _node.isConstant()), make_pair("storageLocation", location(_node.referenceLocation())), make_pair("visibility", visibility(_node.visibility())), make_pair("value", _node.value() ? toJson(*_node.value()) : Json::nullValue), @@ -413,7 +413,7 @@ bool ASTJsonConverter::visit(FunctionTypeName const& _node) setJsonNode(_node, "FunctionTypeName", { make_pair("payable", _node.isPayable()), make_pair("visibility", visibility(_node.visibility())), - make_pair("constant", _node.isDeclaredConst()), + make_pair(m_legacy ? "constant" : "isDeclaredConst", _node.isDeclaredConst()), make_pair("parameterTypes", toJson(_node.parameterTypes())), make_pair("returnParameterTypes", toJson(_node.returnParameterTypes())), make_pair("typeDescriptions", typePointerToJson(_node.annotation().type)) @@ -629,7 +629,7 @@ bool ASTJsonConverter::visit(FunctionCall const& _node) for (auto const& name: _node.names()) names.append(Json::Value(*name)); std::vector> attributes = { - make_pair("type_conversion", _node.annotation().isTypeConversion), + make_pair(m_legacy ? "type_conversion" : "isTypeConversion", _node.annotation().isTypeConversion), make_pair("isStructContstructorCall", _node.annotation().isStructConstructorCall), make_pair("expression", toJson(_node.expression())), make_pair("names", std::move(names)), @@ -653,7 +653,7 @@ bool ASTJsonConverter::visit(NewExpression const& _node) bool ASTJsonConverter::visit(MemberAccess const& _node) { std::vector> attributes = { - make_pair("member_name", _node.memberName()), + make_pair(m_legacy ? "member_name" : "memberName", _node.memberName()), make_pair("expression", toJson(_node.expression())), make_pair("referencedDeclaration", idOrNull(_node.annotation().referencedDeclaration)), }; @@ -679,7 +679,7 @@ bool ASTJsonConverter::visit(Identifier const& _node) for (auto const& dec: _node.annotation().overloadedDeclarations) overloads.append(nodeId(*dec)); setJsonNode(_node, "Identifier", { - make_pair("value", _node.name()), + make_pair(m_legacy ? "value" : "name", _node.name()), make_pair("referencedDeclaration", idOrNull(_node.annotation().referencedDeclaration)), make_pair("overloadedDeclarations", overloads), make_pair("typeDescriptions", typePointerToJson(_node.annotation().type)), @@ -691,7 +691,7 @@ bool ASTJsonConverter::visit(Identifier const& _node) bool ASTJsonConverter::visit(ElementaryTypeNameExpression const& _node) { std::vector> attributes = { - make_pair("value", _node.typeName().toString()) + make_pair(m_legacy ? "value" : "typeName", _node.typeName().toString()) }; appendExpressionAttributes(&attributes, _node.annotation()); setJsonNode(_node, "ElementaryTypeNameExpression", std::move(attributes)); @@ -708,7 +708,7 @@ bool ASTJsonConverter::visit(Literal const& _node) std::vector> attributes = { make_pair("token", tokenString ? tokenString : Json::Value()), make_pair("value", value), - make_pair("hexvalue", toHex(_node.value())), + make_pair(m_legacy ? "hexvalue" : "hexValue", toHex(_node.value())), make_pair( "subdenomination", subdenomination == Token::Illegal ? From 2fa7646944451bdb804d842c0dacdbbba960f857 Mon Sep 17 00:00:00 2001 From: djuju Date: Tue, 25 Apr 2017 18:47:11 +0200 Subject: [PATCH 4/9] fixed styletypos, renaming and added helperfunction --- libsolidity/ast/ASTJsonConverter.cpp | 63 +++++++++++++--------------- libsolidity/ast/ASTJsonConverter.h | 13 +++++- 2 files changed, 40 insertions(+), 36 deletions(-) diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index 3388d6cc5..4046073eb 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -101,7 +101,7 @@ void ASTJsonConverter::setJsonNode( if (e.second.isObject()) m_currentValue["children"].append(std::move(e.second)); if (e.second.isArray()) - for (auto& child : e.second) + for (auto& child: e.second) if (!child.isNull()) m_currentValue["children"].append(std::move(child)); } @@ -147,7 +147,7 @@ Json::Value ASTJsonConverter::typePointerToJson(std::shared_ptr> * _attributes, + std::vector> &_attributes, ExpressionAnnotation const& _annotation ) { std::vector> exprAttributes = { make_pair("typeDescriptions", typePointerToJson(_annotation.type)), - make_pair("isConstant", _annotation.isConstant), - make_pair("isPure", _annotation.isPure), - make_pair("isLValue", _annotation.isLValue), - make_pair("lValueRequested", _annotation.lValueRequested), - make_pair("argumentTypes", typePointerToJson(_annotation.argumentTypes)) + make_pair("isConstant", _annotation.isConstant), + make_pair("isPure", _annotation.isPure), + make_pair("isLValue", _annotation.isLValue), + make_pair("lValueRequested", _annotation.lValueRequested), + make_pair("argumentTypes", typePointerToJson(_annotation.argumentTypes)) }; - _attributes->insert(_attributes->end(), exprAttributes.begin(), exprAttributes.end()); + _attributes.insert(_attributes.end(), exprAttributes.begin(), exprAttributes.end()); } @@ -233,26 +233,20 @@ bool ASTJsonConverter::visit(ImportDirective const& _node) tuple["local"] = symbolAlias.second ? Json::Value(*symbolAlias.second) : Json::nullValue; symbolAliases.append(tuple); } - attributes.push_back( make_pair("symbolAliases", std::move(symbolAliases))); + attributes.push_back(make_pair("symbolAliases", std::move(symbolAliases))); setJsonNode(_node, "ImportDirective", std::move(attributes)); return false; } bool ASTJsonConverter::visit(ContractDefinition const& _node) { - Json::Value linearizedBaseContracts(Json::arrayValue); - for (auto const& baseContract: _node.annotation().linearizedBaseContracts) - linearizedBaseContracts.append(nodeId(*baseContract)); - Json::Value contractDependencies(Json::arrayValue); - for (auto const& dependentContract: _node.annotation().contractDependencies) - contractDependencies.append(nodeId(*dependentContract)); setJsonNode(_node, "ContractDefinition", { make_pair("name", _node.name()), make_pair("isLibrary", _node.isLibrary()), make_pair("fullyImplemented", _node.annotation().isFullyImplemented), - make_pair("linearizedBaseContracts", std::move(linearizedBaseContracts)), + make_pair("linearizedBaseContracts", getContainerIds(_node.annotation().linearizedBaseContracts)), make_pair("baseContracts", toJson(_node.baseContracts())), - make_pair("contractDependencies", std::move(contractDependencies)), + make_pair("contractDependencies", getContainerIds(_node.annotation().contractDependencies)), make_pair("nodes", toJson(_node.subNodes())), make_pair("scope", idOrNull(_node.scope())) }); @@ -322,9 +316,9 @@ bool ASTJsonConverter::visit(FunctionDefinition const& _node) make_pair(m_legacy ? "constant" : "isDeclaredConst", _node.isDeclaredConst()), make_pair("payable", _node.isPayable()), make_pair("visibility", visibility(_node.visibility())), - make_pair("parameters", toJson(_node.parameterList())), + make_pair("parameters", toJson(_node.parameterList())), make_pair("isConstructor", _node.isConstructor()), - make_pair("returnParameters", toJson((*_node.returnParameterList()))), + make_pair("returnParameters", toJson(*_node.returnParameterList())), make_pair("modifiers", toJson(_node.modifiers())), make_pair("body", _node.isImplemented() ? toJson(_node.body()) : Json::nullValue), make_pair("isImplemented", _node.isImplemented()), @@ -339,7 +333,7 @@ bool ASTJsonConverter::visit(VariableDeclaration const& _node) std::vector> attributes = { make_pair("name", _node.name()), make_pair("typeName", toJsonOrNull(_node.typeName())), - make_pair(m_legacy ? "constant" : "isConstant", _node.isConstant()), + make_pair("constant", _node.isConstant()), make_pair("storageLocation", location(_node.referenceLocation())), make_pair("visibility", visibility(_node.visibility())), make_pair("value", _node.value() ? toJson(*_node.value()) : Json::nullValue), @@ -374,6 +368,7 @@ bool ASTJsonConverter::visit(ModifierInvocation const& _node) bool ASTJsonConverter::visit(TypeName const&) { + solAssert(false, "AST node of abstract type used."); return false; } @@ -383,7 +378,7 @@ bool ASTJsonConverter::visit(EventDefinition const& _node) setJsonNode(_node, "EventDefinition", { make_pair("name", _node.name()), make_pair("parameters", toJson(_node.parameterList())), - make_pair("isAnonymous", _node.isAnonymous()) + make_pair("anonymous", _node.isAnonymous()) }); return false; } @@ -544,9 +539,7 @@ bool ASTJsonConverter::visit(VariableDeclarationStatement const& _node) { Json::Value varDecs(Json::arrayValue); for (auto const& v: _node.annotation().assignments) - { varDecs.append(idOrNull(v)); - } setJsonNode(_node, "VariableDeclarationStatement", { make_pair("assignments", std::move(varDecs)), make_pair("declarations", toJson(_node.declarations())), @@ -570,7 +563,7 @@ bool ASTJsonConverter::visit(Conditional const& _node) make_pair("trueExpression", toJson(_node.trueExpression())), make_pair("falseExpression", toJson(_node.falseExpression())) }; - appendExpressionAttributes(&attributes, _node.annotation()); + appendExpressionAttributes(attributes, _node.annotation()); setJsonNode(_node, "Conditional", std::move(attributes)); return false; } @@ -582,7 +575,7 @@ bool ASTJsonConverter::visit(Assignment const& _node) make_pair("leftHandSide", toJson(_node.leftHandSide())), make_pair("rightHandSide", toJson(_node.rightHandSide())) }; - appendExpressionAttributes(&attributes, _node.annotation()); + appendExpressionAttributes(attributes, _node.annotation()); setJsonNode( _node, "Assignment", std::move(attributes)); return false; } @@ -593,7 +586,7 @@ bool ASTJsonConverter::visit(TupleExpression const& _node) make_pair("isInlineArray", Json::Value(_node.isInlineArray())), make_pair("components", toJson(_node.components())), }; - appendExpressionAttributes(&attributes, _node.annotation()); + appendExpressionAttributes(attributes, _node.annotation()); setJsonNode(_node, "TupleExpression", std::move(attributes)); return false; } @@ -605,7 +598,7 @@ bool ASTJsonConverter::visit(UnaryOperation const& _node) make_pair("operator", Token::toString(_node.getOperator())), make_pair("subExpression", toJson(_node.subExpression())) }; - appendExpressionAttributes(&attributes, _node.annotation()); + appendExpressionAttributes(attributes, _node.annotation()); setJsonNode(_node, "UnaryOperation", std::move(attributes)); return false; } @@ -618,7 +611,7 @@ bool ASTJsonConverter::visit(BinaryOperation const& _node) make_pair("rightExpression", toJson(_node.rightExpression())), make_pair("commonType", typePointerToJson(_node.annotation().commonType)), }; - appendExpressionAttributes(&attributes, _node.annotation()); + appendExpressionAttributes(attributes, _node.annotation()); setJsonNode(_node, "BinaryOperation", std::move(attributes)); return false; } @@ -635,7 +628,7 @@ bool ASTJsonConverter::visit(FunctionCall const& _node) make_pair("names", std::move(names)), make_pair("arguments", toJson(_node.arguments())) }; - appendExpressionAttributes(&attributes, _node.annotation()); + appendExpressionAttributes(attributes, _node.annotation()); setJsonNode(_node, "FunctionCall", std::move(attributes)); return false; } @@ -645,7 +638,7 @@ bool ASTJsonConverter::visit(NewExpression const& _node) std::vector> attributes = { make_pair("typeName", toJson(_node.typeName())) }; - appendExpressionAttributes(&attributes, _node.annotation()); + appendExpressionAttributes(attributes, _node.annotation()); setJsonNode(_node, "NewExpression", std::move(attributes)); return false; } @@ -657,7 +650,7 @@ bool ASTJsonConverter::visit(MemberAccess const& _node) make_pair("expression", toJson(_node.expression())), make_pair("referencedDeclaration", idOrNull(_node.annotation().referencedDeclaration)), }; - appendExpressionAttributes(&attributes, _node.annotation()); + appendExpressionAttributes(attributes, _node.annotation()); setJsonNode(_node, "MemberAccess", std::move(attributes)); return false; } @@ -668,7 +661,7 @@ bool ASTJsonConverter::visit(IndexAccess const& _node) make_pair("baseExpression", toJson(_node.baseExpression())), make_pair("indexExpression", toJsonOrNull(_node.indexExpression())), }; - appendExpressionAttributes(&attributes, _node.annotation()); + appendExpressionAttributes(attributes, _node.annotation()); setJsonNode(_node, "IndexAccess", std::move(attributes)); return false; } @@ -693,7 +686,7 @@ bool ASTJsonConverter::visit(ElementaryTypeNameExpression const& _node) std::vector> attributes = { make_pair(m_legacy ? "value" : "typeName", _node.typeName().toString()) }; - appendExpressionAttributes(&attributes, _node.annotation()); + appendExpressionAttributes(attributes, _node.annotation()); setJsonNode(_node, "ElementaryTypeNameExpression", std::move(attributes)); return false; } @@ -716,7 +709,7 @@ bool ASTJsonConverter::visit(Literal const& _node) Json::Value{Token::toString(subdenomination)} ) }; - appendExpressionAttributes(&attributes, _node.annotation()); + appendExpressionAttributes(attributes, _node.annotation()); setJsonNode(_node, "Literal", std::move(attributes)); return false; } diff --git a/libsolidity/ast/ASTJsonConverter.h b/libsolidity/ast/ASTJsonConverter.h index eee1086e0..aab8c1246 100644 --- a/libsolidity/ast/ASTJsonConverter.h +++ b/libsolidity/ast/ASTJsonConverter.h @@ -136,10 +136,21 @@ private: { return _node.id(); } + template + Json::Value getContainerIds(Container container) + { + Json::Value tmp(Json::arrayValue); + for (auto it = container.begin(); it != container.end(); ++it) + { + solAssert(*it, ""); + tmp.append(nodeId(**it)); + } + return tmp; + } Json::Value typePointerToJson(TypePointer _tp); Json::Value typePointerToJson(std::shared_ptr> _tps); void appendExpressionAttributes( - std::vector> * _attributes, + std::vector> &_attributes, ExpressionAnnotation const& _annotation ); bool m_legacy = false; ///< if true, use legacy format From a4ba5ace8a5d77397715204fe737b0dba4429368 Mon Sep 17 00:00:00 2001 From: djuju Date: Fri, 5 May 2017 16:15:09 +0200 Subject: [PATCH 5/9] prefixChanges and contractKind-field --- libsolidity/ast/ASTJsonConverter.cpp | 36 ++++++++++++++++++---------- libsolidity/ast/ASTJsonConverter.h | 1 + 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index 4046073eb..492429d70 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -242,7 +242,7 @@ bool ASTJsonConverter::visit(ContractDefinition const& _node) { setJsonNode(_node, "ContractDefinition", { make_pair("name", _node.name()), - make_pair("isLibrary", _node.isLibrary()), + make_pair("contractKind", contractKind(_node.contractKind())), make_pair("fullyImplemented", _node.annotation().isFullyImplemented), make_pair("linearizedBaseContracts", getContainerIds(_node.annotation().linearizedBaseContracts)), make_pair("baseContracts", toJson(_node.baseContracts())), @@ -265,7 +265,7 @@ bool ASTJsonConverter::visit(InheritanceSpecifier const& _node) bool ASTJsonConverter::visit(UsingForDirective const& _node) { setJsonNode(_node, "UsingForDirective", { - make_pair("libraryNames", toJson(_node.libraryName())), + make_pair("libraryName", toJson(_node.libraryName())), make_pair("typeName", _node.typeName() ? toJson(*_node.typeName()) : Json::nullValue) }); return false; @@ -321,7 +321,7 @@ bool ASTJsonConverter::visit(FunctionDefinition const& _node) make_pair("returnParameters", toJson(*_node.returnParameterList())), make_pair("modifiers", toJson(_node.modifiers())), make_pair("body", _node.isImplemented() ? toJson(_node.body()) : Json::nullValue), - make_pair("isImplemented", _node.isImplemented()), + make_pair("implemented", _node.isImplemented()), make_pair("scope", idOrNull(_node.scope())) }; setJsonNode(_node, "FunctionDefinition", std::move(attributes)); @@ -438,18 +438,13 @@ bool ASTJsonConverter::visit(ArrayTypeName const& _node) bool ASTJsonConverter::visit(InlineAssembly const& _node) { - std::map::iterator it; Json::Value externalReferences(Json::arrayValue); - for ( - it = _node.annotation().externalReferences.begin(); - it != _node.annotation().externalReferences.end(); - it++ - ) + for (auto const& it : _node.annotation().externalReferences) { - if (it->first && it->second) + if (it.first && it.second) { Json::Value tuple(Json::objectValue); - tuple[it->first->name] = nodeId(*it->second); + tuple[it.first->name] = nodeId(*it.second); externalReferences.append(tuple); } } @@ -500,7 +495,7 @@ bool ASTJsonConverter::visit(WhileStatement const& _node) bool ASTJsonConverter::visit(ForStatement const& _node) { setJsonNode(_node, "ForStatement", { - make_pair("initExpression", toJsonOrNull(_node.initializationExpression())), + make_pair("initializationExpression", toJsonOrNull(_node.initializationExpression())), make_pair("condition", toJsonOrNull(_node.condition())), make_pair("loopExpression", toJsonOrNull(_node.loopExpression())), make_pair("body", toJson(_node.body())) @@ -623,7 +618,7 @@ bool ASTJsonConverter::visit(FunctionCall const& _node) names.append(Json::Value(*name)); std::vector> attributes = { make_pair(m_legacy ? "type_conversion" : "isTypeConversion", _node.annotation().isTypeConversion), - make_pair("isStructContstructorCall", _node.annotation().isStructConstructorCall), + make_pair("isStructConstructorCall", _node.annotation().isStructConstructorCall), make_pair("expression", toJson(_node.expression())), make_pair("names", std::move(names)), make_pair("arguments", toJson(_node.arguments())) @@ -752,6 +747,21 @@ string ASTJsonConverter::location(VariableDeclaration::Location _location) } } +string ASTJsonConverter::contractKind(ContractDefinition::ContractKind _kind) +{ + switch (_kind) + { + case ContractDefinition::ContractKind::Interface: + return "interface"; + case ContractDefinition::ContractKind::Contract: + return "contract"; + case ContractDefinition::ContractKind::Library: + return "library"; + default: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown contract kind.")); + } +} + string ASTJsonConverter::type(Expression const& _expression) { return _expression.annotation().type ? _expression.annotation().type->toString() : "Unknown"; diff --git a/libsolidity/ast/ASTJsonConverter.h b/libsolidity/ast/ASTJsonConverter.h index aab8c1246..1499c3b86 100644 --- a/libsolidity/ast/ASTJsonConverter.h +++ b/libsolidity/ast/ASTJsonConverter.h @@ -130,6 +130,7 @@ private: } std::string visibility(Declaration::Visibility const& _visibility); std::string location(VariableDeclaration::Location _location); + std::string contractKind(ContractDefinition::ContractKind _kind); std::string type(Expression const& _expression); std::string type(VariableDeclaration const& _varDecl); int nodeId(ASTNode const& _node) From e3583d04f79c5e9ada9914f43711d3b90242dfdc Mon Sep 17 00:00:00 2001 From: djudjuu Date: Wed, 17 May 2017 15:52:45 +0200 Subject: [PATCH 6/9] include new InlineAssemblyInformation into JSON --- libsolidity/ast/ASTJsonConverter.cpp | 14 ++++++++++++-- libsolidity/ast/ASTJsonConverter.h | 1 + 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index 492429d70..3c3ceae86 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -171,6 +171,16 @@ void ASTJsonConverter::appendExpressionAttributes( _attributes.insert(_attributes.end(), exprAttributes.begin(), exprAttributes.end()); } +Json::Value ASTJsonConverter::inlineAssemblyIdentifierToJson(pair _info) +{ + Json::Value tuple(Json::objectValue); + tuple["src"] = sourceLocationToString(_info.first->location); + tuple["declaration"] = idOrNull(_info.second.declaration); + tuple["isSlot"] = Json::Value(_info.second.isSlot); + tuple["isOffset"] = Json::Value(_info.second.isOffset); + tuple["valueSize"] = _info.second.valueSize; + return tuple; +} void ASTJsonConverter::print(ostream& _stream, ASTNode const& _node) { @@ -441,10 +451,10 @@ bool ASTJsonConverter::visit(InlineAssembly const& _node) Json::Value externalReferences(Json::arrayValue); for (auto const& it : _node.annotation().externalReferences) { - if (it.first && it.second) + if (it.first) { Json::Value tuple(Json::objectValue); - tuple[it.first->name] = nodeId(*it.second); + tuple[it.first->name] = inlineAssemblyIdentifierToJson(it); externalReferences.append(tuple); } } diff --git a/libsolidity/ast/ASTJsonConverter.h b/libsolidity/ast/ASTJsonConverter.h index 1499c3b86..cf62e5f5f 100644 --- a/libsolidity/ast/ASTJsonConverter.h +++ b/libsolidity/ast/ASTJsonConverter.h @@ -128,6 +128,7 @@ private: { return _node ? toJson(*_node) : Json::nullValue; } + Json::Value inlineAssemblyIdentifierToJson(std::pair _info); std::string visibility(Declaration::Visibility const& _visibility); std::string location(VariableDeclaration::Location _location); std::string contractKind(ContractDefinition::ContractKind _kind); From 6316a76ab915e03e02825ce391d3812098c6b682 Mon Sep 17 00:00:00 2001 From: djudjuu Date: Wed, 17 May 2017 18:22:39 +0200 Subject: [PATCH 7/9] testsuite adjustment --- libsolidity/ast/ASTJsonConverter.h | 8 ++++---- test/libsolidity/JSONCompiler.cpp | 8 +++++--- test/libsolidity/StandardCompiler.cpp | 4 ++-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/libsolidity/ast/ASTJsonConverter.h b/libsolidity/ast/ASTJsonConverter.h index cf62e5f5f..3d6035a4d 100644 --- a/libsolidity/ast/ASTJsonConverter.h +++ b/libsolidity/ast/ASTJsonConverter.h @@ -139,13 +139,13 @@ private: return _node.id(); } template - Json::Value getContainerIds(Container container) + Json::Value getContainerIds(Container const& container) { Json::Value tmp(Json::arrayValue); - for (auto it = container.begin(); it != container.end(); ++it) + for (auto const& element: container) { - solAssert(*it, ""); - tmp.append(nodeId(**it)); + solAssert(element, ""); + tmp.append(nodeId(*element)); } return tmp; } diff --git a/test/libsolidity/JSONCompiler.cpp b/test/libsolidity/JSONCompiler.cpp index 46c718d7a..6aec59ab9 100644 --- a/test/libsolidity/JSONCompiler.cpp +++ b/test/libsolidity/JSONCompiler.cpp @@ -90,10 +90,12 @@ BOOST_AUTO_TEST_CASE(basic_compilation) BOOST_CHECK(result["sources"]["fileA"].isObject()); BOOST_CHECK(result["sources"]["fileA"]["AST"].isObject()); BOOST_CHECK(dev::jsonCompactPrint(result["sources"]["fileA"]["AST"]) == - "{\"children\":[{\"attributes\":{\"fullyImplemented\":true,\"isLibrary\":false,\"linearizedBaseContracts\":[1]," - "\"name\":\"A\"},\"children\":[],\"id\":1,\"name\":\"ContractDefinition\",\"src\":\"0:14:0\"}],\"name\":\"SourceUnit\"}"); + "{\"attributes\":{\"absolutePath\":\"fileA\",\"exportedSymbols\":{\"A\":[1]}}," + "\"children\":[{\"attributes\":{\"baseContracts\":[null],\"contractDependencies\":[null]," + "\"contractKind\":\"contract\",\"fullyImplemented\":true,\"linearizedBaseContracts\":[1]," + "\"name\":\"A\",\"nodes\":[null],\"scope\":2},\"id\":1,\"name\":\"ContractDefinition\"," + "\"src\":\"0:14:0\"}],\"id\":2,\"name\":\"SourceUnit\",\"src\":\"0:14:0\"}"); } - BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp index f4d277bd2..050ca500d 100644 --- a/test/libsolidity/StandardCompiler.cpp +++ b/test/libsolidity/StandardCompiler.cpp @@ -216,8 +216,8 @@ BOOST_AUTO_TEST_CASE(basic_compilation) BOOST_CHECK(result["sources"]["fileA"]["legacyAST"].isObject()); BOOST_CHECK(dev::jsonCompactPrint(result["sources"]["fileA"]["legacyAST"]) == "{\"attributes\":{\"absolutePath\":\"fileA\",\"exportedSymbols\":{\"A\":[1]}},\"children\":" - "[{\"attributes\":{\"baseContracts\":[null],\"contractDependencies\":[null],\"fullyImplemented\":true," - "\"isLibrary\":false,\"linearizedBaseContracts\":[1],\"name\":\"A\",\"nodes\":[null],\"scope\":2}," + "[{\"attributes\":{\"baseContracts\":[null],\"contractDependencies\":[null],\"contractKind\":\"contract\"," + "\"fullyImplemented\":true,\"linearizedBaseContracts\":[1],\"name\":\"A\",\"nodes\":[null],\"scope\":2}," "\"id\":1,\"name\":\"ContractDefinition\",\"src\":\"0:14:0\"}],\"id\":2,\"name\":\"SourceUnit\",\"src\":\"0:14:0\"}"); } From 1d22233a43453a21d9fde6e4ba91e26d651045bd Mon Sep 17 00:00:00 2001 From: djudjuu Date: Fri, 19 May 2017 15:45:01 +0200 Subject: [PATCH 8/9] refactoring functionCallAnnotation --- libsolidity/analysis/TypeChecker.cpp | 15 ++++++---- libsolidity/ast/ASTAnnotations.h | 13 +++++--- libsolidity/ast/ASTJsonConverter.cpp | 35 +++++++++++++++++----- libsolidity/ast/ASTJsonConverter.h | 1 + libsolidity/codegen/ExpressionCompiler.cpp | 6 ++-- libsolidity/formal/Why3Translator.cpp | 2 +- 6 files changed, 51 insertions(+), 21 deletions(-) diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 38cdc1f86..b8221a2ce 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1238,13 +1238,16 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) if (auto const* typeType = dynamic_cast(expressionType.get())) { - _functionCall.annotation().isStructConstructorCall = (typeType->actualType()->category() == Type::Category::Struct); - _functionCall.annotation().isTypeConversion = !_functionCall.annotation().isStructConstructorCall; + if (typeType->actualType()->category() == Type::Category::Struct) + _functionCall.annotation().kind = FunctionCallKind::StructConstructorCall; + else + _functionCall.annotation().kind = FunctionCallKind::TypeConversion; + } else - _functionCall.annotation().isStructConstructorCall = _functionCall.annotation().isTypeConversion = false; + _functionCall.annotation().kind = FunctionCallKind::FunctionCall; - if (_functionCall.annotation().isTypeConversion) + if (_functionCall.annotation().kind == FunctionCallKind::TypeConversion) { TypeType const& t = dynamic_cast(*expressionType); TypePointer resultType = t.actualType(); @@ -1274,7 +1277,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) /// For error message: Struct members that were removed during conversion to memory. set membersRemovedForStructConstructor; - if (_functionCall.annotation().isStructConstructorCall) + if (_functionCall.annotation().kind == FunctionCallKind::StructConstructorCall) { TypeType const& t = dynamic_cast(*expressionType); auto const& structType = dynamic_cast(*t.actualType()); @@ -1312,7 +1315,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) toString(parameterTypes.size()) + "."; // Extend error message in case we try to construct a struct with mapping member. - if (_functionCall.annotation().isStructConstructorCall && !membersRemovedForStructConstructor.empty()) + if (_functionCall.annotation().kind == FunctionCallKind::StructConstructorCall && !membersRemovedForStructConstructor.empty()) { msg += " Members that have to be skipped in memory:"; for (auto const& member: membersRemovedForStructConstructor) diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h index a7d892485..45a6dd1a4 100644 --- a/libsolidity/ast/ASTAnnotations.h +++ b/libsolidity/ast/ASTAnnotations.h @@ -200,12 +200,17 @@ struct BinaryOperationAnnotation: ExpressionAnnotation TypePointer commonType; }; +enum class FunctionCallKind +{ + Unset, + FunctionCall, + TypeConversion, + StructConstructorCall +}; + struct FunctionCallAnnotation: ExpressionAnnotation { - /// Whether this is an explicit type conversion. - bool isTypeConversion = false; - /// Whether this is a struct constructor call. - bool isStructConstructorCall = false; + FunctionCallKind kind = FunctionCallKind::Unset; }; } diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index 3c3ceae86..81996678f 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -156,19 +156,19 @@ Json::Value ASTJsonConverter::typePointerToJson(std::shared_ptr> &_attributes, + std::vector>& _attributes, ExpressionAnnotation const& _annotation ) { std::vector> exprAttributes = { - make_pair("typeDescriptions", typePointerToJson(_annotation.type)), + make_pair("typeDescriptions", typePointerToJson(_annotation.type)), make_pair("isConstant", _annotation.isConstant), make_pair("isPure", _annotation.isPure), make_pair("isLValue", _annotation.isLValue), make_pair("lValueRequested", _annotation.lValueRequested), make_pair("argumentTypes", typePointerToJson(_annotation.argumentTypes)) }; - _attributes.insert(_attributes.end(), exprAttributes.begin(), exprAttributes.end()); + _attributes += exprAttributes; } Json::Value ASTJsonConverter::inlineAssemblyIdentifierToJson(pair _info) @@ -344,6 +344,7 @@ bool ASTJsonConverter::visit(VariableDeclaration const& _node) make_pair("name", _node.name()), make_pair("typeName", toJsonOrNull(_node.typeName())), make_pair("constant", _node.isConstant()), + make_pair("stateVariable", _node.isStateVariable()), make_pair("storageLocation", location(_node.referenceLocation())), make_pair("visibility", visibility(_node.visibility())), make_pair("value", _node.value() ? toJson(*_node.value()) : Json::nullValue), @@ -627,12 +628,17 @@ bool ASTJsonConverter::visit(FunctionCall const& _node) for (auto const& name: _node.names()) names.append(Json::Value(*name)); std::vector> attributes = { - make_pair(m_legacy ? "type_conversion" : "isTypeConversion", _node.annotation().isTypeConversion), - make_pair("isStructConstructorCall", _node.annotation().isStructConstructorCall), make_pair("expression", toJson(_node.expression())), make_pair("names", std::move(names)), make_pair("arguments", toJson(_node.arguments())) - }; + }; + if (m_legacy) + { + attributes.push_back(make_pair("isStructConstructorCall", functionCallKind(_node.annotation().kind))); + attributes.push_back(make_pair("type_conversion", _node.annotation().kind == FunctionCallKind::TypeConversion)); + } + else + attributes.push_back(make_pair("kind", functionCallKind(_node.annotation().kind))); appendExpressionAttributes(attributes, _node.annotation()); setJsonNode(_node, "FunctionCall", std::move(attributes)); return false; @@ -768,7 +774,22 @@ string ASTJsonConverter::contractKind(ContractDefinition::ContractKind _kind) case ContractDefinition::ContractKind::Library: return "library"; default: - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown contract kind.")); + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown kind of contract.")); + } +} + +string ASTJsonConverter::functionCallKind(FunctionCallKind _kind) +{ + switch (_kind) + { + case FunctionCallKind::FunctionCall: + return "functionCall"; + case FunctionCallKind::TypeConversion: + return "typeConversion"; + case FunctionCallKind::StructConstructorCall: + return "structConstructorCall"; + default: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown kind of function call .")); } } diff --git a/libsolidity/ast/ASTJsonConverter.h b/libsolidity/ast/ASTJsonConverter.h index 3d6035a4d..5ee405366 100644 --- a/libsolidity/ast/ASTJsonConverter.h +++ b/libsolidity/ast/ASTJsonConverter.h @@ -132,6 +132,7 @@ private: std::string visibility(Declaration::Visibility const& _visibility); std::string location(VariableDeclaration::Location _location); std::string contractKind(ContractDefinition::ContractKind _kind); + std::string functionCallKind(FunctionCallKind _kind); std::string type(Expression const& _expression); std::string type(VariableDeclaration const& _varDecl); int nodeId(ASTNode const& _node) diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index f018b311f..0aa82ea82 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -434,7 +434,7 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation) bool ExpressionCompiler::visit(FunctionCall const& _functionCall) { CompilerContext::LocationSetter locationSetter(m_context, _functionCall); - if (_functionCall.annotation().isTypeConversion) + if (_functionCall.annotation().kind == FunctionCallKind::TypeConversion) { solAssert(_functionCall.arguments().size() == 1, ""); solAssert(_functionCall.names().empty(), ""); @@ -445,7 +445,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) } FunctionTypePointer functionType; - if (_functionCall.annotation().isStructConstructorCall) + if (_functionCall.annotation().kind == FunctionCallKind::StructConstructorCall) { auto const& type = dynamic_cast(*_functionCall.expression().annotation().type); auto const& structType = dynamic_cast(*type.actualType()); @@ -476,7 +476,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) solAssert(found, ""); } - if (_functionCall.annotation().isStructConstructorCall) + if (_functionCall.annotation().kind == FunctionCallKind::StructConstructorCall) { TypeType const& type = dynamic_cast(*_functionCall.expression().annotation().type); auto const& structType = dynamic_cast(*type.actualType()); diff --git a/libsolidity/formal/Why3Translator.cpp b/libsolidity/formal/Why3Translator.cpp index b6f179074..77d3c2177 100644 --- a/libsolidity/formal/Why3Translator.cpp +++ b/libsolidity/formal/Why3Translator.cpp @@ -582,7 +582,7 @@ bool Why3Translator::visit(BinaryOperation const& _binaryOperation) bool Why3Translator::visit(FunctionCall const& _node) { - if (_node.annotation().isTypeConversion || _node.annotation().isStructConstructorCall) + if (_node.annotation().kind == FunctionCallKind::TypeConversion || _node.annotation().kind == FunctionCallKind::StructConstructorCall) { error(_node, "Only ordinary function calls supported."); return true; From e82df073d15237455b1e53e35ef544aea72a69f9 Mon Sep 17 00:00:00 2001 From: djudjuu Date: Mon, 22 May 2017 11:51:45 +0200 Subject: [PATCH 9/9] minor fixes and changelog update --- Changelog.md | 1 + libsolidity/analysis/TypeChecker.cpp | 1 + libsolidity/ast/ASTJsonConverter.cpp | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index be5c18c52..650d75d89 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,4 +1,5 @@ ### 0.4.12 (unreleased) + * AST: export all attributes to Json format ### 0.4.11 (2017-05-03) diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index b8221a2ce..8161a3a12 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1246,6 +1246,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) } else _functionCall.annotation().kind = FunctionCallKind::FunctionCall; + solAssert(_functionCall.annotation().kind != FunctionCallKind::Unset, ""); if (_functionCall.annotation().kind == FunctionCallKind::TypeConversion) { diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index 81996678f..40c552a3d 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -634,7 +634,7 @@ bool ASTJsonConverter::visit(FunctionCall const& _node) }; if (m_legacy) { - attributes.push_back(make_pair("isStructConstructorCall", functionCallKind(_node.annotation().kind))); + attributes.push_back(make_pair("isStructConstructorCall", _node.annotation().kind == FunctionCallKind::StructConstructorCall)); attributes.push_back(make_pair("type_conversion", _node.annotation().kind == FunctionCallKind::TypeConversion)); } else