From 43d6726dd78e35bf79fa2da3824c2916c5e6b0a8 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 1 Dec 2014 17:03:04 +0100 Subject: Exporting Natspec documentation to a JSON interface - Adding a getDocumentation() function to solidity compiler stack so that we can obtain the natspec interface for a contract - Adding libjsoncpp as a dependency of libsolidity. This is done in a dirty way, using libjsonrpc-cpp s an intermediate dependency for the moment. Will fix soon. - Start of a test file for Natspec exporting to JSON --- AST.h | 2 +- CMakeLists.txt | 4 ++++ CompilerStack.cpp | 26 ++++++++++++++++++++++++++ CompilerStack.h | 4 ++++ 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/AST.h b/AST.h index 81a12ad1..4ed8489f 100644 --- a/AST.h +++ b/AST.h @@ -199,7 +199,7 @@ public: Block& getBody() { return *m_body; } /// @return A shared pointer of an ASTString. /// Can contain a nullptr in which case indicates absence of documentation - ASTPointer const& getDocumentation() { return m_documentation; } + ASTPointer const& getDocumentation() const { return m_documentation; } void addLocalVariable(VariableDeclaration const& _localVariable) { m_localVariables.push_back(&_localVariable); } std::vector const& getLocalVariables() const { return m_localVariables; } diff --git a/CMakeLists.txt b/CMakeLists.txt index ea2ef4b7..b5147ced 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,10 @@ endif() include_directories(..) target_link_libraries(${EXECUTABLE} evmcore devcore) +# TODO: Temporary until PR 532 https://github.com/ethereum/cpp-ethereum/pull/532 +# gets accepted. Then we can simply add jsoncpp as a dependency and not the +# whole of JSONRPC as we are doing right here +target_link_libraries(${EXECUTABLE} ${JSONRPC_LS}) install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) diff --git a/CompilerStack.cpp b/CompilerStack.cpp index 6535e00d..45d3e0b8 100644 --- a/CompilerStack.cpp +++ b/CompilerStack.cpp @@ -28,6 +28,8 @@ #include #include +#include + using namespace std; namespace dev @@ -125,6 +127,30 @@ string const& CompilerStack::getInterface() return m_interface; } +string const& CompilerStack::getDocumentation() +{ + + Json::StyledWriter writer; + if (!m_parseSuccessful) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); + if (m_documentation.empty()) + { + Json::Value doc; + Json::Value methods; + + vector exportedFunctions = m_contractASTNode->getInterfaceFunctions(); + for (FunctionDefinition const* f: exportedFunctions) + { + Json::Value user; + user["user"] = Json::Value(*f->getDocumentation()); + methods[f->getName()] = user; + } + doc["methods"] = methods; + m_documentation = writer.write(doc); + } + return m_documentation; +} + bytes CompilerStack::staticCompile(std::string const& _sourceCode, bool _optimize) { CompilerStack stack; diff --git a/CompilerStack.h b/CompilerStack.h index 6cae8660..74784c5e 100644 --- a/CompilerStack.h +++ b/CompilerStack.h @@ -62,6 +62,9 @@ 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 documentation in JSON. + /// Prerequisite: Successful call to parse or compile. + std::string const& getDocumentation(); /// Returns the previously used scanner, useful for counting lines during error reporting. Scanner const& getScanner() const { return *m_scanner; } @@ -77,6 +80,7 @@ private: std::shared_ptr m_contractASTNode; bool m_parseSuccessful; std::string m_interface; + std::string m_documentation; std::shared_ptr m_compiler; bytes m_bytecode; }; -- cgit From 0f79ed6957c65fbe9e09ffa8f9b5e3d6dca4a210 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 1 Dec 2014 18:01:42 +0100 Subject: Using jsoncpp for exporting ABI interface from solidity - Also changing the interface JSON test to have a shorter name plus to provide meaningful error message in case of failure --- CompilerStack.cpp | 48 +++++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/CompilerStack.cpp b/CompilerStack.cpp index 45d3e0b8..e25438f7 100644 --- a/CompilerStack.cpp +++ b/CompilerStack.cpp @@ -85,54 +85,52 @@ void CompilerStack::streamAssembly(ostream& _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()) { - stringstream interface; - interface << '['; + Json::Value methods(Json::arrayValue); + vector exportedFunctions = m_contractASTNode->getInterfaceFunctions(); - unsigned functionsCount = exportedFunctions.size(); for (FunctionDefinition const* f: exportedFunctions) { - auto streamVariables = [&](vector> const& _vars) + Json::Value method; + Json::Value inputs(Json::arrayValue); + Json::Value outputs(Json::arrayValue); + + auto streamVariables = [&](vector> const& _vars, + Json::Value &json) { - unsigned varCount = _vars.size(); for (ASTPointer const& var: _vars) { - interface << "{" - << "\"name\":" << escaped(var->getName(), false) << "," - << "\"type\":" << escaped(var->getType()->toString(), false) - << "}"; - if (--varCount > 0) - interface << ","; + Json::Value input; + input["name"] = var->getName(); + input["type"] = var->getType()->toString(); + json.append(input); } }; - interface << '{' - << "\"name\":" << escaped(f->getName(), false) << "," - << "\"inputs\":["; - streamVariables(f->getParameters()); - interface << "]," - << "\"outputs\":["; - streamVariables(f->getReturnParameters()); - interface << "]" - << "}"; - if (--functionsCount > 0) - interface << ","; + method["name"] = f->getName(); + streamVariables(f->getParameters(), inputs); + method["inputs"] = inputs; + streamVariables(f->getReturnParameters(), outputs); + method["outputs"] = outputs; + + methods.append(method); } - interface << ']'; - m_interface = interface.str(); + m_interface = writer.write(methods); } return m_interface; } string const& CompilerStack::getDocumentation() { - Json::StyledWriter writer; if (!m_parseSuccessful) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); + if (m_documentation.empty()) { Json::Value doc; -- cgit From e4114492194e048d08ece9782ada1541629afc44 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 2 Dec 2014 10:41:18 +0100 Subject: More Natspec JSON export tests and better error reporting --- CompilerStack.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CompilerStack.cpp b/CompilerStack.cpp index e25438f7..77a019b5 100644 --- a/CompilerStack.cpp +++ b/CompilerStack.cpp @@ -134,7 +134,7 @@ string const& CompilerStack::getDocumentation() if (m_documentation.empty()) { Json::Value doc; - Json::Value methods; + Json::Value methods(Json::objectValue); vector exportedFunctions = m_contractASTNode->getInterfaceFunctions(); for (FunctionDefinition const* f: exportedFunctions) -- cgit From 0d3ab07ad1863ad89785c3e66d4e1969eac98a29 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 2 Dec 2014 11:03:34 +0100 Subject: Handle absence of Natspec doc and add option to solc --- CompilerStack.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CompilerStack.cpp b/CompilerStack.cpp index 77a019b5..2b299158 100644 --- a/CompilerStack.cpp +++ b/CompilerStack.cpp @@ -140,8 +140,12 @@ string const& CompilerStack::getDocumentation() for (FunctionDefinition const* f: exportedFunctions) { Json::Value user; - user["user"] = Json::Value(*f->getDocumentation()); - methods[f->getName()] = user; + auto strPtr = f->getDocumentation(); + if (strPtr) + { + user["user"] = Json::Value(*strPtr); + methods[f->getName()] = user; + } } doc["methods"] = methods; m_documentation = writer.write(doc); -- cgit From af9fb9917c338522d1949e2767c9709c770b2879 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 2 Dec 2014 12:14:24 +0100 Subject: Removing unneeded local variable in CompilerStack::getDocumentation() --- CompilerStack.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CompilerStack.cpp b/CompilerStack.cpp index 2b299158..48a37b9c 100644 --- a/CompilerStack.cpp +++ b/CompilerStack.cpp @@ -136,8 +136,7 @@ string const& CompilerStack::getDocumentation() Json::Value doc; Json::Value methods(Json::objectValue); - vector exportedFunctions = m_contractASTNode->getInterfaceFunctions(); - for (FunctionDefinition const* f: exportedFunctions) + for (FunctionDefinition const* f: m_contractASTNode->getInterfaceFunctions()) { Json::Value user; auto strPtr = f->getDocumentation(); -- cgit From 06998aa2d22b4d40fd9d5ad713f249252544ce8e Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 2 Dec 2014 17:18:09 +0100 Subject: Simplifying lambda function in CompilerStack::getInterface() --- CompilerStack.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/CompilerStack.cpp b/CompilerStack.cpp index 48a37b9c..e44a10fb 100644 --- a/CompilerStack.cpp +++ b/CompilerStack.cpp @@ -100,24 +100,22 @@ string const& CompilerStack::getInterface() Json::Value inputs(Json::arrayValue); Json::Value outputs(Json::arrayValue); - auto streamVariables = [&](vector> const& _vars, - Json::Value &json) + 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(); - json.append(input); + params.append(input); } + return params; }; method["name"] = f->getName(); - streamVariables(f->getParameters(), inputs); - method["inputs"] = inputs; - streamVariables(f->getReturnParameters(), outputs); - method["outputs"] = outputs; - + method["inputs"] = streamVariables(f->getParameters()); + method["outputs"] = streamVariables(f->getReturnParameters()); methods.append(method); } m_interface = writer.write(methods); -- cgit From be81981ec4a3a9e7704b230096d9a580175d759e Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 3 Dec 2014 13:50:04 +0100 Subject: Separate user and dev natspec documentation - plus other small changes according to the spec --- CompilerStack.cpp | 23 ++++++++++++++++++----- CompilerStack.h | 10 +++++++--- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/CompilerStack.cpp b/CompilerStack.cpp index e44a10fb..b1209705 100644 --- a/CompilerStack.cpp +++ b/CompilerStack.cpp @@ -123,13 +123,13 @@ string const& CompilerStack::getInterface() return m_interface; } -string const& CompilerStack::getDocumentation() +string const& CompilerStack::getUserDocumentation() { Json::StyledWriter writer; if (!m_parseSuccessful) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); - if (m_documentation.empty()) + if (m_userDocumentation.empty()) { Json::Value doc; Json::Value methods(Json::objectValue); @@ -140,14 +140,27 @@ string const& CompilerStack::getDocumentation() auto strPtr = f->getDocumentation(); if (strPtr) { - user["user"] = Json::Value(*strPtr); + user["notice"] = Json::Value(*strPtr); methods[f->getName()] = user; } } doc["methods"] = methods; - m_documentation = writer.write(doc); + m_userDocumentation = writer.write(doc); } - return m_documentation; + 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()) + { + // TODO + } + return m_devDocumentation; } bytes CompilerStack::staticCompile(std::string const& _sourceCode, bool _optimize) diff --git a/CompilerStack.h b/CompilerStack.h index 74784c5e..4e0d2251 100644 --- a/CompilerStack.h +++ b/CompilerStack.h @@ -62,9 +62,12 @@ 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 documentation in JSON. + /// Returns a string representing the contract's user documentation in JSON. /// Prerequisite: Successful call to parse or compile. - std::string const& getDocumentation(); + std::string const& getUserDocumentation(); + /// Returns a string representing the contract's developer documentation in JSON. + /// Prerequisite: Successful call to parse or compile. + std::string const& getDevDocumentation(); /// Returns the previously used scanner, useful for counting lines during error reporting. Scanner const& getScanner() const { return *m_scanner; } @@ -80,7 +83,8 @@ private: std::shared_ptr m_contractASTNode; bool m_parseSuccessful; std::string m_interface; - std::string m_documentation; + std::string m_userDocumentation; + std::string m_devDocumentation; std::shared_ptr m_compiler; bytes m_bytecode; }; -- cgit From d25581de7cc89470a060625c043dba8cf9ae293f Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 3 Dec 2014 16:40:37 +0100 Subject: 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 --- CompilerStack.cpp | 90 ++++++++++++---------------------------------------- CompilerStack.h | 26 +++++++++------ InterfaceHandler.cpp | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++ InterfaceHandler.h | 74 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 199 insertions(+), 79 deletions(-) create mode 100644 InterfaceHandler.cpp create mode 100644 InterfaceHandler.h diff --git a/CompilerStack.cpp b/CompilerStack.cpp index b1209705..6f80d245 100644 --- a/CompilerStack.cpp +++ b/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/CompilerStack.h b/CompilerStack.h index 4e0d2251..7dc86e2b 100644 --- a/CompilerStack.h +++ b/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/InterfaceHandler.cpp b/InterfaceHandler.cpp new file mode 100644 index 00000000..c0e07280 --- /dev/null +++ b/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/InterfaceHandler.h b/InterfaceHandler.h new file mode 100644 index 00000000..ed6c8ba4 --- /dev/null +++ b/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 -- cgit From a0ff2179d46404e265226981f8f7cd99c7aba5d1 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 3 Dec 2014 17:46:04 +0100 Subject: Work in progress for parsing natspec doxytags --- InterfaceHandler.cpp | 69 +++++++++++++++++++++++++++++++++++++++++++++++++--- InterfaceHandler.h | 11 +++++++-- 2 files changed, 75 insertions(+), 5 deletions(-) diff --git a/InterfaceHandler.cpp b/InterfaceHandler.cpp index c0e07280..a2c52c1f 100644 --- a/InterfaceHandler.cpp +++ b/InterfaceHandler.cpp @@ -5,12 +5,14 @@ namespace dev { namespace solidity { +/* -- public -- */ + InterfaceHandler::InterfaceHandler() { } std::unique_ptr InterfaceHandler::getDocumentation(std::shared_ptr _contractDef, - enum documentation_type _type) + enum documentation_type _type) { switch(_type) { @@ -80,8 +82,69 @@ std::unique_ptr InterfaceHandler::getUserDocumentation(std::shared_ std::unique_ptr InterfaceHandler::getDevDocumentation(std::shared_ptr _contractDef) { - //TODO - return nullptr; + Json::Value doc; + Json::Value methods(Json::objectValue); + + for (FunctionDefinition const* f: _contractDef->getInterfaceFunctions()) + { + Json::Value method; + auto strPtr = f->getDocumentation(); + if (strPtr) + { + m_dev.clear(); + parseDocString(*strPtr); + + method["dev"] = Json::Value(m_dev); + methods[f->getName()] = method; + } + } + doc["methods"] = methods; + + return std::unique_ptr(new std::string(m_writer.write(doc))); +} + +/* -- private -- */ +size_t InterfaceHandler::parseDocTag(std::string const& _string, std::string const& _tag, size_t _pos) +{ + size_t nlPos = _pos; + if (_tag == "dev") + { + nlPos = _string.find("\n", _pos); + m_dev += _string.substr(_pos, + nlPos == std::string::npos ? + _string.length() : + nlPos - _pos); + } + else if (_tag == "notice") + { + nlPos = _string.find("\n", _pos); + m_notice += _string.substr(_pos, + nlPos == std::string::npos ? + _string.length() : + nlPos - _pos); + } + else + { + //TODO: Some form of warning + } + + return nlPos; +} + +void InterfaceHandler::parseDocString(std::string const& _string, size_t _startPos) +{ + size_t pos2; + size_t pos1 = _string.find("@", _startPos); + + if (pos1 == std::string::npos) + return; // no doxytags found + + pos2 = _string.find(" ", pos1); + if (pos2 == std::string::npos) + return; //no end of tag found + + size_t newPos = parseDocTag(_string, _string.substr(pos1 + 1, pos2 - pos1), pos2); + parseDocString(_string, newPos); } } //solidity NS diff --git a/InterfaceHandler.h b/InterfaceHandler.h index ed6c8ba4..125ecda4 100644 --- a/InterfaceHandler.h +++ b/InterfaceHandler.h @@ -20,7 +20,7 @@ * 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 */ @@ -44,7 +44,7 @@ public: /// Get the given type of documentation /// @param _contractDef The contract definition - /// @param _type The type of the documentation. Can be one of the + /// @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 @@ -67,7 +67,14 @@ public: std::unique_ptr getDevDocumentation(std::shared_ptr _contractDef); private: + void parseDocString(std::string const& _string, size_t _startPos = 0); + size_t parseDocTag(std::string const& _string, std::string const& _tag, size_t _pos); + Json::StyledWriter m_writer; + + // internal state + std::string m_notice; + std::string m_dev; }; } //solidity NS -- cgit From ba27dc74214d70a4ce8dcfcbb0b15a829f2b050d Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 4 Dec 2014 01:27:38 +0100 Subject: Styling in libsolidity's InterfaceHandler --- CompilerStack.cpp | 4 ++-- CompilerStack.h | 4 ++-- InterfaceHandler.cpp | 8 ++++---- InterfaceHandler.h | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/CompilerStack.cpp b/CompilerStack.cpp index 6f80d245..3e9791bd 100644 --- a/CompilerStack.cpp +++ b/CompilerStack.cpp @@ -84,12 +84,12 @@ void CompilerStack::streamAssembly(ostream& _outStream) m_compiler->streamAssembly(_outStream); } -std::string const* CompilerStack::getJsonDocumentation(enum documentation_type _type) +std::string const* CompilerStack::getJsonDocumentation(enum documentationType _type) { if (!m_parseSuccessful) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); - auto createOrReturnDoc = [&, this](std::unique_ptr& _doc) + auto createOrReturnDoc = [this, _type](std::unique_ptr& _doc) { if(!_doc) { diff --git a/CompilerStack.h b/CompilerStack.h index 7dc86e2b..51195129 100644 --- a/CompilerStack.h +++ b/CompilerStack.h @@ -37,7 +37,7 @@ class Compiler; class GlobalContext; class InterfaceHandler; -enum documentation_type : unsigned short +enum documentationType: unsigned short { NATSPEC_USER = 1, NATSPEC_DEV, @@ -74,7 +74,7 @@ public: /// Prerequisite: Successful call to parse or compile. /// @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); + std::string const* getJsonDocumentation(enum documentationType type); /// Returns the previously used scanner, useful for counting lines during error reporting. Scanner const& getScanner() const { return *m_scanner; } diff --git a/InterfaceHandler.cpp b/InterfaceHandler.cpp index a2c52c1f..61570b8d 100644 --- a/InterfaceHandler.cpp +++ b/InterfaceHandler.cpp @@ -12,7 +12,7 @@ InterfaceHandler::InterfaceHandler() } std::unique_ptr InterfaceHandler::getDocumentation(std::shared_ptr _contractDef, - enum documentation_type _type) + enum documentationType _type) { switch(_type) { @@ -39,7 +39,7 @@ std::unique_ptr InterfaceHandler::getABIInterface(std::shared_ptr> const& _vars) + auto populateParameters = [](std::vector> const& _vars) { Json::Value params(Json::arrayValue); for (ASTPointer const& var: _vars) @@ -53,8 +53,8 @@ std::unique_ptr InterfaceHandler::getABIInterface(std::shared_ptrgetName(); - method["inputs"] = streamVariables(f->getParameters()); - method["outputs"] = streamVariables(f->getReturnParameters()); + method["inputs"] = populateParameters(f->getParameters()); + method["outputs"] = populateParameters(f->getReturnParameters()); methods.append(method); } return std::unique_ptr(new std::string(m_writer.write(methods))); diff --git a/InterfaceHandler.h b/InterfaceHandler.h index 125ecda4..5c8bf5bc 100644 --- a/InterfaceHandler.h +++ b/InterfaceHandler.h @@ -35,7 +35,7 @@ namespace solidity { // Forward declarations class ContractDefinition; -enum documentation_type: unsigned short; +enum documentationType: unsigned short; class InterfaceHandler { @@ -49,7 +49,7 @@ public: /// @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); + enum documentationType _type); /// Get the ABI Interface of the contract /// @param _contractDef The contract definition /// @return A unique pointer contained string with the json -- cgit From 3e803b40e1b22daf8e3ac45593aec6798d365ccb Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 4 Dec 2014 09:42:38 +0100 Subject: Parsing notice and dev doxytags. - Only initial work done. Still need to refine the logic and incorporate all the other types of tags. - Added/Modified some tests - Work in progress --- InterfaceHandler.cpp | 90 ++++++++++++++++++++++++++++++++++++++-------------- InterfaceHandler.h | 8 +++++ 2 files changed, 75 insertions(+), 23 deletions(-) diff --git a/InterfaceHandler.cpp b/InterfaceHandler.cpp index 61570b8d..e7da5e6d 100644 --- a/InterfaceHandler.cpp +++ b/InterfaceHandler.cpp @@ -9,6 +9,7 @@ namespace solidity { InterfaceHandler::InterfaceHandler() { + m_lastTag = DOCTAG_NONE; } std::unique_ptr InterfaceHandler::getDocumentation(std::shared_ptr _contractDef, @@ -71,7 +72,9 @@ std::unique_ptr InterfaceHandler::getUserDocumentation(std::shared_ auto strPtr = f->getDocumentation(); if (strPtr) { - user["notice"] = Json::Value(*strPtr); + m_notice.clear(); + parseDocString(*strPtr); + user["notice"] = Json::Value(m_notice); methods[f->getName()] = user; } } @@ -94,7 +97,7 @@ std::unique_ptr InterfaceHandler::getDevDocumentation(std::shared_p m_dev.clear(); parseDocString(*strPtr); - method["dev"] = Json::Value(m_dev); + method["details"] = Json::Value(m_dev); methods[f->getName()] = method; } } @@ -106,26 +109,55 @@ std::unique_ptr InterfaceHandler::getDevDocumentation(std::shared_p /* -- private -- */ size_t InterfaceHandler::parseDocTag(std::string const& _string, std::string const& _tag, size_t _pos) { + //TODO: This is pretty naive at the moment. e.g. need to check for + // '@' between _pos and \n, remove redundancy e.t.c. size_t nlPos = _pos; - if (_tag == "dev") - { - nlPos = _string.find("\n", _pos); - m_dev += _string.substr(_pos, - nlPos == std::string::npos ? - _string.length() : - nlPos - _pos); - } - else if (_tag == "notice") + if (m_lastTag == DOCTAG_NONE || _tag != "") { - nlPos = _string.find("\n", _pos); - m_notice += _string.substr(_pos, - nlPos == std::string::npos ? - _string.length() : - nlPos - _pos); + if (_tag == "dev") + { + nlPos = _string.find("\n", _pos); + m_dev += _string.substr(_pos, + nlPos == std::string::npos ? + _string.length() : + nlPos - _pos); + m_lastTag = DOCTAG_DEV; + } + else if (_tag == "notice") + { + nlPos = _string.find("\n", _pos); + m_notice += _string.substr(_pos, + nlPos == std::string::npos ? + _string.length() : + nlPos - _pos); + m_lastTag = DOCTAG_NOTICE; + } + else + { + //TODO: Some form of warning + } } else { - //TODO: Some form of warning + switch(m_lastTag) + { + case DOCTAG_DEV: + nlPos = _string.find("\n", _pos); + m_dev += _string.substr(_pos, + nlPos == std::string::npos ? + _string.length() : + nlPos - _pos); + break; + case DOCTAG_NOTICE: + nlPos = _string.find("\n", _pos); + m_notice += _string.substr(_pos, + nlPos == std::string::npos ? + _string.length() : + nlPos - _pos); + break; + default: + break; + } } return nlPos; @@ -134,16 +166,28 @@ size_t InterfaceHandler::parseDocTag(std::string const& _string, std::string con void InterfaceHandler::parseDocString(std::string const& _string, size_t _startPos) { size_t pos2; + size_t newPos = _startPos; size_t pos1 = _string.find("@", _startPos); - if (pos1 == std::string::npos) - return; // no doxytags found + if (pos1 != std::string::npos) + { + // we found a tag + pos2 = _string.find(" ", pos1); + if (pos2 == std::string::npos) + { + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("End of tag not found")); + return; //no end of tag found + } - pos2 = _string.find(" ", pos1); - if (pos2 == std::string::npos) - return; //no end of tag found + newPos = parseDocTag(_string, _string.substr(pos1 + 1, pos2 - pos1 - 1), pos2 + 1); + } + else + { + newPos = parseDocTag(_string, "", _startPos + 1); + } - size_t newPos = parseDocTag(_string, _string.substr(pos1 + 1, pos2 - pos1), pos2); + if (newPos == std::string::npos) + return; // EOS parseDocString(_string, newPos); } diff --git a/InterfaceHandler.h b/InterfaceHandler.h index 5c8bf5bc..6f2f2937 100644 --- a/InterfaceHandler.h +++ b/InterfaceHandler.h @@ -37,6 +37,13 @@ namespace solidity { class ContractDefinition; enum documentationType: unsigned short; +enum docTagType +{ + DOCTAG_NONE = 0, + DOCTAG_DEV, + DOCTAG_NOTICE, +}; + class InterfaceHandler { public: @@ -73,6 +80,7 @@ private: Json::StyledWriter m_writer; // internal state + enum docTagType m_lastTag; std::string m_notice; std::string m_dev; }; -- cgit From 05964375f888e8b8a3ccf5bc01d9cfff8fd00566 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 4 Dec 2014 17:19:47 +0100 Subject: Natspec parsing @param doctags - Plus additional work on generally parsing doctags. One important missing feature is to parse a tag midline - Adding more tests --- InterfaceHandler.cpp | 158 +++++++++++++++++++++++++++++++++++++-------------- InterfaceHandler.h | 9 +++ 2 files changed, 124 insertions(+), 43 deletions(-) diff --git a/InterfaceHandler.cpp b/InterfaceHandler.cpp index e7da5e6d..222711e6 100644 --- a/InterfaceHandler.cpp +++ b/InterfaceHandler.cpp @@ -1,3 +1,4 @@ + #include #include #include @@ -72,7 +73,7 @@ std::unique_ptr InterfaceHandler::getUserDocumentation(std::shared_ auto strPtr = f->getDocumentation(); if (strPtr) { - m_notice.clear(); + resetUser(); parseDocString(*strPtr); user["notice"] = Json::Value(m_notice); methods[f->getName()] = user; @@ -94,10 +95,16 @@ std::unique_ptr InterfaceHandler::getDevDocumentation(std::shared_p auto strPtr = f->getDocumentation(); if (strPtr) { - m_dev.clear(); + resetDev(); parseDocString(*strPtr); method["details"] = Json::Value(m_dev); + Json::Value params(Json::objectValue); + for (auto const& pair: m_params) + { + params[pair.first] = pair.second; + } + method["params"] = params; methods[f->getName()] = method; } } @@ -107,86 +114,151 @@ std::unique_ptr InterfaceHandler::getDevDocumentation(std::shared_p } /* -- private -- */ +void InterfaceHandler::resetUser() +{ + m_notice.clear(); +} + +void InterfaceHandler::resetDev() +{ + m_dev.clear(); + m_params.clear(); +} + +size_t skipLineOrEOS(std::string const& _string, size_t _nlPos) +{ + return (_nlPos == std::string::npos) ? _string.length() : _nlPos + 1; +} + +size_t InterfaceHandler::parseDocTagLine(std::string const& _string, + std::string& _tagString, + size_t _pos, + enum docTagType _tagType) +{ + size_t nlPos = _string.find("\n", _pos); + _tagString += _string.substr(_pos, + nlPos == std::string::npos ? + _string.length() : + nlPos - _pos); + m_lastTag = _tagType; + return skipLineOrEOS(_string, nlPos); +} + +size_t InterfaceHandler::parseDocTagParam(std::string const& _string, size_t _startPos) +{ + // find param name + size_t currPos = _string.find(" ", _startPos); + if (currPos == std::string::npos) + { + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("End of param name not found")); + return currPos; //no end of tag found + } + + auto paramName = _string.substr(_startPos, currPos - _startPos); + + currPos += 1; + size_t nlPos = _string.find("\n", currPos); + auto paramDesc = _string.substr(currPos, + nlPos == std::string::npos ? + _string.length() : + nlPos - currPos); + + m_params.push_back(std::make_pair(paramName, paramDesc)); + + m_lastTag = DOCTAG_PARAM; + return skipLineOrEOS(_string, nlPos); +} + +size_t InterfaceHandler::appendDocTagParam(std::string const& _string, size_t _startPos) +{ + // Should never be called with an empty vector + assert(!m_params.empty()); + + auto pair = m_params.back(); + size_t nlPos = _string.find("\n", _startPos); + pair.second += _string.substr(_startPos, + nlPos == std::string::npos ? + _string.length() : + nlPos - _startPos); + + m_params.at(m_params.size() - 1) = pair; + + return skipLineOrEOS(_string, nlPos); +} + size_t InterfaceHandler::parseDocTag(std::string const& _string, std::string const& _tag, size_t _pos) { - //TODO: This is pretty naive at the moment. e.g. need to check for - // '@' between _pos and \n, remove redundancy e.t.c. + //TODO: need to check for @(start of a tag) between here and the end of line + // for all cases size_t nlPos = _pos; if (m_lastTag == DOCTAG_NONE || _tag != "") { if (_tag == "dev") - { - nlPos = _string.find("\n", _pos); - m_dev += _string.substr(_pos, - nlPos == std::string::npos ? - _string.length() : - nlPos - _pos); - m_lastTag = DOCTAG_DEV; - } + nlPos = parseDocTagLine(_string, m_dev, _pos, DOCTAG_DEV); else if (_tag == "notice") - { - nlPos = _string.find("\n", _pos); - m_notice += _string.substr(_pos, - nlPos == std::string::npos ? - _string.length() : - nlPos - _pos); - m_lastTag = DOCTAG_NOTICE; - } + nlPos = parseDocTagLine(_string, m_notice, _pos, DOCTAG_NOTICE); + else if (_tag == "param") + nlPos = parseDocTagParam(_string, _pos); else { //TODO: Some form of warning } } else + appendDocTag(_string, _pos); + + return nlPos; +} + +size_t InterfaceHandler::appendDocTag(std::string const& _string, size_t _startPos) +{ + size_t newPos = _startPos; + switch(m_lastTag) { - switch(m_lastTag) - { case DOCTAG_DEV: - nlPos = _string.find("\n", _pos); - m_dev += _string.substr(_pos, - nlPos == std::string::npos ? - _string.length() : - nlPos - _pos); + m_dev += " "; + newPos = parseDocTagLine(_string, m_dev, _startPos, DOCTAG_DEV); break; case DOCTAG_NOTICE: - nlPos = _string.find("\n", _pos); - m_notice += _string.substr(_pos, - nlPos == std::string::npos ? - _string.length() : - nlPos - _pos); + m_notice += " "; + newPos = parseDocTagLine(_string, m_notice, _startPos, DOCTAG_NOTICE); + break; + case DOCTAG_PARAM: + newPos = appendDocTagParam(_string, _startPos); break; default: break; } - } - - return nlPos; + return newPos; } void InterfaceHandler::parseDocString(std::string const& _string, size_t _startPos) { size_t pos2; size_t newPos = _startPos; - size_t pos1 = _string.find("@", _startPos); + size_t tagPos = _string.find("@", _startPos); + size_t nlPos = _string.find("\n", _startPos); - if (pos1 != std::string::npos) + if (tagPos != std::string::npos && tagPos < nlPos) { // we found a tag - pos2 = _string.find(" ", pos1); + pos2 = _string.find(" ", tagPos); if (pos2 == std::string::npos) { BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("End of tag not found")); return; //no end of tag found } - newPos = parseDocTag(_string, _string.substr(pos1 + 1, pos2 - pos1 - 1), pos2 + 1); + newPos = parseDocTag(_string, _string.substr(tagPos + 1, pos2 - tagPos - 1), pos2 + 1); } - else + else if (m_lastTag != DOCTAG_NONE) // continuation of the previous tag + newPos = appendDocTag(_string, _startPos + 1); + else // skip the line if a newline was found { - newPos = parseDocTag(_string, "", _startPos + 1); + if (newPos != std::string::npos) + newPos = nlPos + 1; } - - if (newPos == std::string::npos) + if (newPos == std::string::npos || newPos == _string.length()) return; // EOS parseDocString(_string, newPos); } diff --git a/InterfaceHandler.h b/InterfaceHandler.h index 6f2f2937..2a70af95 100644 --- a/InterfaceHandler.h +++ b/InterfaceHandler.h @@ -42,6 +42,7 @@ enum docTagType DOCTAG_NONE = 0, DOCTAG_DEV, DOCTAG_NOTICE, + DOCTAG_PARAM }; class InterfaceHandler @@ -74,7 +75,14 @@ public: std::unique_ptr getDevDocumentation(std::shared_ptr _contractDef); private: + void resetUser(); + void resetDev(); + + size_t parseDocTagLine(std::string const& _string, std::string& _tagString, size_t _pos, enum docTagType _tagType); + size_t parseDocTagParam(std::string const& _string, size_t _startPos); + size_t appendDocTagParam(std::string const& _string, size_t _startPos); void parseDocString(std::string const& _string, size_t _startPos = 0); + size_t appendDocTag(std::string const& _string, size_t _startPos); size_t parseDocTag(std::string const& _string, std::string const& _tag, size_t _pos); Json::StyledWriter m_writer; @@ -83,6 +91,7 @@ private: enum docTagType m_lastTag; std::string m_notice; std::string m_dev; + std::vector> m_params; }; } //solidity NS -- cgit From 02a04eef5c897dc4c211d14803285bd0485f8877 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 4 Dec 2014 18:12:52 +0100 Subject: Natspec @return tag parsing - Also omitting tags from the output JSON file if they are missing instead of providing an empty string for their value --- InterfaceHandler.cpp | 32 +++++++++++++++++++++++++------- InterfaceHandler.h | 4 +++- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/InterfaceHandler.cpp b/InterfaceHandler.cpp index 222711e6..2a6de2c3 100644 --- a/InterfaceHandler.cpp +++ b/InterfaceHandler.cpp @@ -75,8 +75,11 @@ std::unique_ptr InterfaceHandler::getUserDocumentation(std::shared_ { resetUser(); parseDocString(*strPtr); - user["notice"] = Json::Value(m_notice); - methods[f->getName()] = user; + if (!m_notice.empty()) + {// since @notice is the only user tag if missing function should not appear + user["notice"] = Json::Value(m_notice); + methods[f->getName()] = user; + } } } doc["methods"] = methods; @@ -86,6 +89,8 @@ std::unique_ptr InterfaceHandler::getUserDocumentation(std::shared_ std::unique_ptr InterfaceHandler::getDevDocumentation(std::shared_ptr _contractDef) { + // LTODO: Somewhere in this function warnings for mismatch of param names + // should be thrown Json::Value doc; Json::Value methods(Json::objectValue); @@ -98,14 +103,20 @@ std::unique_ptr InterfaceHandler::getDevDocumentation(std::shared_p resetDev(); parseDocString(*strPtr); - method["details"] = Json::Value(m_dev); + if (!m_dev.empty()) + method["details"] = Json::Value(m_dev); Json::Value params(Json::objectValue); for (auto const& pair: m_params) { params[pair.first] = pair.second; } - method["params"] = params; - methods[f->getName()] = method; + if (!m_params.empty()) + method["params"] = params; + if (!m_return.empty()) + method["return"] = m_return; + + if (!method.empty()) // add the function, only if we have any documentation to add + methods[f->getName()] = method; } } doc["methods"] = methods; @@ -122,6 +133,7 @@ void InterfaceHandler::resetUser() void InterfaceHandler::resetDev() { m_dev.clear(); + m_return.clear(); m_params.clear(); } @@ -188,7 +200,7 @@ size_t InterfaceHandler::appendDocTagParam(std::string const& _string, size_t _s size_t InterfaceHandler::parseDocTag(std::string const& _string, std::string const& _tag, size_t _pos) { - //TODO: need to check for @(start of a tag) between here and the end of line + // LTODO: need to check for @(start of a tag) between here and the end of line // for all cases size_t nlPos = _pos; if (m_lastTag == DOCTAG_NONE || _tag != "") @@ -197,11 +209,13 @@ size_t InterfaceHandler::parseDocTag(std::string const& _string, std::string con nlPos = parseDocTagLine(_string, m_dev, _pos, DOCTAG_DEV); else if (_tag == "notice") nlPos = parseDocTagLine(_string, m_notice, _pos, DOCTAG_NOTICE); + else if (_tag == "return") + nlPos = parseDocTagLine(_string, m_return, _pos, DOCTAG_RETURN); else if (_tag == "param") nlPos = parseDocTagParam(_string, _pos); else { - //TODO: Some form of warning + // LTODO: Unknown tas, throw some form of warning } } else @@ -223,6 +237,10 @@ size_t InterfaceHandler::appendDocTag(std::string const& _string, size_t _startP m_notice += " "; newPos = parseDocTagLine(_string, m_notice, _startPos, DOCTAG_NOTICE); break; + case DOCTAG_RETURN: + m_return += " "; + newPos = parseDocTagLine(_string, m_return, _startPos, DOCTAG_RETURN); + break; case DOCTAG_PARAM: newPos = appendDocTagParam(_string, _startPos); break; diff --git a/InterfaceHandler.h b/InterfaceHandler.h index 2a70af95..eeaed033 100644 --- a/InterfaceHandler.h +++ b/InterfaceHandler.h @@ -42,7 +42,8 @@ enum docTagType DOCTAG_NONE = 0, DOCTAG_DEV, DOCTAG_NOTICE, - DOCTAG_PARAM + DOCTAG_PARAM, + DOCTAG_RETURN }; class InterfaceHandler @@ -91,6 +92,7 @@ private: enum docTagType m_lastTag; std::string m_notice; std::string m_dev; + std::string m_return; std::vector> m_params; }; -- cgit From dedd1a312ba51c4ed8f9f801628dc23f1b09216d Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 4 Dec 2014 23:55:47 +0100 Subject: Addressing styling and miscellaneous issue with Natspec --- CompilerStack.cpp | 20 +++++++++----------- CompilerStack.h | 4 ++-- InterfaceHandler.cpp | 49 ++++++++++++++++++++++--------------------------- InterfaceHandler.h | 18 ++++++++++-------- 4 files changed, 43 insertions(+), 48 deletions(-) diff --git a/CompilerStack.cpp b/CompilerStack.cpp index 3e9791bd..3281442f 100644 --- a/CompilerStack.cpp +++ b/CompilerStack.cpp @@ -36,7 +36,7 @@ namespace dev namespace solidity { -CompilerStack::CompilerStack():m_interfaceHandler(make_shared()){} +CompilerStack::CompilerStack(): m_interfaceHandler(make_shared()) {} void CompilerStack::setSource(string const& _sourceCode) { @@ -84,33 +84,31 @@ void CompilerStack::streamAssembly(ostream& _outStream) m_compiler->streamAssembly(_outStream); } -std::string const* CompilerStack::getJsonDocumentation(enum documentationType _type) +std::string const* CompilerStack::getJsonDocumentation(enum DocumentationType _type) { if (!m_parseSuccessful) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); - auto createOrReturnDoc = [this, _type](std::unique_ptr& _doc) + auto createDocIfNotThere = [this, _type](std::unique_ptr& _doc) { - if(!_doc) - { + if (!_doc) _doc = m_interfaceHandler->getDocumentation(m_contractASTNode, _type); - } }; switch (_type) { case NATSPEC_USER: - createOrReturnDoc(m_userDocumentation); + createDocIfNotThere(m_userDocumentation); return m_userDocumentation.get(); case NATSPEC_DEV: - createOrReturnDoc(m_devDocumentation); + createDocIfNotThere(m_devDocumentation); return m_devDocumentation.get(); case ABI_INTERFACE: - createOrReturnDoc(m_interface); + createDocIfNotThere(m_interface); return m_interface.get(); } - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Internal error")); - return nullptr; + + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Illegal documentation type.")); } bytes CompilerStack::staticCompile(std::string const& _sourceCode, bool _optimize) diff --git a/CompilerStack.h b/CompilerStack.h index 51195129..de356b1a 100644 --- a/CompilerStack.h +++ b/CompilerStack.h @@ -37,7 +37,7 @@ class Compiler; class GlobalContext; class InterfaceHandler; -enum documentationType: unsigned short +enum DocumentationType: unsigned short { NATSPEC_USER = 1, NATSPEC_DEV, @@ -74,7 +74,7 @@ public: /// Prerequisite: Successful call to parse or compile. /// @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 documentationType type); + std::string const* getJsonDocumentation(enum DocumentationType type); /// Returns the previously used scanner, useful for counting lines during error reporting. Scanner const& getScanner() const { return *m_scanner; } diff --git a/InterfaceHandler.cpp b/InterfaceHandler.cpp index 2a6de2c3..53632bc6 100644 --- a/InterfaceHandler.cpp +++ b/InterfaceHandler.cpp @@ -3,8 +3,10 @@ #include #include -namespace dev { -namespace solidity { +namespace dev +{ +namespace solidity +{ /* -- public -- */ @@ -14,7 +16,7 @@ InterfaceHandler::InterfaceHandler() } std::unique_ptr InterfaceHandler::getDocumentation(std::shared_ptr _contractDef, - enum documentationType _type) + enum DocumentationType _type) { switch(_type) { @@ -34,8 +36,7 @@ std::unique_ptr InterfaceHandler::getABIInterface(std::shared_ptr exportedFunctions = _contractDef->getInterfaceFunctions(); - for (FunctionDefinition const* f: exportedFunctions) + for (FunctionDefinition const* f: _contractDef->getInterfaceFunctions()) { Json::Value method; Json::Value inputs(Json::arrayValue); @@ -107,9 +108,8 @@ std::unique_ptr InterfaceHandler::getDevDocumentation(std::shared_p method["details"] = Json::Value(m_dev); Json::Value params(Json::objectValue); for (auto const& pair: m_params) - { params[pair.first] = pair.second; - } + if (!m_params.empty()) method["params"] = params; if (!m_return.empty()) @@ -145,12 +145,12 @@ size_t skipLineOrEOS(std::string const& _string, size_t _nlPos) size_t InterfaceHandler::parseDocTagLine(std::string const& _string, std::string& _tagString, size_t _pos, - enum docTagType _tagType) + enum DocTagType _tagType) { - size_t nlPos = _string.find("\n", _pos); + size_t nlPos = _string.find('\n', _pos); _tagString += _string.substr(_pos, nlPos == std::string::npos ? - _string.length() : + _string.length() - _pos: nlPos - _pos); m_lastTag = _tagType; return skipLineOrEOS(_string, nlPos); @@ -159,20 +159,18 @@ size_t InterfaceHandler::parseDocTagLine(std::string const& _string, size_t InterfaceHandler::parseDocTagParam(std::string const& _string, size_t _startPos) { // find param name - size_t currPos = _string.find(" ", _startPos); + size_t currPos = _string.find(' ', _startPos); if (currPos == std::string::npos) - { BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("End of param name not found")); - return currPos; //no end of tag found - } + auto paramName = _string.substr(_startPos, currPos - _startPos); currPos += 1; - size_t nlPos = _string.find("\n", currPos); + size_t nlPos = _string.find('\n', currPos); auto paramDesc = _string.substr(currPos, nlPos == std::string::npos ? - _string.length() : + _string.length() - currPos : nlPos - currPos); m_params.push_back(std::make_pair(paramName, paramDesc)); @@ -184,13 +182,13 @@ size_t InterfaceHandler::parseDocTagParam(std::string const& _string, size_t _st size_t InterfaceHandler::appendDocTagParam(std::string const& _string, size_t _startPos) { // Should never be called with an empty vector - assert(!m_params.empty()); - + if (asserts(!m_params.empty())) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Internal: Tried to append to empty parameter")); auto pair = m_params.back(); - size_t nlPos = _string.find("\n", _startPos); + size_t nlPos = _string.find('\n', _startPos); pair.second += _string.substr(_startPos, nlPos == std::string::npos ? - _string.length() : + _string.length() - _startPos : nlPos - _startPos); m_params.at(m_params.size() - 1) = pair; @@ -227,7 +225,7 @@ size_t InterfaceHandler::parseDocTag(std::string const& _string, std::string con size_t InterfaceHandler::appendDocTag(std::string const& _string, size_t _startPos) { size_t newPos = _startPos; - switch(m_lastTag) + switch (m_lastTag) { case DOCTAG_DEV: m_dev += " "; @@ -254,18 +252,15 @@ void InterfaceHandler::parseDocString(std::string const& _string, size_t _startP { size_t pos2; size_t newPos = _startPos; - size_t tagPos = _string.find("@", _startPos); - size_t nlPos = _string.find("\n", _startPos); + size_t tagPos = _string.find('@', _startPos); + size_t nlPos = _string.find('\n', _startPos); if (tagPos != std::string::npos && tagPos < nlPos) { // we found a tag - pos2 = _string.find(" ", tagPos); + pos2 = _string.find(' ', tagPos); if (pos2 == std::string::npos) - { BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("End of tag not found")); - return; //no end of tag found - } newPos = parseDocTag(_string, _string.substr(tagPos + 1, pos2 - tagPos - 1), pos2 + 1); } diff --git a/InterfaceHandler.h b/InterfaceHandler.h index eeaed033..e9e3a83c 100644 --- a/InterfaceHandler.h +++ b/InterfaceHandler.h @@ -30,14 +30,16 @@ #include #include -namespace dev { -namespace solidity { +namespace dev +{ +namespace solidity +{ // Forward declarations class ContractDefinition; -enum documentationType: unsigned short; +enum DocumentationType: unsigned short; -enum docTagType +enum DocTagType { DOCTAG_NONE = 0, DOCTAG_DEV, @@ -54,11 +56,11 @@ public: /// 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 + /// types provided by @c DocumentationType /// @return A unique pointer contained string with the json /// representation of provided type std::unique_ptr getDocumentation(std::shared_ptr _contractDef, - enum documentationType _type); + enum DocumentationType _type); /// Get the ABI Interface of the contract /// @param _contractDef The contract definition /// @return A unique pointer contained string with the json @@ -79,7 +81,7 @@ private: void resetUser(); void resetDev(); - size_t parseDocTagLine(std::string const& _string, std::string& _tagString, size_t _pos, enum docTagType _tagType); + size_t parseDocTagLine(std::string const& _string, std::string& _tagString, size_t _pos, enum DocTagType _tagType); size_t parseDocTagParam(std::string const& _string, size_t _startPos); size_t appendDocTagParam(std::string const& _string, size_t _startPos); void parseDocString(std::string const& _string, size_t _startPos = 0); @@ -89,7 +91,7 @@ private: Json::StyledWriter m_writer; // internal state - enum docTagType m_lastTag; + enum DocTagType m_lastTag; std::string m_notice; std::string m_dev; std::string m_return; -- cgit From 8f6656f1b8f1e1897189af2bf149c907685f8c2a Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 5 Dec 2014 02:10:54 +0100 Subject: Using iterators in Natspec comment parsing - Used iterators in the entirety of the InterfaceHandler natspec comment parsing pipeline - Fixed issue where @param continuing in new line would not get a space --- InterfaceHandler.cpp | 138 ++++++++++++++++++++++++--------------------------- InterfaceHandler.h | 20 +++++--- 2 files changed, 79 insertions(+), 79 deletions(-) diff --git a/InterfaceHandler.cpp b/InterfaceHandler.cpp index 53632bc6..1450d8fc 100644 --- a/InterfaceHandler.cpp +++ b/InterfaceHandler.cpp @@ -137,143 +137,135 @@ void InterfaceHandler::resetDev() m_params.clear(); } -size_t skipLineOrEOS(std::string const& _string, size_t _nlPos) +std::string::const_iterator skipLineOrEOS(std::string::const_iterator _nlPos, + std::string::const_iterator _end) { - return (_nlPos == std::string::npos) ? _string.length() : _nlPos + 1; + return (_nlPos == _end) ? _end : ++_nlPos; } -size_t InterfaceHandler::parseDocTagLine(std::string const& _string, - std::string& _tagString, - size_t _pos, - enum DocTagType _tagType) +std::string::const_iterator InterfaceHandler::parseDocTagLine(std::string::const_iterator _pos, + std::string::const_iterator _end, + std::string& _tagString, + enum DocTagType _tagType) { - size_t nlPos = _string.find('\n', _pos); - _tagString += _string.substr(_pos, - nlPos == std::string::npos ? - _string.length() - _pos: - nlPos - _pos); + auto nlPos = std::find(_pos, _end, '\n'); + std::copy(_pos, nlPos, back_inserter(_tagString)); m_lastTag = _tagType; - return skipLineOrEOS(_string, nlPos); + return skipLineOrEOS(nlPos, _end); } -size_t InterfaceHandler::parseDocTagParam(std::string const& _string, size_t _startPos) +std::string::const_iterator InterfaceHandler::parseDocTagParam(std::string::const_iterator _pos, + std::string::const_iterator _end) { // find param name - size_t currPos = _string.find(' ', _startPos); - if (currPos == std::string::npos) + auto currPos = std::find(_pos, _end, ' '); + if (currPos == _end) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("End of param name not found")); - auto paramName = _string.substr(_startPos, currPos - _startPos); + auto paramName = std::string(_pos, currPos); currPos += 1; - size_t nlPos = _string.find('\n', currPos); - auto paramDesc = _string.substr(currPos, - nlPos == std::string::npos ? - _string.length() - currPos : - nlPos - currPos); - + auto nlPos = std::find(currPos, _end, '\n'); + auto paramDesc = std::string(currPos, nlPos); m_params.push_back(std::make_pair(paramName, paramDesc)); m_lastTag = DOCTAG_PARAM; - return skipLineOrEOS(_string, nlPos); + return skipLineOrEOS(nlPos, _end); } -size_t InterfaceHandler::appendDocTagParam(std::string const& _string, size_t _startPos) +std::string::const_iterator InterfaceHandler::appendDocTagParam(std::string::const_iterator _pos, + std::string::const_iterator _end) { // Should never be called with an empty vector if (asserts(!m_params.empty())) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Internal: Tried to append to empty parameter")); + auto pair = m_params.back(); - size_t nlPos = _string.find('\n', _startPos); - pair.second += _string.substr(_startPos, - nlPos == std::string::npos ? - _string.length() - _startPos : - nlPos - _startPos); + pair.second += " "; + auto nlPos = std::find(_pos, _end, '\n'); + std::copy(_pos, nlPos, back_inserter(pair.second)); m_params.at(m_params.size() - 1) = pair; - return skipLineOrEOS(_string, nlPos); + return skipLineOrEOS(nlPos, _end); } -size_t InterfaceHandler::parseDocTag(std::string const& _string, std::string const& _tag, size_t _pos) +std::string::const_iterator InterfaceHandler::parseDocTag(std::string::const_iterator _pos, + std::string::const_iterator _end, + std::string const& _tag) { // LTODO: need to check for @(start of a tag) between here and the end of line // for all cases - size_t nlPos = _pos; if (m_lastTag == DOCTAG_NONE || _tag != "") { if (_tag == "dev") - nlPos = parseDocTagLine(_string, m_dev, _pos, DOCTAG_DEV); + return parseDocTagLine(_pos, _end, m_dev, DOCTAG_DEV); else if (_tag == "notice") - nlPos = parseDocTagLine(_string, m_notice, _pos, DOCTAG_NOTICE); + return parseDocTagLine(_pos, _end, m_notice, DOCTAG_NOTICE); else if (_tag == "return") - nlPos = parseDocTagLine(_string, m_return, _pos, DOCTAG_RETURN); + return parseDocTagLine(_pos, _end, m_return, DOCTAG_RETURN); else if (_tag == "param") - nlPos = parseDocTagParam(_string, _pos); + return parseDocTagParam(_pos, _end); else { - // LTODO: Unknown tas, throw some form of warning + // LTODO: Unknown tag, throw some form of warning and not just an exception + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Unknown tag encountered")); } } else - appendDocTag(_string, _pos); - - return nlPos; + return appendDocTag(_pos, _end); } -size_t InterfaceHandler::appendDocTag(std::string const& _string, size_t _startPos) +std::string::const_iterator InterfaceHandler::appendDocTag(std::string::const_iterator _pos, + std::string::const_iterator _end) { - size_t newPos = _startPos; switch (m_lastTag) { case DOCTAG_DEV: m_dev += " "; - newPos = parseDocTagLine(_string, m_dev, _startPos, DOCTAG_DEV); - break; + return parseDocTagLine(_pos, _end, m_dev, DOCTAG_DEV); case DOCTAG_NOTICE: m_notice += " "; - newPos = parseDocTagLine(_string, m_notice, _startPos, DOCTAG_NOTICE); - break; + return parseDocTagLine(_pos, _end, m_notice, DOCTAG_NOTICE); case DOCTAG_RETURN: m_return += " "; - newPos = parseDocTagLine(_string, m_return, _startPos, DOCTAG_RETURN); - break; + return parseDocTagLine(_pos, _end, m_return, DOCTAG_RETURN); case DOCTAG_PARAM: - newPos = appendDocTagParam(_string, _startPos); - break; + return appendDocTagParam(_pos, _end); default: + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Internal: Illegal documentation tag")); break; - } - return newPos; + } } -void InterfaceHandler::parseDocString(std::string const& _string, size_t _startPos) +void InterfaceHandler::parseDocString(std::string const& _string) { - size_t pos2; - size_t newPos = _startPos; - size_t tagPos = _string.find('@', _startPos); - size_t nlPos = _string.find('\n', _startPos); + auto currPos = _string.begin(); + auto end = _string.end(); - if (tagPos != std::string::npos && tagPos < nlPos) + while (currPos != end) { - // we found a tag - pos2 = _string.find(' ', tagPos); - if (pos2 == std::string::npos) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("End of tag not found")); + auto tagPos = std::find(currPos, end, '@'); + auto nlPos = std::find(currPos, end, '\n'); - newPos = parseDocTag(_string, _string.substr(tagPos + 1, pos2 - tagPos - 1), pos2 + 1); - } - else if (m_lastTag != DOCTAG_NONE) // continuation of the previous tag - newPos = appendDocTag(_string, _startPos + 1); - else // skip the line if a newline was found - { - if (newPos != std::string::npos) - newPos = nlPos + 1; + if (tagPos != end && tagPos < nlPos) + { + // we found a tag + auto tagNameEndPos = std::find(tagPos, end, ' '); + if (tagNameEndPos == end) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("End of tag not found")); + + currPos = parseDocTag(tagNameEndPos + 1, end, std::string(tagPos +1, tagNameEndPos)); + } + else if (m_lastTag != DOCTAG_NONE) // continuation of the previous tag + currPos = appendDocTag(currPos + 1, end); + else // skip the line if a newline was found + { + if (currPos != end) + currPos = nlPos + 1; + } } - if (newPos == std::string::npos || newPos == _string.length()) - return; // EOS - parseDocString(_string, newPos); } } //solidity NS diff --git a/InterfaceHandler.h b/InterfaceHandler.h index e9e3a83c..7a5ee66d 100644 --- a/InterfaceHandler.h +++ b/InterfaceHandler.h @@ -81,12 +81,20 @@ private: void resetUser(); void resetDev(); - size_t parseDocTagLine(std::string const& _string, std::string& _tagString, size_t _pos, enum DocTagType _tagType); - size_t parseDocTagParam(std::string const& _string, size_t _startPos); - size_t appendDocTagParam(std::string const& _string, size_t _startPos); - void parseDocString(std::string const& _string, size_t _startPos = 0); - size_t appendDocTag(std::string const& _string, size_t _startPos); - size_t parseDocTag(std::string const& _string, std::string const& _tag, size_t _pos); + std::string::const_iterator parseDocTagLine(std::string::const_iterator _pos, + std::string::const_iterator _end, + std::string& _tagString, + enum DocTagType _tagType); + std::string::const_iterator parseDocTagParam(std::string::const_iterator _pos, + std::string::const_iterator _end); + std::string::const_iterator appendDocTagParam(std::string::const_iterator _pos, + std::string::const_iterator _end); + void parseDocString(std::string const& _string); + std::string::const_iterator appendDocTag(std::string::const_iterator _pos, + std::string::const_iterator _end); + std::string::const_iterator parseDocTag(std::string::const_iterator _pos, + std::string::const_iterator _end, + std::string const& _tag); Json::StyledWriter m_writer; -- cgit From 11cac68cf4e72d222da015f1aaa0bd6ce4fd7e62 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 5 Dec 2014 12:08:26 +0100 Subject: Introducing Docstring parsing error exception and style fixes --- Exceptions.h | 1 + InterfaceHandler.cpp | 22 ++++++++++------------ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/Exceptions.h b/Exceptions.h index 1903c1dc..8298c981 100644 --- a/Exceptions.h +++ b/Exceptions.h @@ -36,6 +36,7 @@ struct TypeError: virtual Exception {}; struct DeclarationError: virtual Exception {}; struct CompilerError: virtual Exception {}; struct InternalCompilerError: virtual Exception {}; +struct DocstringParsingError: virtual Exception {}; typedef boost::error_info errinfo_sourcePosition; typedef boost::error_info errinfo_sourceLocation; diff --git a/InterfaceHandler.cpp b/InterfaceHandler.cpp index 1450d8fc..ca02cc37 100644 --- a/InterfaceHandler.cpp +++ b/InterfaceHandler.cpp @@ -28,7 +28,7 @@ std::unique_ptr InterfaceHandler::getDocumentation(std::shared_ptr< return getABIInterface(_contractDef); } - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Internal error")); + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown documentation type")); return nullptr; } @@ -160,7 +160,7 @@ std::string::const_iterator InterfaceHandler::parseDocTagParam(std::string::cons // find param name auto currPos = std::find(_pos, _end, ' '); if (currPos == _end) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("End of param name not found")); + BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("End of param name not found" + std::string(_pos, _end))); auto paramName = std::string(_pos, currPos); @@ -179,7 +179,7 @@ std::string::const_iterator InterfaceHandler::appendDocTagParam(std::string::con { // Should never be called with an empty vector if (asserts(!m_params.empty())) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Internal: Tried to append to empty parameter")); + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Internal: Tried to append to empty parameter")); auto pair = m_params.back(); pair.second += " "; @@ -210,7 +210,7 @@ std::string::const_iterator InterfaceHandler::parseDocTag(std::string::const_ite else { // LTODO: Unknown tag, throw some form of warning and not just an exception - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Unknown tag encountered")); + BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("Unknown tag " + _tag + " encountered")); } } else @@ -234,7 +234,7 @@ std::string::const_iterator InterfaceHandler::appendDocTag(std::string::const_it case DOCTAG_PARAM: return appendDocTagParam(_pos, _end); default: - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Internal: Illegal documentation tag")); + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Internal: Illegal documentation tag type")); break; } } @@ -254,17 +254,15 @@ void InterfaceHandler::parseDocString(std::string const& _string) // we found a tag auto tagNameEndPos = std::find(tagPos, end, ' '); if (tagNameEndPos == end) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("End of tag not found")); + BOOST_THROW_EXCEPTION(DocstringParsingError() << + errinfo_comment("End of tag " + std::string(tagPos, tagNameEndPos) + "not found")); - currPos = parseDocTag(tagNameEndPos + 1, end, std::string(tagPos +1, tagNameEndPos)); + currPos = parseDocTag(tagNameEndPos + 1, end, std::string(tagPos + 1, tagNameEndPos)); } else if (m_lastTag != DOCTAG_NONE) // continuation of the previous tag currPos = appendDocTag(currPos + 1, end); - else // skip the line if a newline was found - { - if (currPos != end) - currPos = nlPos + 1; - } + else if (currPos != end) // skip the line if a newline was found + currPos = nlPos + 1; } } -- cgit From 27ef18865d4014e50e917674cf4a7444b7f5565a Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 5 Dec 2014 12:27:18 +0100 Subject: Newline right after doctag is now a valid natspec entry - Plus tests for that --- InterfaceHandler.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/InterfaceHandler.cpp b/InterfaceHandler.cpp index ca02cc37..0115c7f5 100644 --- a/InterfaceHandler.cpp +++ b/InterfaceHandler.cpp @@ -137,8 +137,8 @@ void InterfaceHandler::resetDev() m_params.clear(); } -std::string::const_iterator skipLineOrEOS(std::string::const_iterator _nlPos, - std::string::const_iterator _end) +static inline std::string::const_iterator skipLineOrEOS(std::string::const_iterator _nlPos, + std::string::const_iterator _end) { return (_nlPos == _end) ? _end : ++_nlPos; } @@ -239,6 +239,14 @@ std::string::const_iterator InterfaceHandler::appendDocTag(std::string::const_it } } +static inline std::string::const_iterator getFirstSpaceOrNl(std::string::const_iterator _pos, + std::string::const_iterator _end) +{ + auto spacePos = std::find(_pos, _end, ' '); + auto nlPos = std::find(_pos, _end, '\n'); + return (spacePos < nlPos) ? spacePos : nlPos; +} + void InterfaceHandler::parseDocString(std::string const& _string) { auto currPos = _string.begin(); @@ -252,7 +260,7 @@ void InterfaceHandler::parseDocString(std::string const& _string) if (tagPos != end && tagPos < nlPos) { // we found a tag - auto tagNameEndPos = std::find(tagPos, end, ' '); + auto tagNameEndPos = getFirstSpaceOrNl(tagPos, end); if (tagNameEndPos == end) BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("End of tag " + std::string(tagPos, tagNameEndPos) + "not found")); -- cgit From c8f96589c58c1a0ab290a192e4aa1dfb263d01df Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 5 Dec 2014 12:41:32 +0100 Subject: Stack compiler now correctly returns a string and not a pointer --- CompilerStack.cpp | 8 ++++---- CompilerStack.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CompilerStack.cpp b/CompilerStack.cpp index 3281442f..c83257a1 100644 --- a/CompilerStack.cpp +++ b/CompilerStack.cpp @@ -84,7 +84,7 @@ void CompilerStack::streamAssembly(ostream& _outStream) m_compiler->streamAssembly(_outStream); } -std::string const* CompilerStack::getJsonDocumentation(enum DocumentationType _type) +std::string const& CompilerStack::getJsonDocumentation(enum DocumentationType _type) { if (!m_parseSuccessful) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); @@ -99,13 +99,13 @@ std::string const* CompilerStack::getJsonDocumentation(enum DocumentationType _t { case NATSPEC_USER: createDocIfNotThere(m_userDocumentation); - return m_userDocumentation.get(); + return *m_userDocumentation; case NATSPEC_DEV: createDocIfNotThere(m_devDocumentation); - return m_devDocumentation.get(); + return *m_devDocumentation; case ABI_INTERFACE: createDocIfNotThere(m_interface); - return m_interface.get(); + return *m_interface; } BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Illegal documentation type.")); diff --git a/CompilerStack.h b/CompilerStack.h index de356b1a..8dc546fb 100644 --- a/CompilerStack.h +++ b/CompilerStack.h @@ -74,7 +74,7 @@ public: /// Prerequisite: Successful call to parse or compile. /// @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 DocumentationType type); + std::string const& getJsonDocumentation(enum DocumentationType type); /// Returns the previously used scanner, useful for counting lines during error reporting. Scanner const& getScanner() const { return *m_scanner; } -- cgit