From 4613214098850490c0da24cfca5c36e5ce014512 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 3 Dec 2014 16:40:37 +0100 Subject: [PATCH] Moving all Interface and Documentation functionality to own class - Creating the Interface Handler class which will take care of the parsing of Natspec comments and of interfacing with and outputing to JSON files. - Will also handle the ABI interface creation --- libsolidity/CompilerStack.cpp | 90 +++++++----------------------- libsolidity/CompilerStack.h | 26 ++++++--- libsolidity/InterfaceHandler.cpp | 88 +++++++++++++++++++++++++++++ libsolidity/InterfaceHandler.h | 74 ++++++++++++++++++++++++ solc/main.cpp | 5 +- test/solidityJSONInterfaceTest.cpp | 2 +- test/solidityNatspecJSON.cpp | 4 +- 7 files changed, 205 insertions(+), 84 deletions(-) create mode 100644 libsolidity/InterfaceHandler.cpp create mode 100644 libsolidity/InterfaceHandler.h diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index b12097052..6f80d245c 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -27,8 +27,7 @@ #include #include #include - -#include +#include using namespace std; @@ -37,6 +36,8 @@ namespace dev namespace solidity { +CompilerStack::CompilerStack():m_interfaceHandler(make_shared()){} + void CompilerStack::setSource(string const& _sourceCode) { reset(); @@ -83,84 +84,33 @@ void CompilerStack::streamAssembly(ostream& _outStream) m_compiler->streamAssembly(_outStream); } -string const& CompilerStack::getInterface() -{ - Json::StyledWriter writer; - if (!m_parseSuccessful) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); - - if (m_interface.empty()) - { - Json::Value methods(Json::arrayValue); - - vector exportedFunctions = m_contractASTNode->getInterfaceFunctions(); - for (FunctionDefinition const* f: exportedFunctions) - { - Json::Value method; - Json::Value inputs(Json::arrayValue); - Json::Value outputs(Json::arrayValue); - - auto streamVariables = [](vector> const& _vars) - { - Json::Value params(Json::arrayValue); - for (ASTPointer const& var: _vars) - { - Json::Value input; - input["name"] = var->getName(); - input["type"] = var->getType()->toString(); - params.append(input); - } - return params; - }; - - method["name"] = f->getName(); - method["inputs"] = streamVariables(f->getParameters()); - method["outputs"] = streamVariables(f->getReturnParameters()); - methods.append(method); - } - m_interface = writer.write(methods); - } - return m_interface; -} - -string const& CompilerStack::getUserDocumentation() +std::string const* CompilerStack::getJsonDocumentation(enum documentation_type _type) { - Json::StyledWriter writer; if (!m_parseSuccessful) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); - if (m_userDocumentation.empty()) + auto createOrReturnDoc = [&, this](std::unique_ptr& _doc) { - Json::Value doc; - Json::Value methods(Json::objectValue); - - for (FunctionDefinition const* f: m_contractASTNode->getInterfaceFunctions()) + if(!_doc) { - Json::Value user; - auto strPtr = f->getDocumentation(); - if (strPtr) - { - user["notice"] = Json::Value(*strPtr); - methods[f->getName()] = user; - } + _doc = m_interfaceHandler->getDocumentation(m_contractASTNode, _type); } - doc["methods"] = methods; - m_userDocumentation = writer.write(doc); - } - return m_userDocumentation; -} - -string const& CompilerStack::getDevDocumentation() -{ - Json::StyledWriter writer; - if (!m_parseSuccessful) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); + }; - if (m_devDocumentation.empty()) + switch (_type) { - // TODO + case NATSPEC_USER: + createOrReturnDoc(m_userDocumentation); + return m_userDocumentation.get(); + case NATSPEC_DEV: + createOrReturnDoc(m_devDocumentation); + return m_devDocumentation.get(); + case ABI_INTERFACE: + createOrReturnDoc(m_interface); + return m_interface.get(); } - return m_devDocumentation; + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Internal error")); + return nullptr; } bytes CompilerStack::staticCompile(std::string const& _sourceCode, bool _optimize) diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index 4e0d2251b..7dc86e2be 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -35,6 +35,14 @@ class Scanner; class ContractDefinition; class Compiler; class GlobalContext; +class InterfaceHandler; + +enum documentation_type : unsigned short +{ + NATSPEC_USER = 1, + NATSPEC_DEV, + ABI_INTERFACE +}; /** * Easy to use and self-contained Solidity compiler with as few header dependencies as possible. @@ -44,7 +52,7 @@ class GlobalContext; class CompilerStack { public: - CompilerStack() {} + CompilerStack(); void reset() { *this = CompilerStack(); } void setSource(std::string const& _sourceCode); void parse(); @@ -62,12 +70,11 @@ public: /// Returns a string representing the contract interface in JSON. /// Prerequisite: Successful call to parse or compile. std::string const& getInterface(); - /// Returns a string representing the contract's user documentation in JSON. - /// Prerequisite: Successful call to parse or compile. - std::string const& getUserDocumentation(); - /// Returns a string representing the contract's developer documentation in JSON. + /// Returns a string representing the contract's documentation in JSON. /// Prerequisite: Successful call to parse or compile. - std::string const& getDevDocumentation(); + /// @param type The type of the documentation to get. + /// Can be one of 3 types defined at @c documentation_type + std::string const* getJsonDocumentation(enum documentation_type type); /// Returns the previously used scanner, useful for counting lines during error reporting. Scanner const& getScanner() const { return *m_scanner; } @@ -82,10 +89,11 @@ private: std::shared_ptr m_globalContext; std::shared_ptr m_contractASTNode; bool m_parseSuccessful; - std::string m_interface; - std::string m_userDocumentation; - std::string m_devDocumentation; + std::unique_ptr m_interface; + std::unique_ptr m_userDocumentation; + std::unique_ptr m_devDocumentation; std::shared_ptr m_compiler; + std::shared_ptr m_interfaceHandler; bytes m_bytecode; }; diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp new file mode 100644 index 000000000..c0e07280e --- /dev/null +++ b/libsolidity/InterfaceHandler.cpp @@ -0,0 +1,88 @@ +#include +#include +#include + +namespace dev { +namespace solidity { + +InterfaceHandler::InterfaceHandler() +{ +} + +std::unique_ptr InterfaceHandler::getDocumentation(std::shared_ptr _contractDef, + enum documentation_type _type) +{ + switch(_type) + { + case NATSPEC_USER: + return getUserDocumentation(_contractDef); + case NATSPEC_DEV: + return getDevDocumentation(_contractDef); + case ABI_INTERFACE: + return getABIInterface(_contractDef); + } + + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Internal error")); + return nullptr; +} + +std::unique_ptr InterfaceHandler::getABIInterface(std::shared_ptr _contractDef) +{ + Json::Value methods(Json::arrayValue); + + std::vector exportedFunctions = _contractDef->getInterfaceFunctions(); + for (FunctionDefinition const* f: exportedFunctions) + { + Json::Value method; + Json::Value inputs(Json::arrayValue); + Json::Value outputs(Json::arrayValue); + + auto streamVariables = [](std::vector> const& _vars) + { + Json::Value params(Json::arrayValue); + for (ASTPointer const& var: _vars) + { + Json::Value input; + input["name"] = var->getName(); + input["type"] = var->getType()->toString(); + params.append(input); + } + return params; + }; + + method["name"] = f->getName(); + method["inputs"] = streamVariables(f->getParameters()); + method["outputs"] = streamVariables(f->getReturnParameters()); + methods.append(method); + } + return std::unique_ptr(new std::string(m_writer.write(methods))); +} + +std::unique_ptr InterfaceHandler::getUserDocumentation(std::shared_ptr _contractDef) +{ + Json::Value doc; + Json::Value methods(Json::objectValue); + + for (FunctionDefinition const* f: _contractDef->getInterfaceFunctions()) + { + Json::Value user; + auto strPtr = f->getDocumentation(); + if (strPtr) + { + user["notice"] = Json::Value(*strPtr); + methods[f->getName()] = user; + } + } + doc["methods"] = methods; + + return std::unique_ptr(new std::string(m_writer.write(doc))); +} + +std::unique_ptr InterfaceHandler::getDevDocumentation(std::shared_ptr _contractDef) +{ + //TODO + return nullptr; +} + +} //solidity NS +} // dev NS diff --git a/libsolidity/InterfaceHandler.h b/libsolidity/InterfaceHandler.h new file mode 100644 index 000000000..ed6c8ba44 --- /dev/null +++ b/libsolidity/InterfaceHandler.h @@ -0,0 +1,74 @@ +/* + 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 . +*/ +/** + * @author Lefteris + * @date 2014 + * Takes the parsed AST and produces the Natspec + * documentation and the ABI interface + * https://github.com/ethereum/wiki/wiki/Ethereum-Natural-Specification-Format + * + * Can generally deal with JSON files + */ + +#pragma once + +#include +#include +#include + +namespace dev { +namespace solidity { + +// Forward declarations +class ContractDefinition; +enum documentation_type: unsigned short; + +class InterfaceHandler +{ +public: + InterfaceHandler(); + + /// Get the given type of documentation + /// @param _contractDef The contract definition + /// @param _type The type of the documentation. Can be one of the + /// types provided by @c documentation_type + /// @return A unique pointer contained string with the json + /// representation of provided type + std::unique_ptr getDocumentation(std::shared_ptr _contractDef, + enum documentation_type _type); + /// Get the ABI Interface of the contract + /// @param _contractDef The contract definition + /// @return A unique pointer contained string with the json + /// representation of the contract's ABI Interface + std::unique_ptr getABIInterface(std::shared_ptr _contractDef); + /// Get the User documentation of the contract + /// @param _contractDef The contract definition + /// @return A unique pointer contained string with the json + /// representation of the contract's user documentation + std::unique_ptr getUserDocumentation(std::shared_ptr _contractDef); + /// Get the Developer's documentation of the contract + /// @param _contractDef The contract definition + /// @return A unique pointer contained string with the json + /// representation of the contract's developer documentation + std::unique_ptr getDevDocumentation(std::shared_ptr _contractDef); + +private: + Json::StyledWriter m_writer; +}; + +} //solidity NS +} // dev NS diff --git a/solc/main.cpp b/solc/main.cpp index 29239a717..daeb2707c 100644 --- a/solc/main.cpp +++ b/solc/main.cpp @@ -135,8 +135,9 @@ int main(int argc, char** argv) cout << "Opcodes:" << endl; cout << eth::disassemble(compiler.getBytecode()) << endl; cout << "Binary: " << toHex(compiler.getBytecode()) << endl; - cout << "Interface specification: " << compiler.getInterface() << endl; - cout << "Natspec user documentation: " << compiler.getUserDocumentation() << endl; + cout << "Interface specification: " << compiler.getJsonDocumentation(ABI_INTERFACE) << endl; + cout << "Natspec user documentation: " << compiler.getJsonDocumentation(NATSPEC_USER) << endl; + cout << "Natspec developer documentation: " << compiler.getJsonDocumentation(NATSPEC_DEV) << endl; return 0; } diff --git a/test/solidityJSONInterfaceTest.cpp b/test/solidityJSONInterfaceTest.cpp index f46a3ad36..8fe0ea653 100644 --- a/test/solidityJSONInterfaceTest.cpp +++ b/test/solidityJSONInterfaceTest.cpp @@ -50,7 +50,7 @@ public: msg += *extra; BOOST_FAIL(msg); } - std::string generatedInterfaceString = m_compilerStack.getInterface(); + std::string generatedInterfaceString = *m_compilerStack.getJsonDocumentation(ABI_INTERFACE); Json::Value generatedInterface; m_reader.parse(generatedInterfaceString, generatedInterface); Json::Value expectedInterface; diff --git a/test/solidityNatspecJSON.cpp b/test/solidityNatspecJSON.cpp index f729e4ff8..9e24d23ed 100644 --- a/test/solidityNatspecJSON.cpp +++ b/test/solidityNatspecJSON.cpp @@ -55,9 +55,9 @@ public: } if (_userDocumentation) - generatedDocumentationString = m_compilerStack.getUserDocumentation(); + generatedDocumentationString = *m_compilerStack.getJsonDocumentation(NATSPEC_USER); else - generatedDocumentationString = m_compilerStack.getDevDocumentation(); + generatedDocumentationString = *m_compilerStack.getJsonDocumentation(NATSPEC_DEV); Json::Value generatedDocumentation; m_reader.parse(generatedDocumentationString, generatedDocumentation); Json::Value expectedDocumentation;