aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLefteris Karapetsas <lefteris@refu.co>2014-12-10 20:13:12 +0800
committerLefteris Karapetsas <lefteris@refu.co>2014-12-10 20:24:48 +0800
commitfbc35003cee590b24bbbf8b68dad1cf4a81073c5 (patch)
tree7e83f579f063575b58ca294a02e2dc21cb817717
parent57e6827cb57708ed8f687bf9b0a304b1481cf742 (diff)
downloaddexon-solidity-fbc35003cee590b24bbbf8b68dad1cf4a81073c5.tar
dexon-solidity-fbc35003cee590b24bbbf8b68dad1cf4a81073c5.tar.gz
dexon-solidity-fbc35003cee590b24bbbf8b68dad1cf4a81073c5.tar.bz2
dexon-solidity-fbc35003cee590b24bbbf8b68dad1cf4a81073c5.tar.lz
dexon-solidity-fbc35003cee590b24bbbf8b68dad1cf4a81073c5.tar.xz
dexon-solidity-fbc35003cee590b24bbbf8b68dad1cf4a81073c5.tar.zst
dexon-solidity-fbc35003cee590b24bbbf8b68dad1cf4a81073c5.zip
Natspec title and author tag.
- Adding the title and author natspec documentation tags for contracts - Also using the author tag for functions now - Tests
-rw-r--r--AST.h9
-rw-r--r--InterfaceHandler.cpp109
-rw-r--r--InterfaceHandler.h21
-rw-r--r--Parser.cpp5
4 files changed, 114 insertions, 30 deletions
diff --git a/AST.h b/AST.h
index 10616022..ece609da 100644
--- a/AST.h
+++ b/AST.h
@@ -146,13 +146,15 @@ class ContractDefinition: public Declaration
public:
ContractDefinition(Location const& _location,
ASTPointer<ASTString> const& _name,
+ ASTPointer<ASTString> const& _documentation,
std::vector<ASTPointer<StructDefinition>> const& _definedStructs,
std::vector<ASTPointer<VariableDeclaration>> const& _stateVariables,
std::vector<ASTPointer<FunctionDefinition>> const& _definedFunctions):
Declaration(_location, _name),
m_definedStructs(_definedStructs),
m_stateVariables(_stateVariables),
- m_definedFunctions(_definedFunctions)
+ m_definedFunctions(_definedFunctions),
+ m_documentation(_documentation)
{}
virtual void accept(ASTVisitor& _visitor) override;
@@ -161,6 +163,10 @@ public:
std::vector<ASTPointer<VariableDeclaration>> const& getStateVariables() const { return m_stateVariables; }
std::vector<ASTPointer<FunctionDefinition>> const& getDefinedFunctions() const { return m_definedFunctions; }
+ /// @return A shared pointer of an ASTString.
+ /// Can contain a nullptr in which case indicates absence of documentation
+ ASTPointer<ASTString> const& getDocumentation() const { return m_documentation; }
+
/// Returns the functions that make up the calling interface in the intended order.
std::vector<FunctionDefinition const*> getInterfaceFunctions() const;
@@ -168,6 +174,7 @@ private:
std::vector<ASTPointer<StructDefinition>> m_definedStructs;
std::vector<ASTPointer<VariableDeclaration>> m_stateVariables;
std::vector<ASTPointer<FunctionDefinition>> m_definedFunctions;
+ ASTPointer<ASTString> m_documentation;
};
class StructDefinition: public Declaration
diff --git a/InterfaceHandler.cpp b/InterfaceHandler.cpp
index c3e62cad..ac1fb29a 100644
--- a/InterfaceHandler.cpp
+++ b/InterfaceHandler.cpp
@@ -75,7 +75,7 @@ std::unique_ptr<std::string> InterfaceHandler::getUserDocumentation(ContractDefi
if (strPtr)
{
resetUser();
- parseDocString(*strPtr);
+ 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);
@@ -95,6 +95,20 @@ std::unique_ptr<std::string> InterfaceHandler::getDevDocumentation(ContractDefin
Json::Value doc;
Json::Value methods(Json::objectValue);
+ auto contractDoc = _contractDef.getDocumentation();
+ 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 (FunctionDefinition const* f: _contractDef.getInterfaceFunctions())
{
Json::Value method;
@@ -102,16 +116,21 @@ std::unique_ptr<std::string> InterfaceHandler::getDevDocumentation(ContractDefin
if (strPtr)
{
resetDev();
- parseDocString(*strPtr);
+ 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);
for (auto const& pair: m_params)
params[pair.first] = pair.second;
if (!m_params.empty())
method["params"] = params;
+
if (!m_return.empty())
method["return"] = m_return;
@@ -133,6 +152,7 @@ void InterfaceHandler::resetUser()
void InterfaceHandler::resetDev()
{
m_dev.clear();
+ m_author.clear();
m_return.clear();
m_params.clear();
}
@@ -193,7 +213,8 @@ std::string::const_iterator InterfaceHandler::appendDocTagParam(std::string::con
std::string::const_iterator InterfaceHandler::parseDocTag(std::string::const_iterator _pos,
std::string::const_iterator _end,
- std::string const& _tag)
+ std::string const& _tag,
+ CommentOwner _owner)
{
// LTODO: need to check for @(start of a tag) between here and the end of line
// for all cases
@@ -205,37 +226,77 @@ std::string::const_iterator InterfaceHandler::parseDocTag(std::string::const_ite
return parseDocTagLine(_pos, _end, m_notice, DocTagType::NOTICE);
else if (_tag == "return")
return parseDocTagLine(_pos, _end, m_return, DocTagType::RETURN);
+ else if (_tag == "author")
+ {
+ if (_owner == CommentOwner::CONTRACT)
+ return parseDocTagLine(_pos, _end, m_contractAuthor, DocTagType::AUTHOR);
+ else if(_owner == CommentOwner::FUNCTION)
+ return parseDocTagLine(_pos, _end, m_author, DocTagType::AUTHOR);
+ else
+ // LTODO: for now this else makes no sense but later comments will go to more language constructs
+ BOOST_THROW_EXCEPTION(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);
+ else
+ // LTODO: Unknown tag, throw some form of warning and not just an exception
+ BOOST_THROW_EXCEPTION(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(DocstringParsingError() << errinfo_comment("Unknown tag " + _tag + " encountered"));
- }
}
else
- return appendDocTag(_pos, _end);
+ return appendDocTag(_pos, _end, _owner);
}
std::string::const_iterator InterfaceHandler::appendDocTag(std::string::const_iterator _pos,
- std::string::const_iterator _end)
+ std::string::const_iterator _end,
+ CommentOwner _owner)
{
switch (m_lastTag)
{
- case DocTagType::DEV:
- m_dev += " ";
- return parseDocTagLine(_pos, _end, m_dev, DocTagType::DEV);
- case DocTagType::NOTICE:
- m_notice += " ";
- return parseDocTagLine(_pos, _end, m_notice, DocTagType::NOTICE);
- case DocTagType::RETURN:
- m_return += " ";
- return parseDocTagLine(_pos, _end, m_return, DocTagType::RETURN);
- case DocTagType::PARAM:
- return appendDocTagParam(_pos, _end);
- default:
- BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Internal: Illegal documentation tag type"));
- break;
+ case DocTagType::DEV:
+ m_dev += " ";
+ return parseDocTagLine(_pos, _end, m_dev, DocTagType::DEV);
+ case DocTagType::NOTICE:
+ m_notice += " ";
+ return parseDocTagLine(_pos, _end, m_notice, DocTagType::NOTICE);
+ case DocTagType::RETURN:
+ m_return += " ";
+ return parseDocTagLine(_pos, _end, m_return, DocTagType::RETURN);
+ case DocTagType::AUTHOR:
+ if (_owner == CommentOwner::CONTRACT)
+ {
+ m_contractAuthor += " ";
+ return parseDocTagLine(_pos, _end, m_contractAuthor, DocTagType::AUTHOR);
+ }
+ else if(_owner == CommentOwner::FUNCTION)
+ {
+ m_author += " ";
+ return parseDocTagLine(_pos, _end, m_author, DocTagType::AUTHOR);
+ }
+ else
+ // LTODO: Unknown tag, throw some form of warning and not just an exception
+ BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("@author tag in illegal comment"));
+ case DocTagType::TITLE:
+ if (_owner == CommentOwner::CONTRACT)
+ {
+ m_title += " ";
+ return parseDocTagLine(_pos, _end, m_title, DocTagType::TITLE);
+ }
+ else
+ // LTODO: Unknown tag, throw some form of warning and not just an exception
+ BOOST_THROW_EXCEPTION(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;
}
}
@@ -247,7 +308,7 @@ static inline std::string::const_iterator getFirstSpaceOrNl(std::string::const_i
return (spacePos < nlPos) ? spacePos : nlPos;
}
-void InterfaceHandler::parseDocString(std::string const& _string)
+void InterfaceHandler::parseDocString(std::string const& _string, CommentOwner _owner)
{
auto currPos = _string.begin();
auto end = _string.end();
@@ -265,10 +326,10 @@ void InterfaceHandler::parseDocString(std::string const& _string)
BOOST_THROW_EXCEPTION(DocstringParsingError() <<
errinfo_comment("End of tag " + std::string(tagPos, tagNameEndPos) + "not found"));
- currPos = parseDocTag(tagNameEndPos + 1, end, std::string(tagPos + 1, tagNameEndPos));
+ currPos = parseDocTag(tagNameEndPos + 1, end, std::string(tagPos + 1, tagNameEndPos), _owner);
}
else if (m_lastTag != DocTagType::NONE) // continuation of the previous tag
- currPos = appendDocTag(currPos + 1, end);
+ currPos = appendDocTag(currPos + 1, end, _owner);
else if (currPos != end) // skip the line if a newline was found
currPos = nlPos + 1;
}
diff --git a/InterfaceHandler.h b/InterfaceHandler.h
index e6be9e6a..d71345b9 100644
--- a/InterfaceHandler.h
+++ b/InterfaceHandler.h
@@ -45,7 +45,15 @@ enum class DocTagType: uint8_t
DEV,
NOTICE,
PARAM,
- RETURN
+ RETURN,
+ AUTHOR,
+ TITLE
+};
+
+enum class CommentOwner
+{
+ CONTRACT,
+ FUNCTION
};
class InterfaceHandler
@@ -89,12 +97,14 @@ private:
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);
+ void parseDocString(std::string const& _string, CommentOwner _owner);
std::string::const_iterator appendDocTag(std::string::const_iterator _pos,
- std::string::const_iterator _end);
+ 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);
+ std::string const& _tag,
+ CommentOwner _owner);
Json::StyledWriter m_writer;
@@ -103,6 +113,9 @@ private:
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;
};
diff --git a/Parser.cpp b/Parser.cpp
index ddab489b..b678b2fc 100644
--- a/Parser.cpp
+++ b/Parser.cpp
@@ -112,6 +112,9 @@ ASTPointer<ImportDirective> Parser::parseImportDirective()
ASTPointer<ContractDefinition> Parser::parseContractDefinition()
{
ASTNodeFactory nodeFactory(*this);
+ ASTPointer<ASTString> docstring;
+ if (m_scanner->getCurrentCommentLiteral() != "")
+ docstring = make_shared<ASTString>(m_scanner->getCurrentCommentLiteral());
expectToken(Token::CONTRACT);
ASTPointer<ASTString> name = expectIdentifierToken();
expectToken(Token::LBRACE);
@@ -146,7 +149,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
}
nodeFactory.markEndPosition();
expectToken(Token::RBRACE);
- return nodeFactory.createNode<ContractDefinition>(name, structs, stateVariables, functions);
+ return nodeFactory.createNode<ContractDefinition>(name, docstring, structs, stateVariables, functions);
}
ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(bool _isPublic)