diff options
Diffstat (limited to 'libsolidity')
-rw-r--r-- | libsolidity/CMakeLists.txt | 9 | ||||
-rw-r--r-- | libsolidity/InterfaceHandler.cpp | 478 | ||||
-rw-r--r-- | libsolidity/analysis/ConstantEvaluator.cpp (renamed from libsolidity/ConstantEvaluator.cpp) | 4 | ||||
-rw-r--r-- | libsolidity/analysis/ConstantEvaluator.h (renamed from libsolidity/ConstantEvaluator.h) | 2 | ||||
-rw-r--r-- | libsolidity/analysis/DeclarationContainer.cpp (renamed from libsolidity/DeclarationContainer.cpp) | 6 | ||||
-rw-r--r-- | libsolidity/analysis/DeclarationContainer.h (renamed from libsolidity/DeclarationContainer.h) | 2 | ||||
-rw-r--r-- | libsolidity/analysis/DocStringAnalyser.cpp | 128 | ||||
-rw-r--r-- | libsolidity/analysis/DocStringAnalyser.h | 71 | ||||
-rw-r--r-- | libsolidity/analysis/GlobalContext.cpp (renamed from libsolidity/GlobalContext.cpp) | 6 | ||||
-rw-r--r-- | libsolidity/analysis/GlobalContext.h (renamed from libsolidity/GlobalContext.h) | 2 | ||||
-rw-r--r-- | libsolidity/analysis/NameAndTypeResolver.cpp (renamed from libsolidity/NameAndTypeResolver.cpp) | 8 | ||||
-rw-r--r-- | libsolidity/analysis/NameAndTypeResolver.h (renamed from libsolidity/NameAndTypeResolver.h) | 8 | ||||
-rw-r--r-- | libsolidity/analysis/ReferencesResolver.cpp (renamed from libsolidity/ReferencesResolver.cpp) | 10 | ||||
-rw-r--r-- | libsolidity/analysis/ReferencesResolver.h (renamed from libsolidity/ReferencesResolver.h) | 4 | ||||
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp (renamed from libsolidity/TypeChecker.cpp) | 4 | ||||
-rw-r--r-- | libsolidity/analysis/TypeChecker.h (renamed from libsolidity/TypeChecker.h) | 10 | ||||
-rw-r--r-- | libsolidity/ast/AST.cpp (renamed from libsolidity/AST.cpp) | 38 | ||||
-rw-r--r-- | libsolidity/ast/AST.h (renamed from libsolidity/AST.h) | 71 | ||||
-rw-r--r-- | libsolidity/ast/ASTAnnotations.cpp (renamed from libsolidity/ASTAnnotations.cpp) | 2 | ||||
-rw-r--r-- | libsolidity/ast/ASTAnnotations.h (renamed from libsolidity/ASTAnnotations.h) | 37 | ||||
-rw-r--r-- | libsolidity/ast/ASTForward.h (renamed from libsolidity/ASTForward.h) | 0 | ||||
-rw-r--r-- | libsolidity/ast/ASTJsonConverter.cpp (renamed from libsolidity/ASTJsonConverter.cpp) | 4 | ||||
-rw-r--r-- | libsolidity/ast/ASTJsonConverter.h (renamed from libsolidity/ASTJsonConverter.h) | 8 | ||||
-rw-r--r-- | libsolidity/ast/ASTPrinter.cpp (renamed from libsolidity/ASTPrinter.cpp) | 4 | ||||
-rw-r--r-- | libsolidity/ast/ASTPrinter.h (renamed from libsolidity/ASTPrinter.h) | 4 | ||||
-rw-r--r-- | libsolidity/ast/ASTUtils.cpp (renamed from libsolidity/ASTUtils.cpp) | 2 | ||||
-rw-r--r-- | libsolidity/ast/ASTUtils.h (renamed from libsolidity/ASTUtils.h) | 2 | ||||
-rw-r--r-- | libsolidity/ast/ASTVisitor.h (renamed from libsolidity/ASTVisitor.h) | 2 | ||||
-rw-r--r-- | libsolidity/ast/AST_accept.h (renamed from libsolidity/AST_accept.h) | 4 | ||||
-rw-r--r-- | libsolidity/ast/Types.cpp (renamed from libsolidity/Types.cpp) | 6 | ||||
-rw-r--r-- | libsolidity/ast/Types.h (renamed from libsolidity/Types.h) | 6 | ||||
-rw-r--r-- | libsolidity/codegen/ArrayUtils.cpp (renamed from libsolidity/ArrayUtils.cpp) | 12 | ||||
-rw-r--r-- | libsolidity/codegen/ArrayUtils.h (renamed from libsolidity/ArrayUtils.h) | 0 | ||||
-rw-r--r-- | libsolidity/codegen/Compiler.cpp (renamed from libsolidity/Compiler.cpp) | 14 | ||||
-rw-r--r-- | libsolidity/codegen/Compiler.h (renamed from libsolidity/Compiler.h) | 4 | ||||
-rw-r--r-- | libsolidity/codegen/CompilerContext.cpp (renamed from libsolidity/CompilerContext.cpp) | 8 | ||||
-rw-r--r-- | libsolidity/codegen/CompilerContext.h (renamed from libsolidity/CompilerContext.h) | 6 | ||||
-rw-r--r-- | libsolidity/codegen/CompilerUtils.cpp (renamed from libsolidity/CompilerUtils.cpp) | 10 | ||||
-rw-r--r-- | libsolidity/codegen/CompilerUtils.h (renamed from libsolidity/CompilerUtils.h) | 4 | ||||
-rw-r--r-- | libsolidity/codegen/ExpressionCompiler.cpp (renamed from libsolidity/ExpressionCompiler.cpp) | 10 | ||||
-rw-r--r-- | libsolidity/codegen/ExpressionCompiler.h (renamed from libsolidity/ExpressionCompiler.h) | 6 | ||||
-rw-r--r-- | libsolidity/codegen/LValue.cpp (renamed from libsolidity/LValue.cpp) | 8 | ||||
-rw-r--r-- | libsolidity/codegen/LValue.h (renamed from libsolidity/LValue.h) | 4 | ||||
-rw-r--r-- | libsolidity/formal/Why3Translator.cpp | 525 | ||||
-rw-r--r-- | libsolidity/formal/Why3Translator.h | 115 | ||||
-rw-r--r-- | libsolidity/interface/CompilerStack.cpp (renamed from libsolidity/CompilerStack.cpp) | 53 | ||||
-rw-r--r-- | libsolidity/interface/CompilerStack.h (renamed from libsolidity/CompilerStack.h) | 12 | ||||
-rw-r--r-- | libsolidity/interface/Exceptions.cpp (renamed from libsolidity/Exceptions.cpp) | 43 | ||||
-rw-r--r-- | libsolidity/interface/Exceptions.h (renamed from libsolidity/Exceptions.h) | 1 | ||||
-rw-r--r-- | libsolidity/interface/GasEstimator.cpp (renamed from libsolidity/GasEstimator.cpp) | 6 | ||||
-rw-r--r-- | libsolidity/interface/GasEstimator.h (renamed from libsolidity/GasEstimator.h) | 4 | ||||
-rw-r--r-- | libsolidity/interface/InterfaceHandler.cpp | 248 | ||||
-rw-r--r-- | libsolidity/interface/InterfaceHandler.h (renamed from libsolidity/InterfaceHandler.h) | 55 | ||||
-rw-r--r-- | libsolidity/interface/SourceReferenceFormatter.cpp (renamed from libsolidity/SourceReferenceFormatter.cpp) | 8 | ||||
-rw-r--r-- | libsolidity/interface/SourceReferenceFormatter.h (renamed from libsolidity/SourceReferenceFormatter.h) | 0 | ||||
-rw-r--r-- | libsolidity/interface/Utils.h (renamed from libsolidity/Utils.h) | 2 | ||||
-rw-r--r-- | libsolidity/interface/Version.cpp (renamed from libsolidity/Version.cpp) | 9 | ||||
-rw-r--r-- | libsolidity/interface/Version.h (renamed from libsolidity/Version.h) | 0 | ||||
-rw-r--r-- | libsolidity/parsing/DocStringParser.cpp | 141 | ||||
-rw-r--r-- | libsolidity/parsing/DocStringParser.h | 70 | ||||
-rw-r--r-- | libsolidity/parsing/Parser.cpp (renamed from libsolidity/Parser.cpp) | 98 | ||||
-rw-r--r-- | libsolidity/parsing/Parser.h (renamed from libsolidity/Parser.h) | 14 | ||||
-rw-r--r-- | libsolidity/parsing/Scanner.cpp (renamed from libsolidity/Scanner.cpp) | 4 | ||||
-rw-r--r-- | libsolidity/parsing/Scanner.h (renamed from libsolidity/Scanner.h) | 2 | ||||
-rw-r--r-- | libsolidity/parsing/Token.cpp (renamed from libsolidity/Token.cpp) | 2 | ||||
-rw-r--r-- | libsolidity/parsing/Token.h (renamed from libsolidity/Token.h) | 4 |
66 files changed, 1686 insertions, 758 deletions
diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt index 9fa35e3b..d59afc2d 100644 --- a/libsolidity/CMakeLists.txt +++ b/libsolidity/CMakeLists.txt @@ -1,10 +1,15 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") -aux_source_directory(. SRC_LIST) +aux_source_directory(analysis SRC_LIST) +aux_source_directory(ast SRC_LIST) +aux_source_directory(codegen SRC_LIST) +aux_source_directory(formal SRC_LIST) +aux_source_directory(interface SRC_LIST) +aux_source_directory(parsing SRC_LIST) set(EXECUTABLE solidity) -file(GLOB HEADERS "*.h") +file(GLOB HEADERS "*/*.h") include_directories(BEFORE ..) add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp deleted file mode 100644 index 17ca66b4..00000000 --- a/libsolidity/InterfaceHandler.cpp +++ /dev/null @@ -1,478 +0,0 @@ - -#include <libsolidity/InterfaceHandler.h> -#include <boost/range/irange.hpp> -#include <libsolidity/AST.h> -#include <libsolidity/CompilerStack.h> -using namespace std; - -namespace dev -{ -namespace solidity -{ - -/* -- public -- */ - -InterfaceHandler::InterfaceHandler() -{ - m_lastTag = DocTagType::None; -} - -string InterfaceHandler::documentation( - ContractDefinition const& _contractDef, - DocumentationType _type -) -{ - switch(_type) - { - case DocumentationType::NatspecUser: - return userDocumentation(_contractDef); - case DocumentationType::NatspecDev: - return devDocumentation(_contractDef); - case DocumentationType::ABIInterface: - return abiInterface(_contractDef); - case DocumentationType::ABISolidityInterface: - return ABISolidityInterface(_contractDef); - } - - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown documentation type")); - return ""; -} - -string InterfaceHandler::abiInterface(ContractDefinition const& _contractDef) -{ - Json::Value abi(Json::arrayValue); - - auto populateParameters = [](vector<string> const& _paramNames, vector<string> const& _paramTypes) - { - Json::Value params(Json::arrayValue); - solAssert(_paramNames.size() == _paramTypes.size(), "Names and types vector size does not match"); - for (unsigned i = 0; i < _paramNames.size(); ++i) - { - Json::Value param; - param["name"] = _paramNames[i]; - param["type"] = _paramTypes[i]; - params.append(param); - } - return params; - }; - - for (auto it: _contractDef.interfaceFunctions()) - { - auto externalFunctionType = it.second->interfaceFunctionType(); - Json::Value method; - method["type"] = "function"; - method["name"] = it.second->declaration().name(); - method["constant"] = it.second->isConstant(); - method["inputs"] = populateParameters( - externalFunctionType->parameterNames(), - externalFunctionType->parameterTypeNames(_contractDef.isLibrary()) - ); - method["outputs"] = populateParameters( - externalFunctionType->returnParameterNames(), - externalFunctionType->returnParameterTypeNames(_contractDef.isLibrary()) - ); - abi.append(method); - } - if (_contractDef.constructor()) - { - Json::Value method; - method["type"] = "constructor"; - auto externalFunction = FunctionType(*_contractDef.constructor()).interfaceFunctionType(); - solAssert(!!externalFunction, ""); - method["inputs"] = populateParameters( - externalFunction->parameterNames(), - externalFunction->parameterTypeNames(_contractDef.isLibrary()) - ); - abi.append(method); - } - - for (auto const& it: _contractDef.interfaceEvents()) - { - Json::Value event; - event["type"] = "event"; - event["name"] = it->name(); - event["anonymous"] = it->isAnonymous(); - Json::Value params(Json::arrayValue); - for (auto const& p: it->parameters()) - { - Json::Value input; - input["name"] = p->name(); - input["type"] = p->annotation().type->canonicalName(false); - input["indexed"] = p->isIndexed(); - params.append(input); - } - event["inputs"] = params; - abi.append(event); - } - return Json::FastWriter().write(abi); -} - -string InterfaceHandler::ABISolidityInterface(ContractDefinition const& _contractDef) -{ - string ret = (_contractDef.isLibrary() ? "library " : "contract ") + _contractDef.name() + "{"; - - auto populateParameters = [](vector<string> const& _paramNames, vector<string> const& _paramTypes) - { - string ret = "("; - for (size_t i = 0; i < _paramNames.size(); ++i) - ret += _paramTypes[i] + " " + _paramNames[i] + ","; - if (ret.size() != 1) - ret.pop_back(); - return ret + ")"; - }; - // If this is a library, include all its enum and struct types. Should be more intelligent - // in the future and check what is actually used (it might even use types from other libraries - // or contracts or in the global scope). - if (_contractDef.isLibrary()) - { - for (auto const& stru: _contractDef.definedStructs()) - { - ret += "struct " + stru->name() + "{"; - for (ASTPointer<VariableDeclaration> const& _member: stru->members()) - ret += _member->type(nullptr)->canonicalName(false) + " " + _member->name() + ";"; - ret += "}"; - } - for (auto const& enu: _contractDef.definedEnums()) - { - ret += "enum " + enu->name() + "{"; - for (ASTPointer<EnumValue> const& val: enu->members()) - ret += val->name() + ","; - if (ret.back() == ',') - ret.pop_back(); - ret += "}"; - } - } - if (_contractDef.constructor()) - { - auto externalFunction = FunctionType(*_contractDef.constructor()).interfaceFunctionType(); - solAssert(!!externalFunction, ""); - ret += - "function " + - _contractDef.name() + - populateParameters( - externalFunction->parameterNames(), - externalFunction->parameterTypeNames(_contractDef.isLibrary()) - ) + - ";"; - } - for (auto const& it: _contractDef.interfaceFunctions()) - { - ret += "function " + it.second->declaration().name() + - populateParameters( - it.second->parameterNames(), - it.second->parameterTypeNames(_contractDef.isLibrary()) - ) + (it.second->isConstant() ? "constant " : ""); - if (it.second->returnParameterTypes().size()) - ret += "returns" + populateParameters( - it.second->returnParameterNames(), - it.second->returnParameterTypeNames(_contractDef.isLibrary()) - ); - else if (ret.back() == ' ') - ret.pop_back(); - ret += ";"; - } - - return ret + "}"; -} - -string InterfaceHandler::userDocumentation(ContractDefinition const& _contractDef) -{ - Json::Value doc; - Json::Value methods(Json::objectValue); - - for (auto const& it: _contractDef.interfaceFunctions()) - { - Json::Value user; - auto strPtr = it.second->documentation(); - if (strPtr) - { - resetUser(); - parseDocString(*strPtr, CommentOwner::Function); - if (!m_notice.empty()) - {// since @notice is the only user tag if missing function should not appear - user["notice"] = Json::Value(m_notice); - methods[it.second->externalSignature()] = user; - } - } - } - doc["methods"] = methods; - - return Json::StyledWriter().write(doc); -} - -string InterfaceHandler::devDocumentation(ContractDefinition const& _contractDef) -{ - // LTODO: Somewhere in this function warnings for mismatch of param names - // should be thrown - Json::Value doc; - Json::Value methods(Json::objectValue); - - auto contractDoc = _contractDef.documentation(); - if (contractDoc) - { - m_contractAuthor.clear(); - m_title.clear(); - parseDocString(*contractDoc, CommentOwner::Contract); - - if (!m_contractAuthor.empty()) - doc["author"] = m_contractAuthor; - - if (!m_title.empty()) - doc["title"] = m_title; - } - - for (auto const& it: _contractDef.interfaceFunctions()) - { - Json::Value method; - auto strPtr = it.second->documentation(); - if (strPtr) - { - resetDev(); - parseDocString(*strPtr, CommentOwner::Function); - - if (!m_dev.empty()) - method["details"] = Json::Value(m_dev); - - if (!m_author.empty()) - method["author"] = m_author; - - Json::Value params(Json::objectValue); - vector<string> paramNames = it.second->parameterNames(); - for (auto const& pair: m_params) - { - if (find(paramNames.begin(), paramNames.end(), pair.first) == paramNames.end()) - // LTODO: mismatching parameter name, throw some form of warning and not just an exception - BOOST_THROW_EXCEPTION( - Error(Error::Type::DocstringParsingError) << - errinfo_comment("documented parameter \"" + pair.first + "\" not found in the parameter list of the function.") - ); - params[pair.first] = pair.second; - } - - 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[it.second->externalSignature()] = method; - } - } - doc["methods"] = methods; - - return Json::StyledWriter().write(doc); -} - -/* -- private -- */ -void InterfaceHandler::resetUser() -{ - m_notice.clear(); -} - -void InterfaceHandler::resetDev() -{ - m_dev.clear(); - m_author.clear(); - m_return.clear(); - m_params.clear(); -} - -static inline string::const_iterator skipLineOrEOS( - string::const_iterator _nlPos, - string::const_iterator _end -) -{ - return (_nlPos == _end) ? _end : ++_nlPos; -} - -string::const_iterator InterfaceHandler::parseDocTagLine( - string::const_iterator _pos, - string::const_iterator _end, - string& _tagString, - DocTagType _tagType, - bool _appending -) -{ - auto nlPos = find(_pos, _end, '\n'); - if (_appending && _pos < _end && *_pos != ' ') - _tagString += " "; - copy(_pos, nlPos, back_inserter(_tagString)); - m_lastTag = _tagType; - return skipLineOrEOS(nlPos, _end); -} - -string::const_iterator InterfaceHandler::parseDocTagParam( - string::const_iterator _pos, - string::const_iterator _end -) -{ - // find param name - auto currPos = find(_pos, _end, ' '); - if (currPos == _end) - BOOST_THROW_EXCEPTION(Error(Error::Type::DocstringParsingError) << errinfo_comment("End of param name not found" + string(_pos, _end))); - - - auto paramName = string(_pos, currPos); - - currPos += 1; - auto nlPos = find(currPos, _end, '\n'); - auto paramDesc = string(currPos, nlPos); - m_params.push_back(make_pair(paramName, paramDesc)); - - m_lastTag = DocTagType::Param; - return skipLineOrEOS(nlPos, _end); -} - -string::const_iterator InterfaceHandler::appendDocTagParam( - string::const_iterator _pos, - string::const_iterator _end -) -{ - // Should never be called with an empty vector - solAssert(!m_params.empty(), "Internal: Tried to append to empty parameter"); - - auto pair = m_params.back(); - if (_pos < _end && *_pos != ' ') - pair.second += " "; - auto nlPos = find(_pos, _end, '\n'); - copy(_pos, nlPos, back_inserter(pair.second)); - - m_params.at(m_params.size() - 1) = pair; - - return skipLineOrEOS(nlPos, _end); -} - -string::const_iterator InterfaceHandler::parseDocTag( - string::const_iterator _pos, - string::const_iterator _end, - string const& _tag, - CommentOwner _owner -) -{ - // LTODO: need to check for @(start of a tag) between here and the end of line - // for all cases. Also somehow automate list of acceptable tags for each - // language construct since current way does not scale well. - if (m_lastTag == DocTagType::None || _tag != "") - { - if (_tag == "dev") - return parseDocTagLine(_pos, _end, m_dev, DocTagType::Dev, false); - else if (_tag == "notice") - return parseDocTagLine(_pos, _end, m_notice, DocTagType::Notice, false); - else if (_tag == "return") - return parseDocTagLine(_pos, _end, m_return, DocTagType::Return, false); - else if (_tag == "author") - { - if (_owner == CommentOwner::Contract) - return parseDocTagLine(_pos, _end, m_contractAuthor, DocTagType::Author, false); - else if (_owner == CommentOwner::Function) - return parseDocTagLine(_pos, _end, m_author, DocTagType::Author, false); - else - // LTODO: for now this else makes no sense but later comments will go to more language constructs - BOOST_THROW_EXCEPTION(Error(Error::Type::DocstringParsingError) << errinfo_comment("@author tag is legal only for contracts")); - } - else if (_tag == "title") - { - if (_owner == CommentOwner::Contract) - return parseDocTagLine(_pos, _end, m_title, DocTagType::Title, false); - else - // LTODO: Unknown tag, throw some form of warning and not just an exception - BOOST_THROW_EXCEPTION(Error(Error::Type::DocstringParsingError) << errinfo_comment("@title tag is legal only for contracts")); - } - else if (_tag == "param") - return parseDocTagParam(_pos, _end); - else - // LTODO: Unknown tag, throw some form of warning and not just an exception - BOOST_THROW_EXCEPTION(Error(Error::Type::DocstringParsingError) << errinfo_comment("Unknown tag " + _tag + " encountered")); - } - else - return appendDocTag(_pos, _end, _owner); -} - -string::const_iterator InterfaceHandler::appendDocTag( - string::const_iterator _pos, - string::const_iterator _end, - CommentOwner _owner -) -{ - switch (m_lastTag) - { - case DocTagType::Dev: - return parseDocTagLine(_pos, _end, m_dev, DocTagType::Dev, true); - case DocTagType::Notice: - return parseDocTagLine(_pos, _end, m_notice, DocTagType::Notice, true); - case DocTagType::Return: - return parseDocTagLine(_pos, _end, m_return, DocTagType::Return, true); - case DocTagType::Author: - if (_owner == CommentOwner::Contract) - return parseDocTagLine(_pos, _end, m_contractAuthor, DocTagType::Author, true); - else if (_owner == CommentOwner::Function) - return parseDocTagLine(_pos, _end, m_author, DocTagType::Author, true); - else - // LTODO: Unknown tag, throw some form of warning and not just an exception - BOOST_THROW_EXCEPTION(Error(Error::Type::DocstringParsingError) << errinfo_comment("@author tag in illegal comment")); - case DocTagType::Title: - if (_owner == CommentOwner::Contract) - return parseDocTagLine(_pos, _end, m_title, DocTagType::Title, true); - else - // LTODO: Unknown tag, throw some form of warning and not just an exception - BOOST_THROW_EXCEPTION(Error(Error::Type::DocstringParsingError) << errinfo_comment("@title tag in illegal comment")); - case DocTagType::Param: - return appendDocTagParam(_pos, _end); - default: - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Internal: Illegal documentation tag type")); - break; - } -} - -static inline string::const_iterator firstSpaceOrNl( - string::const_iterator _pos, - string::const_iterator _end -) -{ - auto spacePos = find(_pos, _end, ' '); - auto nlPos = find(_pos, _end, '\n'); - return (spacePos < nlPos) ? spacePos : nlPos; -} - -void InterfaceHandler::parseDocString(string const& _string, CommentOwner _owner) -{ - auto currPos = _string.begin(); - auto end = _string.end(); - - while (currPos != end) - { - auto tagPos = find(currPos, end, '@'); - auto nlPos = find(currPos, end, '\n'); - - if (tagPos != end && tagPos < nlPos) - { - // we found a tag - auto tagNameEndPos = firstSpaceOrNl(tagPos, end); - if (tagNameEndPos == end) - BOOST_THROW_EXCEPTION( - Error(Error::Type::DocstringParsingError) << - errinfo_comment("End of tag " + string(tagPos, tagNameEndPos) + "not found")); - - currPos = parseDocTag(tagNameEndPos + 1, end, string(tagPos + 1, tagNameEndPos), _owner); - } - else if (m_lastTag != DocTagType::None) // continuation of the previous tag - currPos = appendDocTag(currPos, end, _owner); - else if (currPos != end) - { - // if it begins without a tag then consider it as @notice - if (currPos == _string.begin()) - { - currPos = parseDocTag(currPos, end, "notice", CommentOwner::Function); - continue; - } - else if (nlPos == end) //end of text - return; - // else skip the line if a newline was found and we get here - currPos = nlPos + 1; - } - } -} - -} //solidity NS -} // dev NS diff --git a/libsolidity/ConstantEvaluator.cpp b/libsolidity/analysis/ConstantEvaluator.cpp index 5936b3d4..6beb655e 100644 --- a/libsolidity/ConstantEvaluator.cpp +++ b/libsolidity/analysis/ConstantEvaluator.cpp @@ -20,8 +20,8 @@ * Evaluator for types of constant expressions. */ -#include <libsolidity/ConstantEvaluator.h> -#include <libsolidity/AST.h> +#include <libsolidity/analysis/ConstantEvaluator.h> +#include <libsolidity/ast/AST.h> using namespace std; using namespace dev; diff --git a/libsolidity/ConstantEvaluator.h b/libsolidity/analysis/ConstantEvaluator.h index cf3d2094..f311efbf 100644 --- a/libsolidity/ConstantEvaluator.h +++ b/libsolidity/analysis/ConstantEvaluator.h @@ -22,7 +22,7 @@ #pragma once -#include <libsolidity/ASTVisitor.h> +#include <libsolidity/ast/ASTVisitor.h> namespace dev { diff --git a/libsolidity/DeclarationContainer.cpp b/libsolidity/analysis/DeclarationContainer.cpp index dbe9715d..7339ad5d 100644 --- a/libsolidity/DeclarationContainer.cpp +++ b/libsolidity/analysis/DeclarationContainer.cpp @@ -20,9 +20,9 @@ * Scope - object that holds declaration of names. */ -#include <libsolidity/DeclarationContainer.h> -#include <libsolidity/AST.h> -#include <libsolidity/Types.h> +#include <libsolidity/analysis/DeclarationContainer.h> +#include <libsolidity/ast/AST.h> +#include <libsolidity/ast/Types.h> using namespace std; using namespace dev; diff --git a/libsolidity/DeclarationContainer.h b/libsolidity/analysis/DeclarationContainer.h index 3d6ed2cc..064724d1 100644 --- a/libsolidity/DeclarationContainer.h +++ b/libsolidity/analysis/DeclarationContainer.h @@ -26,7 +26,7 @@ #include <set> #include <boost/noncopyable.hpp> -#include <libsolidity/ASTForward.h> +#include <libsolidity/ast/ASTForward.h> namespace dev { diff --git a/libsolidity/analysis/DocStringAnalyser.cpp b/libsolidity/analysis/DocStringAnalyser.cpp new file mode 100644 index 00000000..4f75f03d --- /dev/null +++ b/libsolidity/analysis/DocStringAnalyser.cpp @@ -0,0 +1,128 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. +*/ +/** + * @author Christian <c@ethdev.com> + * @date 2015 + * Parses and analyses the doc strings. + * Stores the parsing results in the AST annotations and reports errors. + */ + +#include <libsolidity/analysis/DocStringAnalyser.h> +#include <libsolidity/ast/AST.h> +#include <libsolidity/parsing/DocStringParser.h> + +using namespace std; +using namespace dev; +using namespace dev::solidity; + +bool DocStringAnalyser::analyseDocStrings(SourceUnit const& _sourceUnit) +{ + m_errorOccured = false; + _sourceUnit.accept(*this); + + return !m_errorOccured; +} + +bool DocStringAnalyser::visit(ContractDefinition const& _node) +{ + static const set<string> validTags = set<string>{"author", "title", "dev", "notice", "why3"}; + parseDocStrings(_node, _node.annotation(), validTags, "contracts"); + + return true; +} + +bool DocStringAnalyser::visit(FunctionDefinition const& _node) +{ + handleCallable(_node, _node, _node.annotation()); + return true; +} + +bool DocStringAnalyser::visit(ModifierDefinition const& _node) +{ + handleCallable(_node, _node, _node.annotation()); + + return true; +} + +bool DocStringAnalyser::visit(EventDefinition const& _node) +{ + handleCallable(_node, _node, _node.annotation()); + + return true; +} + +bool DocStringAnalyser::visitNode(ASTNode const& _node) +{ + if (auto node = dynamic_cast<Statement const*>(&_node)) + { + static const set<string> validTags = {"why3"}; + parseDocStrings(*node, node->annotation(), validTags, "statements"); + } + return true; +} + +void DocStringAnalyser::handleCallable( + CallableDeclaration const& _callable, + Documented const& _node, + DocumentedAnnotation& _annotation +) +{ + static const set<string> validTags = set<string>{"author", "dev", "notice", "return", "param", "why3"}; + parseDocStrings(_node, _annotation, validTags, "functions"); + + set<string> validParams; + for (auto const& p: _callable.parameters()) + validParams.insert(p->name()); + if (_callable.returnParameterList()) + for (auto const& p: _callable.returnParameterList()->parameters()) + validParams.insert(p->name()); + auto paramRange = _annotation.docTags.equal_range("param"); + for (auto i = paramRange.first; i != paramRange.second; ++i) + if (!validParams.count(i->second.paramName)) + appendError( + "Documented parameter \"" + + i->second.paramName + + "\" not found in the parameter list of the function." + ); +} + +void DocStringAnalyser::parseDocStrings( + Documented const& _node, + DocumentedAnnotation& _annotation, + set<string> const& _validTags, + string const& _nodeName +) +{ + DocStringParser parser; + if (_node.documentation() && !_node.documentation()->empty()) + { + if (!parser.parse(*_node.documentation(), m_errors)) + m_errorOccured = true; + _annotation.docTags = parser.tags(); + } + for (auto const& docTag: _annotation.docTags) + if (!_validTags.count(docTag.first)) + appendError("Doc tag @" + docTag.first + " not valid for " + _nodeName + "."); +} + +void DocStringAnalyser::appendError(string const& _description) +{ + auto err = make_shared<Error>(Error::Type::DocstringParsingError); + *err << errinfo_comment(_description); + m_errors.push_back(err); + m_errorOccured = true; +} diff --git a/libsolidity/analysis/DocStringAnalyser.h b/libsolidity/analysis/DocStringAnalyser.h new file mode 100644 index 00000000..cdf297e3 --- /dev/null +++ b/libsolidity/analysis/DocStringAnalyser.h @@ -0,0 +1,71 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. +*/ +/** + * @author Christian <c@ethdev.com> + * @date 2015 + * Parses and analyses the doc strings. + * Stores the parsing results in the AST annotations and reports errors. + */ + +#pragma once + +#include <libsolidity/ast/ASTVisitor.h> + +namespace dev +{ +namespace solidity +{ + +/** + * Parses and analyses the doc strings. + * Stores the parsing results in the AST annotations and reports errors. + */ +class DocStringAnalyser: private ASTConstVisitor +{ +public: + DocStringAnalyser(ErrorList& _errors): m_errors(_errors) {} + bool analyseDocStrings(SourceUnit const& _sourceUnit); + +private: + virtual bool visit(ContractDefinition const& _contract) override; + virtual bool visit(FunctionDefinition const& _function) override; + virtual bool visit(ModifierDefinition const& _modifier) override; + virtual bool visit(EventDefinition const& _event) override; + + virtual bool visitNode(ASTNode const&) override; + + void handleCallable( + CallableDeclaration const& _callable, + Documented const& _node, + DocumentedAnnotation& _annotation + ); + + void parseDocStrings( + Documented const& _node, + DocumentedAnnotation& _annotation, + std::set<std::string> const& _validTags, + std::string const& _nodeName + ); + + void appendError(std::string const& _description); + + bool m_errorOccured = false; + ErrorList& m_errors; +}; + +} +} diff --git a/libsolidity/GlobalContext.cpp b/libsolidity/analysis/GlobalContext.cpp index a0f5396f..20f8272f 100644 --- a/libsolidity/GlobalContext.cpp +++ b/libsolidity/analysis/GlobalContext.cpp @@ -22,9 +22,9 @@ */ #include <memory> -#include <libsolidity/GlobalContext.h> -#include <libsolidity/AST.h> -#include <libsolidity/Types.h> +#include <libsolidity/analysis/GlobalContext.h> +#include <libsolidity/ast/AST.h> +#include <libsolidity/ast/Types.h> using namespace std; diff --git a/libsolidity/GlobalContext.h b/libsolidity/analysis/GlobalContext.h index 20ffecb4..482391d3 100644 --- a/libsolidity/GlobalContext.h +++ b/libsolidity/analysis/GlobalContext.h @@ -27,7 +27,7 @@ #include <map> #include <memory> #include <boost/noncopyable.hpp> -#include <libsolidity/ASTForward.h> +#include <libsolidity/ast/ASTForward.h> namespace dev { diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp index edd0704d..ffd01137 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/analysis/NameAndTypeResolver.cpp @@ -20,10 +20,10 @@ * Parser part that determines the declarations corresponding to names and the types of expressions. */ -#include <libsolidity/NameAndTypeResolver.h> -#include <libsolidity/AST.h> -#include <libsolidity/TypeChecker.h> -#include <libsolidity/Exceptions.h> +#include <libsolidity/analysis/NameAndTypeResolver.h> +#include <libsolidity/ast/AST.h> +#include <libsolidity/analysis/TypeChecker.h> +#include <libsolidity/interface/Exceptions.h> using namespace std; diff --git a/libsolidity/NameAndTypeResolver.h b/libsolidity/analysis/NameAndTypeResolver.h index 7169f302..0d9b2477 100644 --- a/libsolidity/NameAndTypeResolver.h +++ b/libsolidity/analysis/NameAndTypeResolver.h @@ -25,10 +25,10 @@ #include <map> #include <list> #include <boost/noncopyable.hpp> -#include <libsolidity/DeclarationContainer.h> -#include <libsolidity/ReferencesResolver.h> -#include <libsolidity/ASTVisitor.h> -#include <libsolidity/ASTAnnotations.h> +#include <libsolidity/analysis/DeclarationContainer.h> +#include <libsolidity/analysis/ReferencesResolver.h> +#include <libsolidity/ast/ASTVisitor.h> +#include <libsolidity/ast/ASTAnnotations.h> namespace dev { diff --git a/libsolidity/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index b1112dd9..fb7cdb3e 100644 --- a/libsolidity/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -20,11 +20,11 @@ * Component that resolves type names to types and annotates the AST accordingly. */ -#include <libsolidity/ReferencesResolver.h> -#include <libsolidity/AST.h> -#include <libsolidity/NameAndTypeResolver.h> -#include <libsolidity/Exceptions.h> -#include <libsolidity/ConstantEvaluator.h> +#include <libsolidity/analysis/ReferencesResolver.h> +#include <libsolidity/ast/AST.h> +#include <libsolidity/analysis/NameAndTypeResolver.h> +#include <libsolidity/interface/Exceptions.h> +#include <libsolidity/analysis/ConstantEvaluator.h> using namespace std; using namespace dev; diff --git a/libsolidity/ReferencesResolver.h b/libsolidity/analysis/ReferencesResolver.h index b8a55dc2..4276adaa 100644 --- a/libsolidity/ReferencesResolver.h +++ b/libsolidity/analysis/ReferencesResolver.h @@ -25,8 +25,8 @@ #include <map> #include <list> #include <boost/noncopyable.hpp> -#include <libsolidity/ASTVisitor.h> -#include <libsolidity/ASTAnnotations.h> +#include <libsolidity/ast/ASTVisitor.h> +#include <libsolidity/ast/ASTAnnotations.h> namespace dev { diff --git a/libsolidity/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 5ea5825d..6b12c57f 100644 --- a/libsolidity/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -20,10 +20,10 @@ * Type analyzer and checker. */ -#include <libsolidity/TypeChecker.h> +#include <libsolidity/analysis/TypeChecker.h> #include <memory> #include <boost/range/adaptor/reversed.hpp> -#include <libsolidity/AST.h> +#include <libsolidity/ast/AST.h> using namespace std; using namespace dev; diff --git a/libsolidity/TypeChecker.h b/libsolidity/analysis/TypeChecker.h index 7af5473b..9a568349 100644 --- a/libsolidity/TypeChecker.h +++ b/libsolidity/analysis/TypeChecker.h @@ -22,11 +22,11 @@ #pragma once -#include <libsolidity/TypeChecker.h> -#include <libsolidity/Types.h> -#include <libsolidity/ASTAnnotations.h> -#include <libsolidity/ASTForward.h> -#include <libsolidity/ASTVisitor.h> +#include <libsolidity/analysis/TypeChecker.h> +#include <libsolidity/ast/Types.h> +#include <libsolidity/ast/ASTAnnotations.h> +#include <libsolidity/ast/ASTForward.h> +#include <libsolidity/ast/ASTVisitor.h> namespace dev { diff --git a/libsolidity/AST.cpp b/libsolidity/ast/AST.cpp index 062febb9..41a4d182 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -22,11 +22,11 @@ #include <algorithm> #include <functional> -#include <libsolidity/Utils.h> -#include <libsolidity/AST.h> -#include <libsolidity/ASTVisitor.h> -#include <libsolidity/Exceptions.h> -#include <libsolidity/AST_accept.h> +#include <libsolidity/interface/Utils.h> +#include <libsolidity/ast/AST.h> +#include <libsolidity/ast/ASTVisitor.h> +#include <libsolidity/interface/Exceptions.h> +#include <libsolidity/ast/AST_accept.h> #include <libdevcore/SHA3.h> @@ -248,16 +248,37 @@ string FunctionDefinition::externalSignature() const return FunctionType(*this).externalSignature(); } +FunctionDefinitionAnnotation& FunctionDefinition::annotation() const +{ + if (!m_annotation) + m_annotation = new FunctionDefinitionAnnotation(); + return static_cast<FunctionDefinitionAnnotation&>(*m_annotation); +} + TypePointer ModifierDefinition::type(ContractDefinition const*) const { return make_shared<ModifierType>(*this); } +ModifierDefinitionAnnotation& ModifierDefinition::annotation() const +{ + if (!m_annotation) + m_annotation = new ModifierDefinitionAnnotation(); + return static_cast<ModifierDefinitionAnnotation&>(*m_annotation); +} + TypePointer EventDefinition::type(ContractDefinition const*) const { return make_shared<FunctionType>(*this); } +EventDefinitionAnnotation& EventDefinition::annotation() const +{ + if (!m_annotation) + m_annotation = new EventDefinitionAnnotation(); + return static_cast<EventDefinitionAnnotation&>(*m_annotation); +} + UserDefinedTypeNameAnnotation& UserDefinedTypeName::annotation() const { if (!m_annotation) @@ -315,6 +336,13 @@ VariableDeclarationAnnotation& VariableDeclaration::annotation() const return static_cast<VariableDeclarationAnnotation&>(*m_annotation); } +StatementAnnotation& Statement::annotation() const +{ + if (!m_annotation) + m_annotation = new StatementAnnotation(); + return static_cast<StatementAnnotation&>(*m_annotation); +} + ReturnAnnotation& Return::annotation() const { if (!m_annotation) diff --git a/libsolidity/AST.h b/libsolidity/ast/AST.h index fc1db3f3..1a204dca 100644 --- a/libsolidity/AST.h +++ b/libsolidity/ast/AST.h @@ -28,12 +28,12 @@ #include <memory> #include <boost/noncopyable.hpp> #include <libevmasm/SourceLocation.h> -#include <libsolidity/Utils.h> -#include <libsolidity/ASTForward.h> -#include <libsolidity/Token.h> -#include <libsolidity/Types.h> -#include <libsolidity/Exceptions.h> -#include <libsolidity/ASTAnnotations.h> +#include <libsolidity/interface/Utils.h> +#include <libsolidity/ast/ASTForward.h> +#include <libsolidity/parsing/Token.h> +#include <libsolidity/ast/Types.h> +#include <libsolidity/interface/Exceptions.h> +#include <libsolidity/ast/ASTAnnotations.h> namespace dev { @@ -492,6 +492,8 @@ public: virtual TypePointer type(ContractDefinition const* m_currentContract) const override; + virtual FunctionDefinitionAnnotation& annotation() const override; + private: bool m_isConstructor; bool m_isDeclaredConst; @@ -593,6 +595,8 @@ public: virtual TypePointer type(ContractDefinition const* m_currentContract) const override; + virtual ModifierDefinitionAnnotation& annotation() const override; + private: ASTPointer<Block> m_body; }; @@ -647,6 +651,8 @@ public: virtual TypePointer type(ContractDefinition const* m_currentContract) const override; + virtual EventDefinitionAnnotation& annotation() const override; + private: bool m_anonymous = false; }; @@ -786,10 +792,15 @@ private: /** * Abstract base class for statements. */ -class Statement: public ASTNode +class Statement: public ASTNode, public Documented { public: - explicit Statement(SourceLocation const& _location): ASTNode(_location) {} + explicit Statement( + SourceLocation const& _location, + ASTPointer<ASTString> const& _docString + ): ASTNode(_location), Documented(_docString) {} + + virtual StatementAnnotation& annotation() const override; }; /** @@ -800,9 +811,10 @@ class Block: public Statement public: Block( SourceLocation const& _location, + ASTPointer<ASTString> const& _docString, std::vector<ASTPointer<Statement>> const& _statements ): - Statement(_location), m_statements(_statements) {} + Statement(_location, _docString), m_statements(_statements) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; @@ -817,7 +829,10 @@ private: class PlaceholderStatement: public Statement { public: - explicit PlaceholderStatement(SourceLocation const& _location): Statement(_location) {} + explicit PlaceholderStatement( + SourceLocation const& _location, + ASTPointer<ASTString> const& _docString + ): Statement(_location, _docString) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; @@ -832,11 +847,12 @@ class IfStatement: public Statement public: IfStatement( SourceLocation const& _location, + ASTPointer<ASTString> const& _docString, ASTPointer<Expression> const& _condition, ASTPointer<Statement> const& _trueBody, ASTPointer<Statement> const& _falseBody ): - Statement(_location), + Statement(_location, _docString), m_condition(_condition), m_trueBody(_trueBody), m_falseBody(_falseBody) @@ -861,7 +877,10 @@ private: class BreakableStatement: public Statement { public: - explicit BreakableStatement(SourceLocation const& _location): Statement(_location) {} + explicit BreakableStatement( + SourceLocation const& _location, + ASTPointer<ASTString> const& _docString + ): Statement(_location, _docString) {} }; class WhileStatement: public BreakableStatement @@ -869,10 +888,11 @@ class WhileStatement: public BreakableStatement public: WhileStatement( SourceLocation const& _location, + ASTPointer<ASTString> const& _docString, ASTPointer<Expression> const& _condition, ASTPointer<Statement> const& _body ): - BreakableStatement(_location), m_condition(_condition), m_body(_body) {} + BreakableStatement(_location, _docString), m_condition(_condition), m_body(_body) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; @@ -892,12 +912,13 @@ class ForStatement: public BreakableStatement public: ForStatement( SourceLocation const& _location, + ASTPointer<ASTString> const& _docString, ASTPointer<Statement> const& _initExpression, ASTPointer<Expression> const& _conditionExpression, ASTPointer<ExpressionStatement> const& _loopExpression, ASTPointer<Statement> const& _body ): - BreakableStatement(_location), + BreakableStatement(_location, _docString), m_initExpression(_initExpression), m_condExpression(_conditionExpression), m_loopExpression(_loopExpression), @@ -925,7 +946,8 @@ private: class Continue: public Statement { public: - explicit Continue(SourceLocation const& _location): Statement(_location) {} + explicit Continue(SourceLocation const& _location, ASTPointer<ASTString> const& _docString): + Statement(_location, _docString) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; }; @@ -933,7 +955,8 @@ public: class Break: public Statement { public: - explicit Break(SourceLocation const& _location): Statement(_location) {} + explicit Break(SourceLocation const& _location, ASTPointer<ASTString> const& _docString): + Statement(_location, _docString) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; }; @@ -941,8 +964,11 @@ public: class Return: public Statement { public: - Return(SourceLocation const& _location, ASTPointer<Expression> _expression): - Statement(_location), m_expression(_expression) {} + Return( + SourceLocation const& _location, + ASTPointer<ASTString> const& _docString, + ASTPointer<Expression> _expression + ): Statement(_location, _docString), m_expression(_expression) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; @@ -960,7 +986,8 @@ private: class Throw: public Statement { public: - explicit Throw(SourceLocation const& _location): Statement(_location) {} + explicit Throw(SourceLocation const& _location, ASTPointer<ASTString> const& _docString): + Statement(_location, _docString) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; }; @@ -979,10 +1006,11 @@ class VariableDeclarationStatement: public Statement public: VariableDeclarationStatement( SourceLocation const& _location, + ASTPointer<ASTString> const& _docString, std::vector<ASTPointer<VariableDeclaration>> const& _variables, ASTPointer<Expression> const& _initialValue ): - Statement(_location), m_variables(_variables), m_initialValue(_initialValue) {} + Statement(_location, _docString), m_variables(_variables), m_initialValue(_initialValue) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; @@ -1006,9 +1034,10 @@ class ExpressionStatement: public Statement public: ExpressionStatement( SourceLocation const& _location, + ASTPointer<ASTString> const& _docString, ASTPointer<Expression> _expression ): - Statement(_location), m_expression(_expression) {} + Statement(_location, _docString), m_expression(_expression) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; diff --git a/libsolidity/ASTAnnotations.cpp b/libsolidity/ast/ASTAnnotations.cpp index 4253e16d..416e6b44 100644 --- a/libsolidity/ASTAnnotations.cpp +++ b/libsolidity/ast/ASTAnnotations.cpp @@ -20,7 +20,7 @@ * Object containing the type and other annotations for the AST nodes. */ -#include <libsolidity/ASTAnnotations.h> +#include <libsolidity/ast/ASTAnnotations.h> using namespace std; using namespace dev; diff --git a/libsolidity/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h index 1b772ffa..bb59ceae 100644 --- a/libsolidity/ASTAnnotations.h +++ b/libsolidity/ast/ASTAnnotations.h @@ -26,7 +26,7 @@ #include <memory> #include <vector> #include <set> -#include <libsolidity/ASTForward.h> +#include <libsolidity/ast/ASTForward.h> namespace dev { @@ -41,13 +41,26 @@ struct ASTAnnotation virtual ~ASTAnnotation() {} }; +struct DocTag +{ + std::string content; ///< The text content of the tag. + std::string paramName; ///< Only used for @param, stores the parameter name. +}; + +struct DocumentedAnnotation +{ + virtual ~DocumentedAnnotation() {} + /// Mapping docstring tag name -> content. + std::multimap<std::string, DocTag> docTags; +}; + struct TypeDeclarationAnnotation: ASTAnnotation { /// The name of this type, prefixed by proper namespaces if globally accessible. std::string canonicalName; }; -struct ContractDefinitionAnnotation: TypeDeclarationAnnotation +struct ContractDefinitionAnnotation: TypeDeclarationAnnotation, DocumentedAnnotation { /// Whether all functions are implemented. bool isFullyImplemented = true; @@ -59,13 +72,29 @@ struct ContractDefinitionAnnotation: TypeDeclarationAnnotation std::set<ContractDefinition const*> contractDependencies; }; +struct FunctionDefinitionAnnotation: ASTAnnotation, DocumentedAnnotation +{ +}; + +struct EventDefinitionAnnotation: ASTAnnotation, DocumentedAnnotation +{ +}; + +struct ModifierDefinitionAnnotation: ASTAnnotation, DocumentedAnnotation +{ +}; + struct VariableDeclarationAnnotation: ASTAnnotation { /// Type of variable (type of identifier referencing this variable). TypePointer type; }; -struct ReturnAnnotation: ASTAnnotation +struct StatementAnnotation: ASTAnnotation, DocumentedAnnotation +{ +}; + +struct ReturnAnnotation: StatementAnnotation { /// Reference to the return parameters of the function. ParameterList const* functionReturnParameters = nullptr; @@ -84,7 +113,7 @@ struct UserDefinedTypeNameAnnotation: TypeNameAnnotation Declaration const* referencedDeclaration = nullptr; }; -struct VariableDeclarationStatementAnnotation: ASTAnnotation +struct VariableDeclarationStatementAnnotation: StatementAnnotation { /// Information about which component of the value is assigned to which variable. /// The pointer can be null to signify that the component is discarded. diff --git a/libsolidity/ASTForward.h b/libsolidity/ast/ASTForward.h index 02dd054a..02dd054a 100644 --- a/libsolidity/ASTForward.h +++ b/libsolidity/ast/ASTForward.h diff --git a/libsolidity/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index 34012c73..f208c3c9 100644 --- a/libsolidity/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -20,9 +20,9 @@ * Converts the AST into json format */ -#include <libsolidity/ASTJsonConverter.h> +#include <libsolidity/ast/ASTJsonConverter.h> #include <boost/algorithm/string/join.hpp> -#include <libsolidity/AST.h> +#include <libsolidity/ast/AST.h> using namespace std; diff --git a/libsolidity/ASTJsonConverter.h b/libsolidity/ast/ASTJsonConverter.h index a62259e2..de891cc6 100644 --- a/libsolidity/ASTJsonConverter.h +++ b/libsolidity/ast/ASTJsonConverter.h @@ -24,10 +24,10 @@ #include <ostream> #include <stack> -#include <libsolidity/ASTVisitor.h> -#include <libsolidity/Exceptions.h> -#include <libsolidity/Utils.h> -#include <libsolidity/ASTAnnotations.h> +#include <libsolidity/ast/ASTVisitor.h> +#include <libsolidity/interface/Exceptions.h> +#include <libsolidity/interface/Utils.h> +#include <libsolidity/ast/ASTAnnotations.h> #include <json/json.h> namespace dev diff --git a/libsolidity/ASTPrinter.cpp b/libsolidity/ast/ASTPrinter.cpp index cb231842..9253e0bf 100644 --- a/libsolidity/ASTPrinter.cpp +++ b/libsolidity/ast/ASTPrinter.cpp @@ -20,9 +20,9 @@ * Pretty-printer for the abstract syntax tree (the "pretty" is arguable), used for debugging. */ -#include <libsolidity/ASTPrinter.h> +#include <libsolidity/ast/ASTPrinter.h> #include <boost/algorithm/string/join.hpp> -#include <libsolidity/AST.h> +#include <libsolidity/ast/AST.h> using namespace std; diff --git a/libsolidity/ASTPrinter.h b/libsolidity/ast/ASTPrinter.h index 95656436..d9b5e252 100644 --- a/libsolidity/ASTPrinter.h +++ b/libsolidity/ast/ASTPrinter.h @@ -23,8 +23,8 @@ #pragma once #include <ostream> -#include <libsolidity/ASTVisitor.h> -#include <libsolidity/GasEstimator.h> +#include <libsolidity/ast/ASTVisitor.h> +#include <libsolidity/interface/GasEstimator.h> namespace dev { diff --git a/libsolidity/ASTUtils.cpp b/libsolidity/ast/ASTUtils.cpp index a617bf94..e9b70b62 100644 --- a/libsolidity/ASTUtils.cpp +++ b/libsolidity/ast/ASTUtils.cpp @@ -20,7 +20,7 @@ * Utilities to work with the AST. */ -#include <libsolidity/ASTUtils.h> +#include <libsolidity/ast/ASTUtils.h> using namespace std; using namespace dev; diff --git a/libsolidity/ASTUtils.h b/libsolidity/ast/ASTUtils.h index b24a3404..237537ec 100644 --- a/libsolidity/ASTUtils.h +++ b/libsolidity/ast/ASTUtils.h @@ -23,7 +23,7 @@ #pragma once #include <libevmasm/SourceLocation.h> -#include <libsolidity/ASTVisitor.h> +#include <libsolidity/ast/ASTVisitor.h> namespace dev { diff --git a/libsolidity/ASTVisitor.h b/libsolidity/ast/ASTVisitor.h index 3e50fb28..14c09fb4 100644 --- a/libsolidity/ASTVisitor.h +++ b/libsolidity/ast/ASTVisitor.h @@ -25,7 +25,7 @@ #include <string> #include <functional> #include <vector> -#include <libsolidity/AST.h> +#include <libsolidity/ast/AST.h> namespace dev { diff --git a/libsolidity/AST_accept.h b/libsolidity/ast/AST_accept.h index eb1f6098..12a26ea7 100644 --- a/libsolidity/AST_accept.h +++ b/libsolidity/ast/AST_accept.h @@ -23,8 +23,8 @@ #pragma once -#include <libsolidity/AST.h> -#include <libsolidity/ASTVisitor.h> +#include <libsolidity/ast/AST.h> +#include <libsolidity/ast/ASTVisitor.h> namespace dev { diff --git a/libsolidity/Types.cpp b/libsolidity/ast/Types.cpp index 02b86a7f..0253e843 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -20,14 +20,14 @@ * Solidity data types */ -#include <libsolidity/Types.h> +#include <libsolidity/ast/Types.h> #include <limits> #include <boost/range/adaptor/reversed.hpp> #include <libdevcore/CommonIO.h> #include <libdevcore/CommonData.h> #include <libdevcore/SHA3.h> -#include <libsolidity/Utils.h> -#include <libsolidity/AST.h> +#include <libsolidity/interface/Utils.h> +#include <libsolidity/ast/AST.h> using namespace std; using namespace dev; diff --git a/libsolidity/Types.h b/libsolidity/ast/Types.h index 626ebbe4..2f75975f 100644 --- a/libsolidity/Types.h +++ b/libsolidity/ast/Types.h @@ -27,9 +27,9 @@ #include <map> #include <boost/noncopyable.hpp> #include <libdevcore/Common.h> -#include <libsolidity/Exceptions.h> -#include <libsolidity/ASTForward.h> -#include <libsolidity/Token.h> +#include <libsolidity/interface/Exceptions.h> +#include <libsolidity/ast/ASTForward.h> +#include <libsolidity/parsing/Token.h> #include <libdevcore/UndefMacros.h> namespace dev diff --git a/libsolidity/ArrayUtils.cpp b/libsolidity/codegen/ArrayUtils.cpp index 1999eb77..ba26caa6 100644 --- a/libsolidity/ArrayUtils.cpp +++ b/libsolidity/codegen/ArrayUtils.cpp @@ -20,13 +20,13 @@ * Code generation utils that handle arrays. */ -#include <libsolidity/ArrayUtils.h> +#include <libsolidity/codegen/ArrayUtils.h> #include <libevmcore/Instruction.h> -#include <libsolidity/CompilerContext.h> -#include <libsolidity/CompilerUtils.h> -#include <libsolidity/Types.h> -#include <libsolidity/Utils.h> -#include <libsolidity/LValue.h> +#include <libsolidity/codegen/CompilerContext.h> +#include <libsolidity/codegen/CompilerUtils.h> +#include <libsolidity/ast/Types.h> +#include <libsolidity/interface/Utils.h> +#include <libsolidity/codegen/LValue.h> using namespace std; using namespace dev; diff --git a/libsolidity/ArrayUtils.h b/libsolidity/codegen/ArrayUtils.h index 53d36c14..53d36c14 100644 --- a/libsolidity/ArrayUtils.h +++ b/libsolidity/codegen/ArrayUtils.h diff --git a/libsolidity/Compiler.cpp b/libsolidity/codegen/Compiler.cpp index 679704ba..5daa37de 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/codegen/Compiler.cpp @@ -20,15 +20,15 @@ * Solidity compiler. */ -#include <libsolidity/Compiler.h> +#include <libsolidity/codegen/Compiler.h> #include <algorithm> #include <boost/range/adaptor/reversed.hpp> #include <libevmcore/Instruction.h> #include <libevmasm/Assembly.h> #include <libevmcore/Params.h> -#include <libsolidity/AST.h> -#include <libsolidity/ExpressionCompiler.h> -#include <libsolidity/CompilerUtils.h> +#include <libsolidity/ast/AST.h> +#include <libsolidity/codegen/ExpressionCompiler.h> +#include <libsolidity/codegen/CompilerUtils.h> using namespace std; using namespace dev; @@ -606,7 +606,11 @@ bool Compiler::visit(Return const& _return) for (auto const& retVariable: returnParameters) types.push_back(retVariable->annotation().type); - TypePointer expectedType = types.size() == 1 ? types.front() : make_shared<TupleType>(types); + TypePointer expectedType; + if (expression->annotation().type->category() == Type::Category::Tuple || types.size() != 1) + expectedType = make_shared<TupleType>(types); + else + expectedType = types.front(); compileExpression(*expression, expectedType); for (auto const& retVariable: boost::adaptors::reverse(returnParameters)) diff --git a/libsolidity/Compiler.h b/libsolidity/codegen/Compiler.h index 3cf1004a..14314434 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/codegen/Compiler.h @@ -24,8 +24,8 @@ #include <ostream> #include <functional> -#include <libsolidity/ASTVisitor.h> -#include <libsolidity/CompilerContext.h> +#include <libsolidity/ast/ASTVisitor.h> +#include <libsolidity/codegen/CompilerContext.h> #include <libevmasm/Assembly.h> namespace dev { diff --git a/libsolidity/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 0ba7af5b..00b9d87c 100644 --- a/libsolidity/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -20,12 +20,12 @@ * Utilities for the solidity compiler. */ -#include <libsolidity/CompilerContext.h> +#include <libsolidity/codegen/CompilerContext.h> #include <utility> #include <numeric> -#include <libsolidity/AST.h> -#include <libsolidity/Compiler.h> -#include <libsolidity/Version.h> +#include <libsolidity/ast/AST.h> +#include <libsolidity/codegen/Compiler.h> +#include <libsolidity/interface/Version.h> using namespace std; diff --git a/libsolidity/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index 18865091..5287088a 100644 --- a/libsolidity/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -27,9 +27,9 @@ #include <utility> #include <libevmcore/Instruction.h> #include <libevmasm/Assembly.h> -#include <libsolidity/ASTForward.h> -#include <libsolidity/Types.h> -#include <libsolidity/ASTAnnotations.h> +#include <libsolidity/ast/ASTForward.h> +#include <libsolidity/ast/Types.h> +#include <libsolidity/ast/ASTAnnotations.h> #include <libdevcore/Common.h> namespace dev { diff --git a/libsolidity/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index f0dea708..dd38ef97 100644 --- a/libsolidity/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -20,12 +20,12 @@ * Routines used by both the compiler and the expression compiler. */ -#include <libsolidity/CompilerUtils.h> -#include <libsolidity/AST.h> +#include <libsolidity/codegen/CompilerUtils.h> +#include <libsolidity/ast/AST.h> #include <libevmcore/Instruction.h> #include <libevmcore/Params.h> -#include <libsolidity/ArrayUtils.h> -#include <libsolidity/LValue.h> +#include <libsolidity/codegen/ArrayUtils.h> +#include <libsolidity/codegen/LValue.h> using namespace std; @@ -598,7 +598,7 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp } // Value grew if (targetSize > sourceSize) - moveIntoStack(depth + targetSize - sourceSize, targetSize - sourceSize); + moveIntoStack(depth + targetSize - sourceSize - 1, targetSize - sourceSize); } } depth -= sourceSize; diff --git a/libsolidity/CompilerUtils.h b/libsolidity/codegen/CompilerUtils.h index 01b9f422..6292e5c7 100644 --- a/libsolidity/CompilerUtils.h +++ b/libsolidity/codegen/CompilerUtils.h @@ -22,8 +22,8 @@ #pragma once -#include <libsolidity/CompilerContext.h> -#include <libsolidity/ASTForward.h> +#include <libsolidity/codegen/CompilerContext.h> +#include <libsolidity/ast/ASTForward.h> namespace dev { namespace solidity { diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 112521f9..3774e731 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -26,11 +26,11 @@ #include <libevmcore/Params.h> #include <libdevcore/Common.h> #include <libdevcore/SHA3.h> -#include <libsolidity/AST.h> -#include <libsolidity/ExpressionCompiler.h> -#include <libsolidity/CompilerContext.h> -#include <libsolidity/CompilerUtils.h> -#include <libsolidity/LValue.h> +#include <libsolidity/ast/AST.h> +#include <libsolidity/codegen/ExpressionCompiler.h> +#include <libsolidity/codegen/CompilerContext.h> +#include <libsolidity/codegen/CompilerUtils.h> +#include <libsolidity/codegen/LValue.h> using namespace std; diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/codegen/ExpressionCompiler.h index 44d27ea2..379aa65a 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/codegen/ExpressionCompiler.h @@ -26,9 +26,9 @@ #include <boost/noncopyable.hpp> #include <libdevcore/Common.h> #include <libevmasm/SourceLocation.h> -#include <libsolidity/ASTVisitor.h> -#include <libsolidity/LValue.h> -#include <libsolidity/Utils.h> +#include <libsolidity/ast/ASTVisitor.h> +#include <libsolidity/codegen/LValue.h> +#include <libsolidity/interface/Utils.h> namespace dev { namespace eth diff --git a/libsolidity/LValue.cpp b/libsolidity/codegen/LValue.cpp index ac04ebef..574d42f8 100644 --- a/libsolidity/LValue.cpp +++ b/libsolidity/codegen/LValue.cpp @@ -20,11 +20,11 @@ * LValues for use in the expresison compiler. */ -#include <libsolidity/LValue.h> +#include <libsolidity/codegen/LValue.h> #include <libevmcore/Instruction.h> -#include <libsolidity/Types.h> -#include <libsolidity/AST.h> -#include <libsolidity/CompilerUtils.h> +#include <libsolidity/ast/Types.h> +#include <libsolidity/ast/AST.h> +#include <libsolidity/codegen/CompilerUtils.h> using namespace std; using namespace dev; diff --git a/libsolidity/LValue.h b/libsolidity/codegen/LValue.h index 94c8d3b8..e8c3aa80 100644 --- a/libsolidity/LValue.h +++ b/libsolidity/codegen/LValue.h @@ -25,7 +25,7 @@ #include <memory> #include <vector> #include <libevmasm/SourceLocation.h> -#include <libsolidity/ArrayUtils.h> +#include <libsolidity/codegen/ArrayUtils.h> namespace dev { @@ -204,7 +204,7 @@ public: /// Constructs the LValue assuming that the other LValues are present on the stack. /// Empty unique_ptrs are possible if e.g. some values should be ignored during assignment. TupleObject(CompilerContext& _compilerContext, std::vector<std::unique_ptr<LValue>>&& _lvalues); - virtual unsigned sizeOnStack() const; + virtual unsigned sizeOnStack() const override; virtual void retrieveValue(SourceLocation const& _location, bool _remove = false) const override; virtual void storeValue( Type const& _sourceType, diff --git a/libsolidity/formal/Why3Translator.cpp b/libsolidity/formal/Why3Translator.cpp new file mode 100644 index 00000000..944b1e7b --- /dev/null +++ b/libsolidity/formal/Why3Translator.cpp @@ -0,0 +1,525 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. +*/ +/** + * @author Christian <c@ethdev.com> + * @date 2015 + * Component that translates Solidity code into the why3 programming language. + */ + +#include <libsolidity/formal/Why3Translator.h> + +using namespace std; +using namespace dev; +using namespace dev::solidity; + +bool Why3Translator::process(SourceUnit const& _source) +{ + try + { + m_indentation = 0; + if (!m_result.empty()) + fatalError(_source, "Multiple source units not yet supported"); + appendPreface(); + _source.accept(*this); + addLine("end"); + } + catch (FatalError& _e) + { + solAssert(m_errorOccured, ""); + } + return !m_errorOccured; +} + +void Why3Translator::error(ASTNode const& _node, string const& _description) +{ + auto err = make_shared<Error>(Error::Type::Why3TranslatorError); + *err << + errinfo_sourceLocation(_node.location()) << + errinfo_comment(_description); + m_errors.push_back(err); + m_errorOccured = true; +} + +void Why3Translator::fatalError(ASTNode const& _node, string const& _description) +{ + error(_node, _description); + BOOST_THROW_EXCEPTION(FatalError()); +} + +void Why3Translator::appendPreface() +{ + m_result += R"( +module UInt256 + use import mach.int.Unsigned + type uint256 + constant max_uint256: int = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + clone export mach.int.Unsigned with + type t = uint256, + constant max = max_uint256 +end + +module Solidity +use import int.Int +use import ref.Ref +use import map.Map +use import array.Array +use import int.ComputerDivision +use import mach.int.Unsigned +use import UInt256 + +exception Ret +type state = StateUnused +)"; +} + +string Why3Translator::toFormalType(Type const& _type) const +{ + if (auto type = dynamic_cast<IntegerType const*>(&_type)) + { + if (!type->isAddress() && !type->isSigned() && type->numBits() == 256) + return "uint256"; + } + else if (auto type = dynamic_cast<ArrayType const*>(&_type)) + if (!type->isByteArray() && type->isDynamicallySized() && type->dataStoredIn(DataLocation::Memory)) + { + string base = toFormalType(*type->baseType()); + if (!base.empty()) + return "array " + base; + } + + return ""; +} + +void Why3Translator::addLine(string const& _line) +{ + newLine(); + add(_line); + newLine(); +} + +void Why3Translator::add(string const& _str) +{ + m_currentLine += _str; +} + +void Why3Translator::newLine() +{ + if (!m_currentLine.empty()) + { + for (size_t i = 0; i < m_indentation; ++i) + m_result.push_back('\t'); + m_result += m_currentLine; + m_result.push_back('\n'); + m_currentLine.clear(); + } +} + +void Why3Translator::unindent() +{ + solAssert(m_indentation > 0, ""); + m_indentation--; +} + +bool Why3Translator::visit(ContractDefinition const& _contract) +{ + if (m_seenContract) + error(_contract, "More than one contract not supported."); + m_seenContract = true; + if (_contract.isLibrary()) + error(_contract, "Libraries not supported."); + + addSourceFromDocStrings(_contract.annotation()); + + return true; +} + +bool Why3Translator::visit(FunctionDefinition const& _function) +{ + if (!_function.isImplemented()) + { + error(_function, "Unimplemented functions not supported."); + return false; + } + if (_function.name().empty()) + { + error(_function, "Fallback functions not supported."); + return false; + } + if (!_function.modifiers().empty()) + { + error(_function, "Modifiers not supported."); + return false; + } + + add("let rec _" + _function.name()); + add(" (state: state)"); + for (auto const& param: _function.parameters()) + { + string paramType = toFormalType(*param->annotation().type); + if (paramType.empty()) + error(*param, "Parameter type not supported."); + if (param->name().empty()) + error(*param, "Anonymous function parameters not supported."); + add(" (arg_" + param->name() + ": " + paramType + ")"); + } + add(":"); + newLine(); + + indent(); + indent(); + string retString = "("; + for (auto const& retParam: _function.returnParameters()) + { + string paramType = toFormalType(*retParam->annotation().type); + if (paramType.empty()) + error(*retParam, "Parameter type not supported."); + if (retString.size() != 1) + retString += ", "; + retString += paramType; + } + addLine(retString + ")"); + unindent(); + + addSourceFromDocStrings(_function.annotation()); + + addLine("="); + + // initialise local variables + for (auto const& variable: _function.parameters()) + addLine("let _" + variable->name() + " = ref arg_" + variable->name() + " in"); + for (auto const& variable: _function.returnParameters()) + { + if (variable->name().empty()) + error(*variable, "Unnamed return variables not yet supported."); + string varType = toFormalType(*variable->annotation().type); + addLine("let _" + variable->name() + ": ref " + varType + " = ref (of_int 0) in"); + } + for (VariableDeclaration const* variable: _function.localVariables()) + { + if (variable->name().empty()) + error(*variable, "Unnamed variables not yet supported."); + string varType = toFormalType(*variable->annotation().type); + addLine("let _" + variable->name() + ": ref " + varType + " = ref (of_int 0) in"); + } + addLine("try"); + + _function.body().accept(*this); + addLine("raise Ret"); + + string retVals; + for (auto const& variable: _function.returnParameters()) + { + if (!retVals.empty()) + retVals += ", "; + retVals += "!_" + variable->name(); + } + addLine("with Ret -> (" + retVals + ")"); + newLine(); + unindent(); + addLine("end"); + addLine(""); + return false; +} + +bool Why3Translator::visit(Block const& _node) +{ + addSourceFromDocStrings(_node.annotation()); + addLine("begin"); + indent(); + return true; +} + +bool Why3Translator::visit(IfStatement const& _node) +{ + addSourceFromDocStrings(_node.annotation()); + + add("if "); + _node.condition().accept(*this); + add(" then"); + newLine(); + _node.trueStatement().accept(*this); + if (_node.falseStatement()) + { + addLine("else"); + _node.falseStatement()->accept(*this); + } + return false; +} + +bool Why3Translator::visit(WhileStatement const& _node) +{ + addSourceFromDocStrings(_node.annotation()); + + add("while "); + _node.condition().accept(*this); + add(" do"); + newLine(); + _node.body().accept(*this); + addLine("done;"); + return false; +} + +bool Why3Translator::visit(Return const& _node) +{ + addSourceFromDocStrings(_node.annotation()); + + if (_node.expression()) + { + solAssert(!!_node.annotation().functionReturnParameters, ""); + auto const& params = _node.annotation().functionReturnParameters->parameters(); + if (params.size() != 1) + { + error(_node, "Directly returning tuples not supported. Rather assign to return variable."); + return false; + } + newLine(); + add("begin _" + params.front()->name() + " := "); + _node.expression()->accept(*this); + add("; raise Ret end"); + newLine(); + } + else + addLine("raise Ret;"); + return false; +} + +bool Why3Translator::visit(VariableDeclarationStatement const& _node) +{ + addSourceFromDocStrings(_node.annotation()); + + if (_node.declarations().size() != 1) + { + error(_node, "Multiple variables not supported."); + return false; + } + if (_node.initialValue()) + { + add("_" + _node.declarations().front()->name() + " := "); + _node.initialValue()->accept(*this); + add(";"); + newLine(); + } + return false; +} + +bool Why3Translator::visit(ExpressionStatement const& _node) +{ + addSourceFromDocStrings(_node.annotation()); + return true; +} + +bool Why3Translator::visit(Assignment const& _node) +{ + if (_node.assignmentOperator() != Token::Assign) + error(_node, "Compound assignment not supported."); + + _node.leftHandSide().accept(*this); + add(" := "); + _node.rightHandSide().accept(*this); + + return false; +} + +bool Why3Translator::visit(TupleExpression const& _node) +{ + if (_node.components().size() != 1) + error(_node, "Only tuples with exactly one component supported."); + add("("); + return true; +} + +bool Why3Translator::visit(UnaryOperation const& _unaryOperation) +{ + if (toFormalType(*_unaryOperation.annotation().type).empty()) + error(_unaryOperation, "Type not supported."); + + switch (_unaryOperation.getOperator()) + { + case Token::Not: // ! + add("(not "); + break; + default: + error(_unaryOperation, "Operator not supported."); + break; + } + + _unaryOperation.subExpression().accept(*this); + add(")"); + + return false; +} + +bool Why3Translator::visit(BinaryOperation const& _binaryOperation) +{ + Expression const& leftExpression = _binaryOperation.leftExpression(); + Expression const& rightExpression = _binaryOperation.rightExpression(); + solAssert(!!_binaryOperation.annotation().commonType, ""); + Type const& commonType = *_binaryOperation.annotation().commonType; + Token::Value const c_op = _binaryOperation.getOperator(); + + if (commonType.category() == Type::Category::IntegerConstant) + { + add("(of_int " + toString(commonType.literalValue(nullptr)) + ")"); + return false; + } + static const map<Token::Value, char const*> optrans({ + {Token::And, " && "}, + {Token::Or, " || "}, + {Token::BitOr, " lor "}, + {Token::BitXor, " lxor "}, + {Token::BitAnd, " land "}, + {Token::Add, " + "}, + {Token::Sub, " - "}, + {Token::Mul, " * "}, + {Token::Div, " / "}, + {Token::Mod, " mod "}, + {Token::Equal, " = "}, + {Token::NotEqual, " <> "}, + {Token::LessThan, " < "}, + {Token::GreaterThan, " > "}, + {Token::LessThanOrEqual, " <= "}, + {Token::GreaterThanOrEqual, " >= "} + }); + if (!optrans.count(c_op)) + error(_binaryOperation, "Operator not supported."); + + add("("); + leftExpression.accept(*this); + add(optrans.at(c_op)); + rightExpression.accept(*this); + add(")"); + + return false; +} + +bool Why3Translator::visit(FunctionCall const& _node) +{ + if (_node.annotation().isTypeConversion || _node.annotation().isStructConstructorCall) + { + error(_node, "Only ordinary function calls supported."); + return true; + } + FunctionType const& function = dynamic_cast<FunctionType const&>(*_node.expression().annotation().type); + if (function.location() != FunctionType::Location::Internal) + { + error(_node, "Only internal function calls supported."); + return true; + } + if (!_node.names().empty()) + { + error(_node, "Function calls with named arguments not supported."); + return true; + } + + //@TODO check type conversions + + add("("); + _node.expression().accept(*this); + add(" StateUnused"); + for (auto const& arg: _node.arguments()) + { + add(" "); + arg->accept(*this); + } + add(")"); + return false; +} + +bool Why3Translator::visit(MemberAccess const& _node) +{ + if ( + _node.expression().annotation().type->category() == Type::Category::Array && + _node.memberName() == "length" && + !_node.annotation().lValueRequested + ) + { + add("(of_int "); + _node.expression().accept(*this); + add(".length"); + add(")"); + } + else + error(_node, "Only read-only length access for arrays supported."); + return false; +} + +bool Why3Translator::visit(IndexAccess const& _node) +{ + auto baseType = dynamic_cast<ArrayType const*>(_node.baseExpression().annotation().type.get()); + if (!baseType) + { + error(_node, "Index access only supported for arrays."); + return true; + } + if (_node.annotation().lValueRequested) + { + error(_node, "Assignment to array elements not supported."); + return true; + } + add("("); + _node.baseExpression().accept(*this); + add("[to_int "); + _node.indexExpression()->accept(*this); + add("]"); + add(")"); + + return false; +} + +bool Why3Translator::visit(Identifier const& _identifier) +{ + Declaration const* declaration = _identifier.annotation().referencedDeclaration; + if (FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(declaration)) + add("_" + functionDef->name()); + else if (auto variable = dynamic_cast<VariableDeclaration const*>(declaration)) + { + if (_identifier.annotation().lValueRequested) + add("_" + variable->name()); + else + add("!_" + variable->name()); + } + else + error(_identifier, "Not supported."); + return false; +} + +bool Why3Translator::visit(Literal const& _literal) +{ + TypePointer type = _literal.annotation().type; + switch (type->category()) + { + case Type::Category::Bool: + if (type->literalValue(&_literal) == 0) + add("false"); + else + add("true"); + break; + case Type::Category::IntegerConstant: + add("(of_int " + toString(type->literalValue(&_literal)) + ")"); + break; + default: + error(_literal, "Not supported."); + } + return false; +} + +void Why3Translator::addSourceFromDocStrings(const DocumentedAnnotation& _annotation) +{ + auto why3Range = _annotation.docTags.equal_range("why3"); + for (auto i = why3Range.first; i != why3Range.second; ++i) + addLine(i->second.content); +} diff --git a/libsolidity/formal/Why3Translator.h b/libsolidity/formal/Why3Translator.h new file mode 100644 index 00000000..21ead977 --- /dev/null +++ b/libsolidity/formal/Why3Translator.h @@ -0,0 +1,115 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. +*/ +/** + * @author Christian <c@ethdev.com> + * @date 2015 + * Component that translates Solidity code into the why3 programming language. + */ + +#pragma once + +#include <libsolidity/ast/ASTVisitor.h> +#include <libsolidity/interface/Exceptions.h> +#include <string> + +namespace dev +{ +namespace solidity +{ + +class SourceUnit; + +/** + * Simple translator from Solidity to Why3. + * + * @todo detect side effects in sub-expressions and limit them to one per statement. + * @todo `x = y = z` + * @todo implicit and explicit type conversion + */ +class Why3Translator: private ASTConstVisitor +{ +public: + Why3Translator(ErrorList& _errors): m_errors(_errors) {} + + /// Appends formalisation of the given source unit to the output. + /// @returns false on error. + bool process(SourceUnit const& _source); + + std::string translation() const { return m_result; } + +private: + /// Returns an error. + void error(ASTNode const& _node, std::string const& _description); + /// Reports a fatal error and throws. + void fatalError(ASTNode const& _node, std::string const& _description); + + /// Appends imports and constants use throughout the formal code. + void appendPreface(); + + /// @returns a string representation of the corresponding formal type or the empty string + /// if the type is not supported. + std::string toFormalType(Type const& _type) const; + + void indent() { m_indentation++; } + void unindent(); + void addLine(std::string const& _line); + void add(std::string const& _str); + void newLine(); + + virtual bool visit(SourceUnit const&) override { return true; } + virtual bool visit(ContractDefinition const& _contract) override; + virtual bool visit(FunctionDefinition const& _function) override; + virtual bool visit(Block const&) override; + virtual void endVisit(Block const&) override { unindent(); addLine("end;"); } + virtual bool visit(IfStatement const& _node) override; + virtual bool visit(WhileStatement const& _node) override; + virtual bool visit(Return const& _node) override; + virtual bool visit(VariableDeclarationStatement const& _node) override; + virtual bool visit(ExpressionStatement const&) override; + virtual void endVisit(ExpressionStatement const&) override { add(";"); newLine(); } + virtual bool visit(Assignment const& _node) override; + virtual bool visit(TupleExpression const& _node) override; + virtual void endVisit(TupleExpression const&) override { add(")"); } + virtual bool visit(UnaryOperation const& _node) override; + virtual bool visit(BinaryOperation const& _node) override; + virtual bool visit(FunctionCall const& _node) override; + virtual bool visit(MemberAccess const& _node) override; + virtual bool visit(IndexAccess const& _node) override; + virtual bool visit(Identifier const& _node) override; + virtual bool visit(Literal const& _node) override; + + virtual bool visitNode(ASTNode const& _node) override + { + error(_node, "Code not supported for formal verification."); + return false; + } + + void addSourceFromDocStrings(DocumentedAnnotation const& _annotation); + + size_t m_indentation = 0; + std::string m_currentLine; + /// True if we have already seen a contract. For now, only a single contract + /// is supported. + bool m_seenContract = false; + bool m_errorOccured = false; + std::string m_result; + ErrorList& m_errors; +}; + + +} +} diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 03120f66..18eec0a2 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -22,15 +22,17 @@ */ #include <boost/algorithm/string.hpp> -#include <libsolidity/AST.h> -#include <libsolidity/Scanner.h> -#include <libsolidity/Parser.h> -#include <libsolidity/GlobalContext.h> -#include <libsolidity/NameAndTypeResolver.h> -#include <libsolidity/TypeChecker.h> -#include <libsolidity/Compiler.h> -#include <libsolidity/CompilerStack.h> -#include <libsolidity/InterfaceHandler.h> +#include <libsolidity/ast/AST.h> +#include <libsolidity/parsing/Scanner.h> +#include <libsolidity/parsing/Parser.h> +#include <libsolidity/analysis/GlobalContext.h> +#include <libsolidity/analysis/NameAndTypeResolver.h> +#include <libsolidity/analysis/TypeChecker.h> +#include <libsolidity/analysis/DocStringAnalyser.h> +#include <libsolidity/codegen/Compiler.h> +#include <libsolidity/interface/CompilerStack.h> +#include <libsolidity/interface/InterfaceHandler.h> +#include <libsolidity/formal/Why3Translator.h> #include <libdevcore/SHA3.h> @@ -114,6 +116,12 @@ bool CompilerStack::parse() resolveImports(); + bool noErrors = true; + DocStringAnalyser docStringAnalyser(m_errors); + for (Source const* source: m_sourceOrder) + if (!docStringAnalyser.analyseDocStrings(*source->ast)) + noErrors = false; + m_globalContext = make_shared<GlobalContext>(); NameAndTypeResolver resolver(m_globalContext->declarations(), m_errors); for (Source const* source: m_sourceOrder) @@ -131,8 +139,6 @@ bool CompilerStack::parse() m_contracts[contract->name()].contract = contract; } - InterfaceHandler interfaceHandler; - bool typesFine = true; for (Source const* source: m_sourceOrder) for (ASTPointer<ASTNode> const& node: source->ast->nodes()) if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get())) @@ -142,15 +148,15 @@ bool CompilerStack::parse() TypeChecker typeChecker(m_errors); if (typeChecker.checkTypeRequirements(*contract)) { - contract->setDevDocumentation(interfaceHandler.devDocumentation(*contract)); - contract->setUserDocumentation(interfaceHandler.userDocumentation(*contract)); + contract->setDevDocumentation(InterfaceHandler::devDocumentation(*contract)); + contract->setUserDocumentation(InterfaceHandler::userDocumentation(*contract)); } else - typesFine = false; + noErrors = false; m_contracts[contract->name()].contract = contract; } - m_parseSuccessful = typesFine; + m_parseSuccessful = noErrors; return m_parseSuccessful; } @@ -200,6 +206,18 @@ void CompilerStack::link(const std::map<string, h160>& _libraries) } } +bool CompilerStack::prepareFormalAnalysis() +{ + Why3Translator translator(m_errors); + for (Source const* source: m_sourceOrder) + if (!translator.process(*source->ast)) + return false; + + m_formalTranslation = translator.translation(); + + return true; +} + eth::AssemblyItems const* CompilerStack::assemblyItems(string const& _contractName) const { Contract const& currentContract = contract(_contractName); @@ -287,7 +305,7 @@ string const& CompilerStack::metadata(string const& _contractName, Documentation // caches the result if (!*doc) - doc->reset(new string(currentContract.interfaceHandler->documentation(*currentContract.contract, _type))); + doc->reset(new string(InterfaceHandler::documentation(*currentContract.contract, _type))); return *(*doc); } @@ -428,8 +446,5 @@ CompilerStack::Source const& CompilerStack::source(string const& _sourceName) co return it->second; } -CompilerStack::Contract::Contract(): interfaceHandler(make_shared<InterfaceHandler>()) {} - - } } diff --git a/libsolidity/CompilerStack.h b/libsolidity/interface/CompilerStack.h index de548bee..0473d58b 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -33,7 +33,7 @@ #include <libdevcore/FixedHash.h> #include <libevmasm/SourceLocation.h> #include <libevmasm/LinkerObject.h> -#include <libsolidity/Exceptions.h> +#include <libsolidity/interface/Exceptions.h> namespace dev { @@ -108,6 +108,11 @@ public: /// Inserts the given addresses into the linker objects of all compiled contracts. void link(std::map<std::string, h160> const& _libraries); + /// Tries to translate all source files into a language suitable for formal analysis. + /// @returns false on error. + bool prepareFormalAnalysis(); + std::string const& formalTranslation() const { return m_formalTranslation; } + /// @returns the assembled object for a contract. eth::LinkerObject const& object(std::string const& _contractName = "") const; /// @returns the runtime object for the contract. @@ -167,7 +172,6 @@ public: /// @returns the list of errors that occured during parsing and type checking. ErrorList const& errors() const { return m_errors; } - private: /** * Information pertaining to one source unit, filled gradually during parsing and compilation. @@ -188,13 +192,10 @@ private: eth::LinkerObject object; eth::LinkerObject runtimeObject; eth::LinkerObject cloneObject; - std::shared_ptr<InterfaceHandler> interfaceHandler; mutable std::unique_ptr<std::string const> interface; mutable std::unique_ptr<std::string const> solidityInterface; mutable std::unique_ptr<std::string const> userDocumentation; mutable std::unique_ptr<std::string const> devDocumentation; - - Contract(); }; void resolveImports(); @@ -214,6 +215,7 @@ private: std::shared_ptr<GlobalContext> m_globalContext; std::vector<Source const*> m_sourceOrder; std::map<std::string const, Contract> m_contracts; + std::string m_formalTranslation; ErrorList m_errors; }; diff --git a/libsolidity/Exceptions.cpp b/libsolidity/interface/Exceptions.cpp index 96bb2e37..465c3d2f 100644 --- a/libsolidity/Exceptions.cpp +++ b/libsolidity/interface/Exceptions.cpp @@ -20,8 +20,8 @@ * Solidity exception hierarchy. */ -#include <libsolidity/Exceptions.h> -#include <libsolidity/Utils.h> +#include <libsolidity/interface/Exceptions.h> +#include <libsolidity/interface/Utils.h> using namespace dev; using namespace dev::solidity; @@ -30,23 +30,26 @@ Error::Error(Type _type): m_type(_type) { switch(m_type) { - case Type::DeclarationError: - m_typeName = "Declaration Error"; - break; - case Type::DocstringParsingError: - m_typeName = "Docstring Parsing Error"; - break; - case Type::ParserError: - m_typeName = "Parser Error"; - break; - case Type::TypeError: - m_typeName = "Type Error"; - break; - case Type::Warning: - m_typeName = "Warning"; - break; - default: - solAssert(false, ""); - break; + case Type::DeclarationError: + m_typeName = "Declaration Error"; + break; + case Type::DocstringParsingError: + m_typeName = "Docstring Parsing Error"; + break; + case Type::ParserError: + m_typeName = "Parser Error"; + break; + case Type::TypeError: + m_typeName = "Type Error"; + break; + case Type::Why3TranslatorError: + m_typeName = "Why3 Translator Error"; + break; + case Type::Warning: + m_typeName = "Warning"; + break; + default: + solAssert(false, ""); + break; } } diff --git a/libsolidity/Exceptions.h b/libsolidity/interface/Exceptions.h index cda6b97e..14be3c3d 100644 --- a/libsolidity/Exceptions.h +++ b/libsolidity/interface/Exceptions.h @@ -47,6 +47,7 @@ public: DocstringParsingError, ParserError, TypeError, + Why3TranslatorError, Warning }; diff --git a/libsolidity/GasEstimator.cpp b/libsolidity/interface/GasEstimator.cpp index d576561a..d460ba76 100644 --- a/libsolidity/GasEstimator.cpp +++ b/libsolidity/interface/GasEstimator.cpp @@ -28,9 +28,9 @@ #include <libevmasm/ControlFlowGraph.h> #include <libevmasm/KnownState.h> #include <libevmasm/PathGasMeter.h> -#include <libsolidity/AST.h> -#include <libsolidity/ASTVisitor.h> -#include <libsolidity/CompilerUtils.h> +#include <libsolidity/ast/AST.h> +#include <libsolidity/ast/ASTVisitor.h> +#include <libsolidity/codegen/CompilerUtils.h> using namespace std; using namespace dev; diff --git a/libsolidity/GasEstimator.h b/libsolidity/interface/GasEstimator.h index 4020d60b..518e58e4 100644 --- a/libsolidity/GasEstimator.h +++ b/libsolidity/interface/GasEstimator.h @@ -25,7 +25,6 @@ #include <vector> #include <map> #include <array> -#include <libsolidity/ASTForward.h> #include <libevmasm/GasMeter.h> #include <libevmasm/Assembly.h> @@ -34,6 +33,9 @@ namespace dev namespace solidity { +class ASTNode; +class FunctionDefinition; + struct GasEstimator { public: diff --git a/libsolidity/interface/InterfaceHandler.cpp b/libsolidity/interface/InterfaceHandler.cpp new file mode 100644 index 00000000..30cd9724 --- /dev/null +++ b/libsolidity/interface/InterfaceHandler.cpp @@ -0,0 +1,248 @@ + +#include <libsolidity/interface/InterfaceHandler.h> +#include <boost/range/irange.hpp> +#include <libsolidity/ast/AST.h> +#include <libsolidity/interface/CompilerStack.h> + +using namespace std; +using namespace dev; +using namespace dev::solidity; + +string InterfaceHandler::documentation( + ContractDefinition const& _contractDef, + DocumentationType _type +) +{ + switch(_type) + { + case DocumentationType::NatspecUser: + return userDocumentation(_contractDef); + case DocumentationType::NatspecDev: + return devDocumentation(_contractDef); + case DocumentationType::ABIInterface: + return abiInterface(_contractDef); + case DocumentationType::ABISolidityInterface: + return ABISolidityInterface(_contractDef); + } + + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown documentation type")); + return ""; +} + +string InterfaceHandler::abiInterface(ContractDefinition const& _contractDef) +{ + Json::Value abi(Json::arrayValue); + + auto populateParameters = [](vector<string> const& _paramNames, vector<string> const& _paramTypes) + { + Json::Value params(Json::arrayValue); + solAssert(_paramNames.size() == _paramTypes.size(), "Names and types vector size does not match"); + for (unsigned i = 0; i < _paramNames.size(); ++i) + { + Json::Value param; + param["name"] = _paramNames[i]; + param["type"] = _paramTypes[i]; + params.append(param); + } + return params; + }; + + for (auto it: _contractDef.interfaceFunctions()) + { + auto externalFunctionType = it.second->interfaceFunctionType(); + Json::Value method; + method["type"] = "function"; + method["name"] = it.second->declaration().name(); + method["constant"] = it.second->isConstant(); + method["inputs"] = populateParameters( + externalFunctionType->parameterNames(), + externalFunctionType->parameterTypeNames(_contractDef.isLibrary()) + ); + method["outputs"] = populateParameters( + externalFunctionType->returnParameterNames(), + externalFunctionType->returnParameterTypeNames(_contractDef.isLibrary()) + ); + abi.append(method); + } + if (_contractDef.constructor()) + { + Json::Value method; + method["type"] = "constructor"; + auto externalFunction = FunctionType(*_contractDef.constructor()).interfaceFunctionType(); + solAssert(!!externalFunction, ""); + method["inputs"] = populateParameters( + externalFunction->parameterNames(), + externalFunction->parameterTypeNames(_contractDef.isLibrary()) + ); + abi.append(method); + } + + for (auto const& it: _contractDef.interfaceEvents()) + { + Json::Value event; + event["type"] = "event"; + event["name"] = it->name(); + event["anonymous"] = it->isAnonymous(); + Json::Value params(Json::arrayValue); + for (auto const& p: it->parameters()) + { + Json::Value input; + input["name"] = p->name(); + input["type"] = p->annotation().type->canonicalName(false); + input["indexed"] = p->isIndexed(); + params.append(input); + } + event["inputs"] = params; + abi.append(event); + } + return Json::FastWriter().write(abi); +} + +string InterfaceHandler::ABISolidityInterface(ContractDefinition const& _contractDef) +{ + string ret = (_contractDef.isLibrary() ? "library " : "contract ") + _contractDef.name() + "{"; + + auto populateParameters = [](vector<string> const& _paramNames, vector<string> const& _paramTypes) + { + string ret = "("; + for (size_t i = 0; i < _paramNames.size(); ++i) + ret += _paramTypes[i] + " " + _paramNames[i] + ","; + if (ret.size() != 1) + ret.pop_back(); + return ret + ")"; + }; + // If this is a library, include all its enum and struct types. Should be more intelligent + // in the future and check what is actually used (it might even use types from other libraries + // or contracts or in the global scope). + if (_contractDef.isLibrary()) + { + for (auto const& stru: _contractDef.definedStructs()) + { + ret += "struct " + stru->name() + "{"; + for (ASTPointer<VariableDeclaration> const& _member: stru->members()) + ret += _member->type(nullptr)->canonicalName(false) + " " + _member->name() + ";"; + ret += "}"; + } + for (auto const& enu: _contractDef.definedEnums()) + { + ret += "enum " + enu->name() + "{"; + for (ASTPointer<EnumValue> const& val: enu->members()) + ret += val->name() + ","; + if (ret.back() == ',') + ret.pop_back(); + ret += "}"; + } + } + if (_contractDef.constructor()) + { + auto externalFunction = FunctionType(*_contractDef.constructor()).interfaceFunctionType(); + solAssert(!!externalFunction, ""); + ret += + "function " + + _contractDef.name() + + populateParameters( + externalFunction->parameterNames(), + externalFunction->parameterTypeNames(_contractDef.isLibrary()) + ) + + ";"; + } + for (auto const& it: _contractDef.interfaceFunctions()) + { + ret += "function " + it.second->declaration().name() + + populateParameters( + it.second->parameterNames(), + it.second->parameterTypeNames(_contractDef.isLibrary()) + ) + (it.second->isConstant() ? "constant " : ""); + if (it.second->returnParameterTypes().size()) + ret += "returns" + populateParameters( + it.second->returnParameterNames(), + it.second->returnParameterTypeNames(_contractDef.isLibrary()) + ); + else if (ret.back() == ' ') + ret.pop_back(); + ret += ";"; + } + + return ret + "}"; +} + +string InterfaceHandler::userDocumentation(ContractDefinition const& _contractDef) +{ + Json::Value doc; + Json::Value methods(Json::objectValue); + + for (auto const& it: _contractDef.interfaceFunctions()) + if (it.second->hasDeclaration()) + if (auto const* f = dynamic_cast<FunctionDefinition const*>(&it.second->declaration())) + { + string value = extractDoc(f->annotation().docTags, "notice"); + if (!value.empty()) + { + Json::Value user; + // since @notice is the only user tag if missing function should not appear + user["notice"] = Json::Value(value); + methods[it.second->externalSignature()] = user; + } + } + doc["methods"] = methods; + + return Json::StyledWriter().write(doc); +} + +string InterfaceHandler::devDocumentation(ContractDefinition const& _contractDef) +{ + Json::Value doc; + Json::Value methods(Json::objectValue); + + auto author = extractDoc(_contractDef.annotation().docTags, "author"); + if (!author.empty()) + doc["author"] = author; + auto title = extractDoc(_contractDef.annotation().docTags, "title"); + if (!title.empty()) + doc["title"] = title; + + for (auto const& it: _contractDef.interfaceFunctions()) + { + if (!it.second->hasDeclaration()) + continue; + Json::Value method; + if (auto fun = dynamic_cast<FunctionDefinition const*>(&it.second->declaration())) + { + auto dev = extractDoc(fun->annotation().docTags, "dev"); + if (!dev.empty()) + method["details"] = Json::Value(dev); + + auto author = extractDoc(fun->annotation().docTags, "author"); + if (!author.empty()) + method["author"] = author; + + auto ret = extractDoc(fun->annotation().docTags, "return"); + if (!ret.empty()) + method["return"] = ret; + + Json::Value params(Json::objectValue); + auto paramRange = fun->annotation().docTags.equal_range("param"); + for (auto i = paramRange.first; i != paramRange.second; ++i) + params[i->second.paramName] = Json::Value(i->second.content); + + if (!params.empty()) + method["params"] = params; + + if (!method.empty()) + // add the function, only if we have any documentation to add + methods[it.second->externalSignature()] = method; + } + } + doc["methods"] = methods; + + return Json::StyledWriter().write(doc); +} + +string InterfaceHandler::extractDoc(multimap<string, DocTag> const& _tags, string const& _name) +{ + string value; + auto range = _tags.equal_range(_name); + for (auto i = range.first; i != range.second; i++) + value += i->second.content; + return value; +} diff --git a/libsolidity/InterfaceHandler.h b/libsolidity/interface/InterfaceHandler.h index 62164517..30b8f520 100644 --- a/libsolidity/InterfaceHandler.h +++ b/libsolidity/interface/InterfaceHandler.h @@ -37,6 +37,7 @@ namespace solidity // Forward declarations class ContractDefinition; +struct DocTag; enum class DocumentationType: uint8_t; enum class DocTagType: uint8_t @@ -59,73 +60,33 @@ enum class CommentOwner 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 DocumentationType /// @return A string with the json representation of provided type - std::string documentation( + static std::string documentation( ContractDefinition const& _contractDef, DocumentationType _type ); /// Get the ABI Interface of the contract /// @param _contractDef The contract definition /// @return A string with the json representation of the contract's ABI Interface - std::string abiInterface(ContractDefinition const& _contractDef); - std::string ABISolidityInterface(ContractDefinition const& _contractDef); + static std::string abiInterface(ContractDefinition const& _contractDef); + static std::string ABISolidityInterface(ContractDefinition const& _contractDef); /// Get the User documentation of the contract /// @param _contractDef The contract definition /// @return A string with the json representation of the contract's user documentation - std::string userDocumentation(ContractDefinition const& _contractDef); + static std::string userDocumentation(ContractDefinition const& _contractDef); /// Genereates the Developer's documentation of the contract /// @param _contractDef The contract definition /// @return A string with the json representation /// of the contract's developer documentation - std::string devDocumentation(ContractDefinition const& _contractDef); + static std::string devDocumentation(ContractDefinition const& _contractDef); private: - void resetUser(); - void resetDev(); - - std::string::const_iterator parseDocTagLine( - std::string::const_iterator _pos, - std::string::const_iterator _end, - std::string& _tagString, - DocTagType _tagType, - bool _appending - ); - 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, CommentOwner _owner); - std::string::const_iterator appendDocTag( - std::string::const_iterator _pos, - std::string::const_iterator _end, - CommentOwner _owner - ); - std::string::const_iterator parseDocTag( - std::string::const_iterator _pos, - std::string::const_iterator _end, - std::string const& _tag, - CommentOwner _owner - ); - - // internal state - DocTagType m_lastTag; - std::string m_notice; - std::string m_dev; - std::string m_return; - std::string m_contractAuthor; - std::string m_author; - std::string m_title; - std::vector<std::pair<std::string, std::string>> m_params; + /// Returns concatenation of all content under the given tag name. + static std::string extractDoc(std::multimap<std::string, DocTag> const& _tags, std::string const& _name); }; } //solidity NS diff --git a/libsolidity/SourceReferenceFormatter.cpp b/libsolidity/interface/SourceReferenceFormatter.cpp index 339d5b23..169e5c18 100644 --- a/libsolidity/SourceReferenceFormatter.cpp +++ b/libsolidity/interface/SourceReferenceFormatter.cpp @@ -20,10 +20,10 @@ * Formatting functions for errors referencing positions and locations in the source. */ -#include <libsolidity/SourceReferenceFormatter.h> -#include <libsolidity/CompilerStack.h> -#include <libsolidity/Scanner.h> -#include <libsolidity/Exceptions.h> +#include <libsolidity/interface/SourceReferenceFormatter.h> +#include <libsolidity/interface/CompilerStack.h> +#include <libsolidity/parsing/Scanner.h> +#include <libsolidity/interface/Exceptions.h> using namespace std; diff --git a/libsolidity/SourceReferenceFormatter.h b/libsolidity/interface/SourceReferenceFormatter.h index dd258c27..dd258c27 100644 --- a/libsolidity/SourceReferenceFormatter.h +++ b/libsolidity/interface/SourceReferenceFormatter.h diff --git a/libsolidity/Utils.h b/libsolidity/interface/Utils.h index 48bb1e47..738669ac 100644 --- a/libsolidity/Utils.h +++ b/libsolidity/interface/Utils.h @@ -23,7 +23,7 @@ #pragma once #include <libdevcore/Assertions.h> -#include <libsolidity/Exceptions.h> +#include <libsolidity/interface/Exceptions.h> namespace dev { diff --git a/libsolidity/Version.cpp b/libsolidity/interface/Version.cpp index 09a6d84b..84a82dbf 100644 --- a/libsolidity/Version.cpp +++ b/libsolidity/interface/Version.cpp @@ -20,12 +20,12 @@ * Versioning. */ -#include <libsolidity/Version.h> +#include <libsolidity/interface/Version.h> #include <string> #include <libdevcore/CommonData.h> #include <libdevcore/Common.h> #include <libevmasm/Version.h> -#include <libsolidity/Utils.h> +#include <libsolidity/interface/Utils.h> #include <solidity/BuildInfo.h> using namespace dev; @@ -65,7 +65,10 @@ bytes dev::solidity::binaryVersion() solAssert(i < VersionString.size() && VersionString[i] == '-', ""); ++i; solAssert(i + 7 < VersionString.size(), ""); - ret += fromHex(VersionString.substr(i, 8)); + bytes commitHash = fromHex(VersionString.substr(i, 8)); + if (commitHash.empty()) + commitHash = bytes(4, 0); + ret += commitHash; solAssert(ret.size() == 1 + 3 + 4, ""); return ret; diff --git a/libsolidity/Version.h b/libsolidity/interface/Version.h index fea73997..fea73997 100644 --- a/libsolidity/Version.h +++ b/libsolidity/interface/Version.h diff --git a/libsolidity/parsing/DocStringParser.cpp b/libsolidity/parsing/DocStringParser.cpp new file mode 100644 index 00000000..bbee35f5 --- /dev/null +++ b/libsolidity/parsing/DocStringParser.cpp @@ -0,0 +1,141 @@ + +#include <libsolidity/parsing/DocStringParser.h> +#include <boost/range/irange.hpp> +#include <libsolidity/interface/Utils.h> + +using namespace std; +using namespace dev; +using namespace dev::solidity; + + +static inline string::const_iterator skipLineOrEOS( + string::const_iterator _nlPos, + string::const_iterator _end +) +{ + return (_nlPos == _end) ? _end : ++_nlPos; +} + +static inline string::const_iterator firstSpaceOrNl( + string::const_iterator _pos, + string::const_iterator _end +) +{ + auto spacePos = find(_pos, _end, ' '); + auto nlPos = find(_pos, _end, '\n'); + return (spacePos < nlPos) ? spacePos : nlPos; +} + +bool DocStringParser::parse(string const& _docString, ErrorList& _errors) +{ + m_errors = &_errors; + m_errorsOccurred = false; + m_lastTag = nullptr; + + auto currPos = _docString.begin(); + auto end = _docString.end(); + + while (currPos != end) + { + auto tagPos = find(currPos, end, '@'); + auto nlPos = find(currPos, end, '\n'); + + if (tagPos != end && tagPos < nlPos) + { + // we found a tag + auto tagNameEndPos = firstSpaceOrNl(tagPos, end); + if (tagNameEndPos == end) + { + appendError("End of tag " + string(tagPos, tagNameEndPos) + "not found"); + break; + } + + currPos = parseDocTag(tagNameEndPos + 1, end, string(tagPos + 1, tagNameEndPos)); + } + else if (!!m_lastTag) // continuation of the previous tag + currPos = appendDocTag(currPos, end); + else if (currPos != end) + { + // if it begins without a tag then consider it as @notice + if (currPos == _docString.begin()) + { + currPos = parseDocTag(currPos, end, "notice"); + continue; + } + else if (nlPos == end) //end of text + break; + // else skip the line if a newline was found and we get here + currPos = nlPos + 1; + } + } + return !m_errorsOccurred; +} + +DocStringParser::iter DocStringParser::parseDocTagLine(iter _pos, iter _end, bool _appending) +{ + solAssert(!!m_lastTag, ""); + auto nlPos = find(_pos, _end, '\n'); + if (_appending && _pos < _end && *_pos != ' ') + m_lastTag->content += " "; + copy(_pos, nlPos, back_inserter(m_lastTag->content)); + return skipLineOrEOS(nlPos, _end); +} + +DocStringParser::iter DocStringParser::parseDocTagParam(iter _pos, iter _end) +{ + // find param name + auto currPos = find(_pos, _end, ' '); + if (currPos == _end) + { + appendError("End of param name not found" + string(_pos, _end)); + return _end; + } + + auto paramName = string(_pos, currPos); + + currPos += 1; + auto nlPos = find(currPos, _end, '\n'); + auto paramDesc = string(currPos, nlPos); + newTag("param"); + m_lastTag->paramName = paramName; + m_lastTag->content = paramDesc; + + return skipLineOrEOS(nlPos, _end); +} + +DocStringParser::iter DocStringParser::parseDocTag(iter _pos, iter _end, string const& _tag) +{ + // LTODO: need to check for @(start of a tag) between here and the end of line + // for all cases. + if (!m_lastTag || _tag != "") + { + if (_tag == "param") + return parseDocTagParam(_pos, _end); + else + { + newTag(_tag); + return parseDocTagLine(_pos, _end, false); + } + } + else + return appendDocTag(_pos, _end); +} + +DocStringParser::iter DocStringParser::appendDocTag(iter _pos, iter _end) +{ + solAssert(!!m_lastTag, ""); + return parseDocTagLine(_pos, _end, true); +} + +void DocStringParser::newTag(string const& _tagName) +{ + m_lastTag = &m_docTags.insert(make_pair(_tagName, DocTag()))->second; +} + +void DocStringParser::appendError(string const& _description) +{ + auto err = make_shared<Error>(Error::Type::DocstringParsingError); + *err << errinfo_comment(_description); + m_errors->push_back(err); + m_errorsOccurred = true; +} diff --git a/libsolidity/parsing/DocStringParser.h b/libsolidity/parsing/DocStringParser.h new file mode 100644 index 00000000..f67b8bbd --- /dev/null +++ b/libsolidity/parsing/DocStringParser.h @@ -0,0 +1,70 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. +*/ +/** + * @author Lefteris <lefteris@ethdev.com> + * @date 2014, 2015 + * Parses a given docstring into pieces introduced by tags. + */ + +#pragma once + +#include <string> +#include <libsolidity/interface/Exceptions.h> +#include <libsolidity/ast/ASTAnnotations.h> + +namespace dev +{ +namespace solidity +{ + +class DocStringParser +{ +public: + /// Parse the given @a _docString and stores the parsed components internally. + /// @returns false on error and appends the error to @a _errors. + bool parse(std::string const& _docString, ErrorList& _errors); + + std::multimap<std::string, DocTag> const& tags() const { return m_docTags; } + +private: + using iter = std::string::const_iterator; + void resetUser(); + void resetDev(); + + iter parseDocTagLine(iter _pos, iter _end, bool _appending); + iter parseDocTagParam(iter _pos, iter _end); + iter appendDocTagParam(iter _pos, iter _end); + void parseDocString(std::string const& _string); + iter appendDocTag(iter _pos, iter _end); + /// Parses the doc tag named @a _tag, adds it to m_docTags and returns the position + /// after the tag. + iter parseDocTag(iter _pos, iter _end, std::string const& _tag); + + /// Creates and inserts a new tag and adjusts m_lastTag. + void newTag(std::string const& _tagName); + + void appendError(std::string const& _description); + + /// Mapping tag name -> content. + std::multimap<std::string, DocTag> m_docTags; + DocTag* m_lastTag = nullptr; + ErrorList* m_errors = nullptr; + bool m_errorsOccurred = false; +}; + +} //solidity NS +} // dev NS diff --git a/libsolidity/Parser.cpp b/libsolidity/parsing/Parser.cpp index 4fdfd2e4..d89218bb 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -23,10 +23,10 @@ #include <vector> #include <libdevcore/Log.h> #include <libevmasm/SourceLocation.h> -#include <libsolidity/Parser.h> -#include <libsolidity/Scanner.h> -#include <libsolidity/Exceptions.h> -#include <libsolidity/InterfaceHandler.h> +#include <libsolidity/parsing/Parser.h> +#include <libsolidity/parsing/Scanner.h> +#include <libsolidity/interface/Exceptions.h> +#include <libsolidity/interface/InterfaceHandler.h> using namespace std; @@ -600,7 +600,7 @@ ASTPointer<ParameterList> Parser::parseParameterList( return nodeFactory.createNode<ParameterList>(parameters); } -ASTPointer<Block> Parser::parseBlock() +ASTPointer<Block> Parser::parseBlock(ASTPointer<ASTString> const& _docString) { ASTNodeFactory nodeFactory(*this); expectToken(Token::LBrace); @@ -609,29 +609,32 @@ ASTPointer<Block> Parser::parseBlock() statements.push_back(parseStatement()); nodeFactory.markEndPosition(); expectToken(Token::RBrace); - return nodeFactory.createNode<Block>(statements); + return nodeFactory.createNode<Block>(_docString, statements); } ASTPointer<Statement> Parser::parseStatement() { + ASTPointer<ASTString> docString; + if (m_scanner->currentCommentLiteral() != "") + docString = make_shared<ASTString>(m_scanner->currentCommentLiteral()); ASTPointer<Statement> statement; switch (m_scanner->currentToken()) { case Token::If: - return parseIfStatement(); + return parseIfStatement(docString); case Token::While: - return parseWhileStatement(); + return parseWhileStatement(docString); case Token::For: - return parseForStatement(); + return parseForStatement(docString); case Token::LBrace: - return parseBlock(); + return parseBlock(docString); // starting from here, all statements must be terminated by a semicolon case Token::Continue: - statement = ASTNodeFactory(*this).createNode<Continue>(); + statement = ASTNodeFactory(*this).createNode<Continue>(docString); m_scanner->next(); break; case Token::Break: - statement = ASTNodeFactory(*this).createNode<Break>(); + statement = ASTNodeFactory(*this).createNode<Break>(docString); m_scanner->next(); break; case Token::Return: @@ -643,31 +646,31 @@ ASTPointer<Statement> Parser::parseStatement() expression = parseExpression(); nodeFactory.setEndPositionFromNode(expression); } - statement = nodeFactory.createNode<Return>(expression); + statement = nodeFactory.createNode<Return>(docString, expression); break; } case Token::Throw: { - statement = ASTNodeFactory(*this).createNode<Throw>(); + statement = ASTNodeFactory(*this).createNode<Throw>(docString); m_scanner->next(); break; } case Token::Identifier: if (m_insideModifier && m_scanner->currentLiteral() == "_") { - statement = ASTNodeFactory(*this).createNode<PlaceholderStatement>(); + statement = ASTNodeFactory(*this).createNode<PlaceholderStatement>(docString); m_scanner->next(); return statement; } // fall-through default: - statement = parseSimpleStatement(); + statement = parseSimpleStatement(docString); } expectToken(Token::Semicolon); return statement; } -ASTPointer<IfStatement> Parser::parseIfStatement() +ASTPointer<IfStatement> Parser::parseIfStatement(ASTPointer<ASTString> const& _docString) { ASTNodeFactory nodeFactory(*this); expectToken(Token::If); @@ -684,10 +687,10 @@ ASTPointer<IfStatement> Parser::parseIfStatement() } else nodeFactory.setEndPositionFromNode(trueBody); - return nodeFactory.createNode<IfStatement>(condition, trueBody, falseBody); + return nodeFactory.createNode<IfStatement>(_docString, condition, trueBody, falseBody); } -ASTPointer<WhileStatement> Parser::parseWhileStatement() +ASTPointer<WhileStatement> Parser::parseWhileStatement(ASTPointer<ASTString> const& _docString) { ASTNodeFactory nodeFactory(*this); expectToken(Token::While); @@ -696,10 +699,10 @@ ASTPointer<WhileStatement> Parser::parseWhileStatement() expectToken(Token::RParen); ASTPointer<Statement> body = parseStatement(); nodeFactory.setEndPositionFromNode(body); - return nodeFactory.createNode<WhileStatement>(condition, body); + return nodeFactory.createNode<WhileStatement>(_docString, condition, body); } -ASTPointer<ForStatement> Parser::parseForStatement() +ASTPointer<ForStatement> Parser::parseForStatement(ASTPointer<ASTString> const& _docString) { ASTNodeFactory nodeFactory(*this); ASTPointer<Statement> initExpression; @@ -710,7 +713,7 @@ ASTPointer<ForStatement> Parser::parseForStatement() // LTODO: Maybe here have some predicate like peekExpression() instead of checking for semicolon and RParen? if (m_scanner->currentToken() != Token::Semicolon) - initExpression = parseSimpleStatement(); + initExpression = parseSimpleStatement(ASTPointer<ASTString>()); expectToken(Token::Semicolon); if (m_scanner->currentToken() != Token::Semicolon) @@ -718,18 +721,21 @@ ASTPointer<ForStatement> Parser::parseForStatement() expectToken(Token::Semicolon); if (m_scanner->currentToken() != Token::RParen) - loopExpression = parseExpressionStatement(); + loopExpression = parseExpressionStatement(ASTPointer<ASTString>()); expectToken(Token::RParen); ASTPointer<Statement> body = parseStatement(); nodeFactory.setEndPositionFromNode(body); - return nodeFactory.createNode<ForStatement>(initExpression, - conditionExpression, - loopExpression, - body); + return nodeFactory.createNode<ForStatement>( + _docString, + initExpression, + conditionExpression, + loopExpression, + body + ); } -ASTPointer<Statement> Parser::parseSimpleStatement() +ASTPointer<Statement> Parser::parseSimpleStatement(ASTPointer<ASTString> const& _docString) { // These two cases are very hard to distinguish: // x[7 * 20 + 3] a; - x[7 * 20 + 3] = 9; @@ -740,9 +746,9 @@ ASTPointer<Statement> Parser::parseSimpleStatement() switch (peekStatementType()) { case LookAheadInfo::VariableDeclarationStatement: - return parseVariableDeclarationStatement(); + return parseVariableDeclarationStatement(_docString); case LookAheadInfo::ExpressionStatement: - return parseExpressionStatement(); + return parseExpressionStatement(_docString); default: break; } @@ -781,12 +787,13 @@ ASTPointer<Statement> Parser::parseSimpleStatement() } if (m_scanner->currentToken() == Token::Identifier || Token::isLocationSpecifier(m_scanner->currentToken())) - return parseVariableDeclarationStatement(typeNameIndexAccessStructure(path, indices)); + return parseVariableDeclarationStatement(_docString, typeNameIndexAccessStructure(path, indices)); else - return parseExpressionStatement(expressionFromIndexAccessStructure(path, indices)); + return parseExpressionStatement(_docString, expressionFromIndexAccessStructure(path, indices)); } ASTPointer<VariableDeclarationStatement> Parser::parseVariableDeclarationStatement( + ASTPointer<ASTString> const& _docString, ASTPointer<TypeName> const& _lookAheadArrayType ) { @@ -845,15 +852,16 @@ ASTPointer<VariableDeclarationStatement> Parser::parseVariableDeclarationStateme value = parseExpression(); nodeFactory.setEndPositionFromNode(value); } - return nodeFactory.createNode<VariableDeclarationStatement>(variables, value); + return nodeFactory.createNode<VariableDeclarationStatement>(_docString, variables, value); } ASTPointer<ExpressionStatement> Parser::parseExpressionStatement( + ASTPointer<ASTString> const& _docString, ASTPointer<Expression> const& _lookAheadIndexAccessStructure ) { ASTPointer<Expression> expression = parseExpression(_lookAheadIndexAccessStructure); - return ASTNodeFactory(*this, expression).createNode<ExpressionStatement>(expression); + return ASTNodeFactory(*this, expression).createNode<ExpressionStatement>(_docString, expression); } ASTPointer<Expression> Parser::parseExpression( @@ -1180,7 +1188,13 @@ ASTPointer<Expression> Parser::expressionFromIndexAccessStructure( void Parser::expectToken(Token::Value _value) { if (m_scanner->currentToken() != _value) - fatalParserError(std::string(string("Expected token ") + string(Token::name(_value)))); + fatalParserError( + string("Expected token ") + + string(Token::name(_value)) + + string(" got '") + + string(Token::name(m_scanner->currentToken())) + + string("'") + ); m_scanner->next(); } @@ -1188,7 +1202,12 @@ Token::Value Parser::expectAssignmentOperator() { Token::Value op = m_scanner->currentToken(); if (!Token::isAssignmentOp(op)) - fatalParserError(std::string("Expected assignment operator")); + fatalParserError( + std::string("Expected assignment operator ") + + string(" got '") + + string(Token::name(m_scanner->currentToken())) + + string("'") + ); m_scanner->next(); return op; } @@ -1196,7 +1215,12 @@ Token::Value Parser::expectAssignmentOperator() ASTPointer<ASTString> Parser::expectIdentifierToken() { if (m_scanner->currentToken() != Token::Identifier) - fatalParserError(std::string("Expected identifier")); + fatalParserError( + std::string("Expected identifier ") + + string(" got '") + + string(Token::name(m_scanner->currentToken())) + + string("'") + ); return getLiteralAndAdvance(); } diff --git a/libsolidity/Parser.h b/libsolidity/parsing/Parser.h index bd483e09..663c0f92 100644 --- a/libsolidity/Parser.h +++ b/libsolidity/parsing/Parser.h @@ -22,7 +22,7 @@ #pragma once -#include "libsolidity/AST.h" +#include "libsolidity/ast/AST.h" namespace dev { @@ -82,17 +82,19 @@ private: VarDeclParserOptions const& _options, bool _allowEmpty = true ); - ASTPointer<Block> parseBlock(); + ASTPointer<Block> parseBlock(ASTPointer<ASTString> const& _docString = {}); ASTPointer<Statement> parseStatement(); - ASTPointer<IfStatement> parseIfStatement(); - ASTPointer<WhileStatement> parseWhileStatement(); - ASTPointer<ForStatement> parseForStatement(); + ASTPointer<IfStatement> parseIfStatement(ASTPointer<ASTString> const& _docString); + ASTPointer<WhileStatement> parseWhileStatement(ASTPointer<ASTString> const& _docString); + ASTPointer<ForStatement> parseForStatement(ASTPointer<ASTString> const& _docString); /// A "simple statement" can be a variable declaration statement or an expression statement. - ASTPointer<Statement> parseSimpleStatement(); + ASTPointer<Statement> parseSimpleStatement(ASTPointer<ASTString> const& _docString); ASTPointer<VariableDeclarationStatement> parseVariableDeclarationStatement( + ASTPointer<ASTString> const& _docString, ASTPointer<TypeName> const& _lookAheadArrayType = ASTPointer<TypeName>() ); ASTPointer<ExpressionStatement> parseExpressionStatement( + ASTPointer<ASTString> const& _docString, ASTPointer<Expression> const& _lookAheadIndexAccessStructure = ASTPointer<Expression>() ); ASTPointer<Expression> parseExpression( diff --git a/libsolidity/Scanner.cpp b/libsolidity/parsing/Scanner.cpp index d67b6423..fe0807d5 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/parsing/Scanner.cpp @@ -52,8 +52,8 @@ #include <algorithm> #include <tuple> -#include <libsolidity/Utils.h> -#include <libsolidity/Scanner.h> +#include <libsolidity/interface/Utils.h> +#include <libsolidity/parsing/Scanner.h> using namespace std; diff --git a/libsolidity/Scanner.h b/libsolidity/parsing/Scanner.h index 29b44d15..a1a5c9c1 100644 --- a/libsolidity/Scanner.h +++ b/libsolidity/parsing/Scanner.h @@ -56,7 +56,7 @@ #include <libdevcore/Log.h> #include <libdevcore/CommonData.h> #include <libevmasm/SourceLocation.h> -#include <libsolidity/Token.h> +#include <libsolidity/parsing/Token.h> namespace dev { diff --git a/libsolidity/Token.cpp b/libsolidity/parsing/Token.cpp index d07d7502..cda639fb 100644 --- a/libsolidity/Token.cpp +++ b/libsolidity/parsing/Token.cpp @@ -41,7 +41,7 @@ // along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. #include <map> -#include <libsolidity/Token.h> +#include <libsolidity/parsing/Token.h> using namespace std; diff --git a/libsolidity/Token.h b/libsolidity/parsing/Token.h index 2ea7eb01..98461fa4 100644 --- a/libsolidity/Token.h +++ b/libsolidity/parsing/Token.h @@ -44,8 +44,8 @@ #include <libdevcore/Common.h> #include <libdevcore/Log.h> -#include <libsolidity/Utils.h> -#include <libsolidity/Exceptions.h> +#include <libsolidity/interface/Utils.h> +#include <libsolidity/interface/Exceptions.h> #include <libdevcore/UndefMacros.h> namespace dev |