aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity
diff options
context:
space:
mode:
Diffstat (limited to 'libsolidity')
-rw-r--r--libsolidity/CMakeLists.txt9
-rw-r--r--libsolidity/InterfaceHandler.cpp478
-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.cpp128
-rw-r--r--libsolidity/analysis/DocStringAnalyser.h71
-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.cpp525
-rw-r--r--libsolidity/formal/Why3Translator.h115
-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.cpp248
-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.cpp141
-rw-r--r--libsolidity/parsing/DocStringParser.h70
-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