diff options
Diffstat (limited to 'libsolidity/parsing')
-rw-r--r-- | libsolidity/parsing/DocStringParser.cpp | 79 | ||||
-rw-r--r-- | libsolidity/parsing/DocStringParser.h | 7 | ||||
-rw-r--r-- | libsolidity/parsing/Parser.cpp | 143 | ||||
-rw-r--r-- | libsolidity/parsing/Parser.h | 10 | ||||
-rw-r--r-- | libsolidity/parsing/ParserBase.cpp | 87 | ||||
-rw-r--r-- | libsolidity/parsing/ParserBase.h | 15 | ||||
-rw-r--r-- | libsolidity/parsing/Scanner.cpp | 5 | ||||
-rw-r--r-- | libsolidity/parsing/Token.h | 7 |
8 files changed, 222 insertions, 131 deletions
diff --git a/libsolidity/parsing/DocStringParser.cpp b/libsolidity/parsing/DocStringParser.cpp index bbee35f5..0409de72 100644 --- a/libsolidity/parsing/DocStringParser.cpp +++ b/libsolidity/parsing/DocStringParser.cpp @@ -1,14 +1,20 @@ #include <libsolidity/parsing/DocStringParser.h> +#include <libsolidity/interface/ErrorReporter.h> +#include <libsolidity/interface/Exceptions.h> + #include <boost/range/irange.hpp> -#include <libsolidity/interface/Utils.h> +#include <boost/range/algorithm.hpp> using namespace std; using namespace dev; using namespace dev::solidity; -static inline string::const_iterator skipLineOrEOS( +namespace +{ + +string::const_iterator skipLineOrEOS( string::const_iterator _nlPos, string::const_iterator _end ) @@ -16,19 +22,39 @@ static inline string::const_iterator skipLineOrEOS( return (_nlPos == _end) ? _end : ++_nlPos; } -static inline string::const_iterator firstSpaceOrNl( +string::const_iterator firstSpaceOrTab( string::const_iterator _pos, string::const_iterator _end ) { - auto spacePos = find(_pos, _end, ' '); - auto nlPos = find(_pos, _end, '\n'); - return (spacePos < nlPos) ? spacePos : nlPos; + return boost::range::find_first_of(make_pair(_pos, _end), " \t"); } -bool DocStringParser::parse(string const& _docString, ErrorList& _errors) +string::const_iterator firstWhitespaceOrNewline( + string::const_iterator _pos, + string::const_iterator _end +) { - m_errors = &_errors; + return boost::range::find_first_of(make_pair(_pos, _end), " \t\n"); +} + + +string::const_iterator skipWhitespace( + string::const_iterator _pos, + string::const_iterator _end +) +{ + auto currPos = _pos; + while (currPos != _end && (*currPos == ' ' || *currPos == '\t')) + currPos += 1; + return currPos; +} + +} + +bool DocStringParser::parse(string const& _docString, ErrorReporter& _errorReporter) +{ + m_errorReporter = &_errorReporter; m_errorsOccurred = false; m_lastTag = nullptr; @@ -43,7 +69,7 @@ bool DocStringParser::parse(string const& _docString, ErrorList& _errors) if (tagPos != end && tagPos < nlPos) { // we found a tag - auto tagNameEndPos = firstSpaceOrNl(tagPos, end); + auto tagNameEndPos = firstWhitespaceOrNewline(tagPos, end); if (tagNameEndPos == end) { appendError("End of tag " + string(tagPos, tagNameEndPos) + "not found"); @@ -75,27 +101,40 @@ DocStringParser::iter DocStringParser::parseDocTagLine(iter _pos, iter _end, boo { solAssert(!!m_lastTag, ""); auto nlPos = find(_pos, _end, '\n'); - if (_appending && _pos < _end && *_pos != ' ') + if (_appending && _pos < _end && *_pos != ' ' && *_pos != '\t') m_lastTag->content += " "; + else if (!_appending) + _pos = skipWhitespace(_pos, _end); 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) + // find param name start + auto nameStartPos = skipWhitespace(_pos, _end); + if (nameStartPos == _end) { - appendError("End of param name not found" + string(_pos, _end)); + appendError("No param name given"); return _end; } + auto nameEndPos = firstSpaceOrTab(nameStartPos, _end); + if (nameEndPos == _end) + { + appendError("End of param name not found: " + string(nameStartPos, _end)); + return _end; + } + auto paramName = string(nameStartPos, nameEndPos); - auto paramName = string(_pos, currPos); + auto descStartPos = skipWhitespace(nameEndPos, _end); + if (descStartPos == _end) + { + appendError("No description given for param " + paramName); + return _end; + } - currPos += 1; - auto nlPos = find(currPos, _end, '\n'); - auto paramDesc = string(currPos, nlPos); + auto nlPos = find(descStartPos, _end, '\n'); + auto paramDesc = string(descStartPos, nlPos); newTag("param"); m_lastTag->paramName = paramName; m_lastTag->content = paramDesc; @@ -134,8 +173,6 @@ void DocStringParser::newTag(string const& _tagName) 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; + m_errorReporter->docstringParsingError(_description); } diff --git a/libsolidity/parsing/DocStringParser.h b/libsolidity/parsing/DocStringParser.h index c7f81c55..5f2819cc 100644 --- a/libsolidity/parsing/DocStringParser.h +++ b/libsolidity/parsing/DocStringParser.h @@ -23,7 +23,6 @@ #pragma once #include <string> -#include <libsolidity/interface/Exceptions.h> #include <libsolidity/ast/ASTAnnotations.h> namespace dev @@ -31,12 +30,14 @@ namespace dev namespace solidity { +class ErrorReporter; + 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); + bool parse(std::string const& _docString, ErrorReporter& _errorReporter); std::multimap<std::string, DocTag> const& tags() const { return m_docTags; } @@ -62,7 +63,7 @@ private: /// Mapping tag name -> content. std::multimap<std::string, DocTag> m_docTags; DocTag* m_lastTag = nullptr; - ErrorList* m_errors = nullptr; + ErrorReporter* m_errorReporter = nullptr; bool m_errorsOccurred = false; }; diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index f02a4a45..b0cf364e 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -26,8 +26,7 @@ #include <libsolidity/parsing/Parser.h> #include <libsolidity/parsing/Scanner.h> #include <libsolidity/inlineasm/AsmParser.h> -#include <libsolidity/interface/Exceptions.h> -#include <libsolidity/interface/InterfaceHandler.h> +#include <libsolidity/interface/ErrorReporter.h> using namespace std; @@ -82,9 +81,10 @@ ASTPointer<SourceUnit> Parser::parse(shared_ptr<Scanner> const& _scanner) case Token::Import: nodes.push_back(parseImportDirective()); break; + case Token::Interface: case Token::Contract: case Token::Library: - nodes.push_back(parseContractDefinition(token == Token::Library)); + nodes.push_back(parseContractDefinition(token)); break; default: fatalParserError(string("Expected import directive or contract definition.")); @@ -94,7 +94,7 @@ ASTPointer<SourceUnit> Parser::parse(shared_ptr<Scanner> const& _scanner) } catch (FatalError const&) { - if (m_errors.empty()) + if (m_errorReporter.errors().empty()) throw; // Something is weird here, rather throw again. return nullptr; } @@ -193,13 +193,30 @@ ASTPointer<ImportDirective> Parser::parseImportDirective() return nodeFactory.createNode<ImportDirective>(path, unitAlias, move(symbolAliases)); } -ASTPointer<ContractDefinition> Parser::parseContractDefinition(bool _isLibrary) +ContractDefinition::ContractKind Parser::tokenToContractKind(Token::Value _token) +{ + switch(_token) + { + case Token::Interface: + return ContractDefinition::ContractKind::Interface; + case Token::Contract: + return ContractDefinition::ContractKind::Contract; + case Token::Library: + return ContractDefinition::ContractKind::Library; + default: + fatalParserError("Unsupported contract type."); + } + // FIXME: fatalParserError is not considered as throwing here + return ContractDefinition::ContractKind::Contract; +} + +ASTPointer<ContractDefinition> Parser::parseContractDefinition(Token::Value _expectedKind) { ASTNodeFactory nodeFactory(*this); ASTPointer<ASTString> docString; if (m_scanner->currentCommentLiteral() != "") docString = make_shared<ASTString>(m_scanner->currentCommentLiteral()); - expectToken(_isLibrary ? Token::Library : Token::Contract); + expectToken(_expectedKind); ASTPointer<ASTString> name = expectIdentifierToken(); vector<ASTPointer<InheritanceSpecifier>> baseContracts; if (m_scanner->currentToken() == Token::Is) @@ -252,7 +269,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition(bool _isLibrary) docString, baseContracts, subNodes, - _isLibrary + tokenToContractKind(_expectedKind) ); } @@ -306,11 +323,17 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _forceEmptyN Token::Value token = m_scanner->currentToken(); if (token == Token::Const) { + if (result.isDeclaredConst) + parserError(string("Multiple \"constant\" specifiers.")); + result.isDeclaredConst = true; m_scanner->next(); } else if (m_scanner->currentToken() == Token::Payable) { + if (result.isPayable) + parserError(string("Multiple \"payable\" specifiers.")); + result.isPayable = true; m_scanner->next(); } @@ -330,8 +353,12 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _forceEmptyN else if (Token::isVisibilitySpecifier(token)) { if (result.visibility != Declaration::Visibility::Default) - fatalParserError(string("Multiple visibility specifiers.")); - result.visibility = parseVisibilitySpecifier(token); + { + parserError(string("Multiple visibility specifiers.")); + m_scanner->next(); + } + else + result.visibility = parseVisibilitySpecifier(token); } else break; @@ -484,8 +511,12 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration( if (_options.isStateVariable && Token::isVariableVisibilitySpecifier(token)) { if (visibility != Declaration::Visibility::Default) - fatalParserError(string("Visibility already specified.")); - visibility = parseVisibilitySpecifier(token); + { + parserError(string("Visibility already specified.")); + m_scanner->next(); + } + else + visibility = parseVisibilitySpecifier(token); } else { @@ -496,14 +527,15 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration( else if (_options.allowLocationSpecifier && Token::isLocationSpecifier(token)) { if (location != VariableDeclaration::Location::Default) - fatalParserError(string("Location already specified.")); - if (!type) - fatalParserError(string("Location specifier needs explicit type name.")); - location = ( - token == Token::Memory ? - VariableDeclaration::Location::Memory : - VariableDeclaration::Location::Storage - ); + parserError(string("Location already specified.")); + else if (!type) + parserError(string("Location specifier needs explicit type name.")); + else + location = ( + token == Token::Memory ? + VariableDeclaration::Location::Memory : + VariableDeclaration::Location::Storage + ); } else break; @@ -685,7 +717,7 @@ ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar) else if (token == Token::Var) { if (!_allowVar) - fatalParserError(string("Expected explicit type name.")); + parserError(string("Expected explicit type name.")); m_scanner->next(); } else if (token == Token::Function) @@ -848,7 +880,7 @@ ASTPointer<InlineAssembly> Parser::parseInlineAssembly(ASTPointer<ASTString> con m_scanner->next(); } - assembly::Parser asmParser(m_errors); + assembly::Parser asmParser(m_errorReporter); shared_ptr<assembly::Block> block = asmParser.parse(m_scanner); nodeFactory.markEndPosition(); return nodeFactory.createNode<InlineAssembly>(_docString, block); @@ -1153,9 +1185,9 @@ ASTPointer<Expression> Parser::parseLeftHandSideExpression( else if (m_scanner->currentToken() == Token::New) { expectToken(Token::New); - ASTPointer<TypeName> contractName(parseTypeName(false)); - nodeFactory.setEndPositionFromNode(contractName); - expression = nodeFactory.createNode<NewExpression>(contractName); + ASTPointer<TypeName> typeName(parseTypeName(false)); + nodeFactory.setEndPositionFromNode(typeName); + expression = nodeFactory.createNode<NewExpression>(typeName); } else expression = parsePrimaryExpression(); @@ -1311,16 +1343,27 @@ pair<vector<ASTPointer<Expression>>, vector<ASTPointer<ASTString>>> Parser::pars { // call({arg1 : 1, arg2 : 2 }) expectToken(Token::LBrace); + + bool first = true; while (m_scanner->currentToken() != Token::RBrace) { + if (!first) + expectToken(Token::Comma); + ret.second.push_back(expectIdentifierToken()); expectToken(Token::Colon); ret.first.push_back(parseExpression()); - if (m_scanner->currentToken() == Token::Comma) - expectToken(Token::Comma); - else - break; + if ( + m_scanner->currentToken() == Token::Comma && + m_scanner->peekNextToken() == Token::RBrace + ) + { + parserError("Unexpected trailing comma."); + m_scanner->next(); + } + + first = false; } expectToken(Token::RBrace); } @@ -1420,5 +1463,49 @@ ASTPointer<ParameterList> Parser::createEmptyParameterList() return nodeFactory.createNode<ParameterList>(vector<ASTPointer<VariableDeclaration>>()); } +string Parser::currentTokenName() +{ + Token::Value token = m_scanner->currentToken(); + if (Token::isElementaryTypeName(token)) //for the sake of accuracy in reporting + { + ElementaryTypeNameToken elemTypeName = m_scanner->currentElementaryTypeNameToken(); + return elemTypeName.toString(); + } + else + return Token::name(token); +} + +Token::Value Parser::expectAssignmentOperator() +{ + Token::Value op = m_scanner->currentToken(); + if (!Token::isAssignmentOp(op)) + fatalParserError( + string("Expected assignment operator, got '") + + currentTokenName() + + string("'") + ); + m_scanner->next(); + return op; +} + +ASTPointer<ASTString> Parser::expectIdentifierToken() +{ + Token::Value id = m_scanner->currentToken(); + if (id != Token::Identifier) + fatalParserError( + string("Expected identifier, got '") + + currentTokenName() + + string("'") + ); + return getLiteralAndAdvance(); +} + +ASTPointer<ASTString> Parser::getLiteralAndAdvance() +{ + ASTPointer<ASTString> identifier = make_shared<ASTString>(m_scanner->currentLiteral()); + m_scanner->next(); + return identifier; +} + } } diff --git a/libsolidity/parsing/Parser.h b/libsolidity/parsing/Parser.h index 79d1d1d4..19631c58 100644 --- a/libsolidity/parsing/Parser.h +++ b/libsolidity/parsing/Parser.h @@ -35,7 +35,7 @@ class Scanner; class Parser: public ParserBase { public: - Parser(ErrorList& _errors): ParserBase(_errors) {} + Parser(ErrorReporter& _errorReporter): ParserBase(_errorReporter) {} ASTPointer<SourceUnit> parse(std::shared_ptr<Scanner> const& _scanner); @@ -69,7 +69,8 @@ private: ///@name Parsing functions for the AST nodes ASTPointer<PragmaDirective> parsePragmaDirective(); ASTPointer<ImportDirective> parseImportDirective(); - ASTPointer<ContractDefinition> parseContractDefinition(bool _isLibrary); + ContractDefinition::ContractKind tokenToContractKind(Token::Value _token); + ASTPointer<ContractDefinition> parseContractDefinition(Token::Value _expectedKind); ASTPointer<InheritanceSpecifier> parseInheritanceSpecifier(); Declaration::Visibility parseVisibilitySpecifier(Token::Value _token); FunctionHeaderParserResult parseFunctionHeader(bool _forceEmptyName, bool _allowModifiers); @@ -153,6 +154,11 @@ private: std::vector<ASTPointer<PrimaryExpression>> const& _path, std::vector<std::pair<ASTPointer<Expression>, SourceLocation>> const& _indices ); + + std::string currentTokenName(); + Token::Value expectAssignmentOperator(); + ASTPointer<ASTString> expectIdentifierToken(); + ASTPointer<ASTString> getLiteralAndAdvance(); ///@} /// Creates an empty ParameterList at the current location (used if parameters can be omitted). diff --git a/libsolidity/parsing/ParserBase.cpp b/libsolidity/parsing/ParserBase.cpp index 87d47f4b..5657c2c0 100644 --- a/libsolidity/parsing/ParserBase.cpp +++ b/libsolidity/parsing/ParserBase.cpp @@ -22,6 +22,7 @@ #include <libsolidity/parsing/ParserBase.h> #include <libsolidity/parsing/Scanner.h> +#include <libsolidity/interface/ErrorReporter.h> using namespace std; using namespace dev; @@ -42,6 +43,26 @@ int ParserBase::endPosition() const return m_scanner->currentLocation().end; } +Token::Value ParserBase::currentToken() const +{ + return m_scanner->currentToken(); +} + +Token::Value ParserBase::peekNextToken() const +{ + return m_scanner->peekNextToken(); +} + +std::string ParserBase::currentLiteral() const +{ + return m_scanner->currentLiteral(); +} + +Token::Value ParserBase::advance() +{ + return m_scanner->next(); +} + void ParserBase::expectToken(Token::Value _value) { Token::Value tok = m_scanner->currentToken(); @@ -80,74 +101,12 @@ void ParserBase::expectToken(Token::Value _value) m_scanner->next(); } -Token::Value ParserBase::expectAssignmentOperator() -{ - Token::Value op = m_scanner->currentToken(); - if (!Token::isAssignmentOp(op)) - { - if (Token::isElementaryTypeName(op)) //for the sake of accuracy in reporting - { - ElementaryTypeNameToken elemTypeName = m_scanner->currentElementaryTypeNameToken(); - fatalParserError( - string("Expected assignment operator, got '") + - elemTypeName.toString() + - string("'") - ); - } - else - fatalParserError( - string("Expected assignment operator, got '") + - string(Token::name(m_scanner->currentToken())) + - string("'") - ); - } - m_scanner->next(); - return op; -} - -ASTPointer<ASTString> ParserBase::expectIdentifierToken() -{ - Token::Value id = m_scanner->currentToken(); - if (id != Token::Identifier) - { - if (Token::isElementaryTypeName(id)) //for the sake of accuracy in reporting - { - ElementaryTypeNameToken elemTypeName = m_scanner->currentElementaryTypeNameToken(); - fatalParserError( - string("Expected identifier, got '") + - elemTypeName.toString() + - string("'") - ); - } - else - fatalParserError( - string("Expected identifier, got '") + - string(Token::name(id)) + - string("'") - ); - } - return getLiteralAndAdvance(); -} - -ASTPointer<ASTString> ParserBase::getLiteralAndAdvance() -{ - ASTPointer<ASTString> identifier = make_shared<ASTString>(m_scanner->currentLiteral()); - m_scanner->next(); - return identifier; -} - void ParserBase::parserError(string const& _description) { - auto err = make_shared<Error>(Error::Type::ParserError); - *err << - errinfo_sourceLocation(SourceLocation(position(), position(), sourceName())) << - errinfo_comment(_description); - - m_errors.push_back(err); + m_errorReporter.parserError(SourceLocation(position(), position(), sourceName()), _description); } void ParserBase::fatalParserError(string const& _description) { - parserError(_description); - BOOST_THROW_EXCEPTION(FatalError()); + m_errorReporter.fatalParserError(SourceLocation(position(), position(), sourceName()), _description); } diff --git a/libsolidity/parsing/ParserBase.h b/libsolidity/parsing/ParserBase.h index dfb7cab7..5b03ab5e 100644 --- a/libsolidity/parsing/ParserBase.h +++ b/libsolidity/parsing/ParserBase.h @@ -23,21 +23,20 @@ #pragma once #include <memory> -#include <libsolidity/interface/Exceptions.h> #include <libsolidity/parsing/Token.h> -#include <libsolidity/ast/ASTForward.h> namespace dev { namespace solidity { +class ErrorReporter; class Scanner; class ParserBase { public: - ParserBase(ErrorList& errors): m_errors(errors) {} + ParserBase(ErrorReporter& errorReporter): m_errorReporter(errorReporter) {} std::shared_ptr<std::string const> const& sourceName() const; @@ -47,14 +46,14 @@ protected: /// End position of the current token int endPosition() const; - ///@{ ///@name Helper functions /// If current token value is not _value, throw exception otherwise advance token. void expectToken(Token::Value _value); - Token::Value expectAssignmentOperator(); - ASTPointer<ASTString> expectIdentifierToken(); - ASTPointer<ASTString> getLiteralAndAdvance(); + Token::Value currentToken() const; + Token::Value peekNextToken() const; + std::string currentLiteral() const; + Token::Value advance(); ///@} /// Creates a @ref ParserError and annotates it with the current position and the @@ -67,7 +66,7 @@ protected: std::shared_ptr<Scanner> m_scanner; /// The reference to the list of errors and warning to add errors/warnings during parsing - ErrorList& m_errors; + ErrorReporter& m_errorReporter; }; } diff --git a/libsolidity/parsing/Scanner.cpp b/libsolidity/parsing/Scanner.cpp index 3623f23f..fdca23ea 100644 --- a/libsolidity/parsing/Scanner.cpp +++ b/libsolidity/parsing/Scanner.cpp @@ -52,7 +52,7 @@ #include <algorithm> #include <tuple> -#include <libsolidity/interface/Utils.h> +#include <libsolidity/interface/Exceptions.h> #include <libsolidity/parsing/Scanner.h> using namespace std; @@ -758,6 +758,9 @@ Token::Value Scanner::scanNumber(char _charSeen) while (isHexDigit(m_char)) addLiteralCharAndAdvance(); } + else if (isDecimalDigit(m_char)) + // We do not allow octal numbers + return Token::Illegal; } // Parse decimal digits and allow trailing fractional part. if (kind == DECIMAL) diff --git a/libsolidity/parsing/Token.h b/libsolidity/parsing/Token.h index 3ce0f424..39c0eff9 100644 --- a/libsolidity/parsing/Token.h +++ b/libsolidity/parsing/Token.h @@ -43,7 +43,6 @@ #pragma once #include <libdevcore/Common.h> -#include <libsolidity/interface/Utils.h> #include <libsolidity/interface/Exceptions.h> #include <libdevcore/UndefMacros.h> @@ -147,7 +146,6 @@ namespace solidity K(Const, "constant", 0) \ K(Continue, "continue", 0) \ K(Contract, "contract", 0) \ - K(Default, "default", 0) \ K(Do, "do", 0) \ K(Else, "else", 0) \ K(Enum, "enum", 0) \ @@ -158,6 +156,7 @@ namespace solidity K(Hex, "hex", 0) \ K(If, "if", 0) \ K(Indexed, "indexed", 0) \ + K(Interface, "interface", 0) \ K(Internal, "internal", 0) \ K(Import, "import", 0) \ K(Is, "is", 0) \ @@ -208,7 +207,6 @@ namespace solidity T(TypesEnd, NULL, 0) /* used as type enum end marker */ \ \ /* Literals */ \ - K(NullLiteral, "null", 0) \ K(TrueLiteral, "true", 0) \ K(FalseLiteral, "false", 0) \ T(Number, NULL, 0) \ @@ -223,12 +221,13 @@ namespace solidity K(After, "after", 0) \ K(Case, "case", 0) \ K(Catch, "catch", 0) \ + K(Default, "default", 0) \ K(Final, "final", 0) \ K(In, "in", 0) \ K(Inline, "inline", 0) \ - K(Interface, "interface", 0) \ K(Let, "let", 0) \ K(Match, "match", 0) \ + K(NullLiteral, "null", 0) \ K(Of, "of", 0) \ K(Pure, "pure", 0) \ K(Relocatable, "relocatable", 0) \ |