diff options
author | Christian Parpart <christian@parpart.family> | 2018-10-23 07:50:15 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-10-23 07:50:15 +0800 |
commit | a2f5087d13274d6832669a39694ee5a3bf68f878 (patch) | |
tree | 4b6b8b3816a0a1620e73a30de687ff3557a10098 /libsolidity/parsing | |
parent | c13b5280c1b44f18a2a1fb61ef5556e91c5678e7 (diff) | |
parent | f112377dd44e8281bff092639bb546ec8a6a39ac (diff) | |
download | dexon-solidity-a2f5087d13274d6832669a39694ee5a3bf68f878.tar dexon-solidity-a2f5087d13274d6832669a39694ee5a3bf68f878.tar.gz dexon-solidity-a2f5087d13274d6832669a39694ee5a3bf68f878.tar.bz2 dexon-solidity-a2f5087d13274d6832669a39694ee5a3bf68f878.tar.lz dexon-solidity-a2f5087d13274d6832669a39694ee5a3bf68f878.tar.xz dexon-solidity-a2f5087d13274d6832669a39694ee5a3bf68f878.tar.zst dexon-solidity-a2f5087d13274d6832669a39694ee5a3bf68f878.zip |
Merge pull request #5286 from ethereum/refactor-token-as-enum-class
refactor `libsolidity::Token` into a strongly typed enum
Diffstat (limited to 'libsolidity/parsing')
-rw-r--r-- | libsolidity/parsing/Parser.cpp | 80 | ||||
-rw-r--r-- | libsolidity/parsing/ParserBase.cpp | 20 | ||||
-rw-r--r-- | libsolidity/parsing/ParserBase.h | 8 | ||||
-rw-r--r-- | libsolidity/parsing/Scanner.cpp | 32 | ||||
-rw-r--r-- | libsolidity/parsing/Scanner.h | 30 | ||||
-rw-r--r-- | libsolidity/parsing/Token.cpp | 98 | ||||
-rw-r--r-- | libsolidity/parsing/Token.h | 145 |
7 files changed, 203 insertions, 210 deletions
diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index ca9a9b57..f99b9ea4 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -112,17 +112,17 @@ ASTPointer<PragmaDirective> Parser::parsePragmaDirective() ASTNodeFactory nodeFactory(*this); expectToken(Token::Pragma); vector<string> literals; - vector<Token::Value> tokens; + vector<Token> tokens; do { - Token::Value token = m_scanner->currentToken(); + Token token = m_scanner->currentToken(); if (token == Token::Illegal) parserError("Token incompatible with Solidity parser as part of pragma directive."); else { string literal = m_scanner->currentLiteral(); - if (literal.empty() && Token::toString(token)) - literal = Token::toString(token); + if (literal.empty() && TokenTraits::toString(token)) + literal = TokenTraits::toString(token); literals.push_back(literal); tokens.push_back(token); } @@ -240,7 +240,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition() expectToken(Token::LBrace); while (true) { - Token::Value currentTokenValue = m_scanner->currentToken(); + Token currentTokenValue = m_scanner->currentToken(); if (currentTokenValue == Token::RBrace) break; else if (currentTokenValue == Token::Function || currentTokenValue == Token::Constructor) @@ -254,7 +254,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition() else if ( currentTokenValue == Token::Identifier || currentTokenValue == Token::Mapping || - Token::isElementaryTypeName(currentTokenValue) + TokenTraits::isElementaryTypeName(currentTokenValue) ) { VarDeclParserOptions options; @@ -304,7 +304,7 @@ ASTPointer<InheritanceSpecifier> Parser::parseInheritanceSpecifier() Declaration::Visibility Parser::parseVisibilitySpecifier() { Declaration::Visibility visibility(Declaration::Visibility::Default); - Token::Value token = m_scanner->currentToken(); + Token token = m_scanner->currentToken(); switch (token) { case Token::Public: @@ -329,7 +329,7 @@ Declaration::Visibility Parser::parseVisibilitySpecifier() StateMutability Parser::parseStateMutability() { StateMutability stateMutability(StateMutability::NonPayable); - Token::Value token = m_scanner->currentToken(); + Token token = m_scanner->currentToken(); switch(token) { case Token::Payable: @@ -386,7 +386,7 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _forceEmptyN result.parameters = parseParameterList(options); while (true) { - Token::Value token = m_scanner->currentToken(); + Token token = m_scanner->currentToken(); if (_allowModifiers && token == Token::Identifier) { // If the name is empty (and this is not a constructor), @@ -401,7 +401,7 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _forceEmptyN else result.modifiers.push_back(parseModifierInvocation()); } - else if (Token::isVisibilitySpecifier(token)) + else if (TokenTraits::isVisibilitySpecifier(token)) { if (result.visibility != Declaration::Visibility::Default) { @@ -423,7 +423,7 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _forceEmptyN else result.visibility = parseVisibilitySpecifier(); } - else if (Token::isStateMutabilitySpecifier(token)) + else if (TokenTraits::isStateMutabilitySpecifier(token)) { if (result.stateMutability != StateMutability::NonPayable) { @@ -587,8 +587,8 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration( while (true) { - Token::Value token = m_scanner->currentToken(); - if (_options.isStateVariable && Token::isVariableVisibilitySpecifier(token)) + Token token = m_scanner->currentToken(); + if (_options.isStateVariable && TokenTraits::isVariableVisibilitySpecifier(token)) { nodeFactory.markEndPosition(); if (visibility != Declaration::Visibility::Default) @@ -609,7 +609,7 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration( isIndexed = true; else if (token == Token::Constant) isDeclaredConst = true; - else if (_options.allowLocationSpecifier && Token::isLocationSpecifier(token)) + else if (_options.allowLocationSpecifier && TokenTraits::isLocationSpecifier(token)) { if (location != VariableDeclaration::Location::Unspecified) parserError(string("Location already specified.")); @@ -806,8 +806,8 @@ ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar) RecursionGuard recursionGuard(*this); ASTNodeFactory nodeFactory(*this); ASTPointer<TypeName> type; - Token::Value token = m_scanner->currentToken(); - if (Token::isElementaryTypeName(token)) + Token token = m_scanner->currentToken(); + if (TokenTraits::isElementaryTypeName(token)) { unsigned firstSize; unsigned secondSize; @@ -817,7 +817,7 @@ ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar) nodeFactory.markEndPosition(); m_scanner->next(); auto stateMutability = boost::make_optional(elemTypeName.token() == Token::Address, StateMutability::NonPayable); - if (Token::isStateMutabilitySpecifier(m_scanner->currentToken(), false)) + if (TokenTraits::isStateMutabilitySpecifier(m_scanner->currentToken(), false)) { if (elemTypeName.token() == Token::Address) { @@ -874,8 +874,8 @@ ASTPointer<Mapping> Parser::parseMapping() expectToken(Token::Mapping); expectToken(Token::LParen); ASTPointer<ElementaryTypeName> keyType; - Token::Value token = m_scanner->currentToken(); - if (!Token::isElementaryTypeName(token)) + Token token = m_scanner->currentToken(); + if (!TokenTraits::isElementaryTypeName(token)) fatalParserError(string("Expected elementary type name for mapping key type")); unsigned firstSize; unsigned secondSize; @@ -1252,7 +1252,7 @@ pair<Parser::LookAheadInfo, Parser::IndexAccessedPath> Parser::tryParseIndexAcce // VariableDeclarationStatement out of it. IndexAccessedPath iap = parseIndexAccessedPath(); - if (m_scanner->currentToken() == Token::Identifier || Token::isLocationSpecifier(m_scanner->currentToken())) + if (m_scanner->currentToken() == Token::Identifier || TokenTraits::isLocationSpecifier(m_scanner->currentToken())) return make_pair(LookAheadInfo::VariableDeclaration, move(iap)); else return make_pair(LookAheadInfo::Expression, move(iap)); @@ -1342,16 +1342,16 @@ ASTPointer<Expression> Parser::parseExpression( { RecursionGuard recursionGuard(*this); ASTPointer<Expression> expression = parseBinaryExpression(4, _partiallyParsedExpression); - if (Token::isAssignmentOp(m_scanner->currentToken())) + if (TokenTraits::isAssignmentOp(m_scanner->currentToken())) { - Token::Value assignmentOperator = m_scanner->currentToken(); + Token assignmentOperator = m_scanner->currentToken(); m_scanner->next(); ASTPointer<Expression> rightHandSide = parseExpression(); ASTNodeFactory nodeFactory(*this, expression); nodeFactory.setEndPositionFromNode(rightHandSide); return nodeFactory.createNode<Assignment>(expression, assignmentOperator, rightHandSide); } - else if (m_scanner->currentToken() == Token::Value::Conditional) + else if (m_scanner->currentToken() == Token::Conditional) { m_scanner->next(); ASTPointer<Expression> trueExpression = parseExpression(); @@ -1373,11 +1373,11 @@ ASTPointer<Expression> Parser::parseBinaryExpression( RecursionGuard recursionGuard(*this); ASTPointer<Expression> expression = parseUnaryExpression(_partiallyParsedExpression); ASTNodeFactory nodeFactory(*this, expression); - int precedence = Token::precedence(m_scanner->currentToken()); + int precedence = TokenTraits::precedence(m_scanner->currentToken()); for (; precedence >= _minPrecedence; --precedence) - while (Token::precedence(m_scanner->currentToken()) == precedence) + while (TokenTraits::precedence(m_scanner->currentToken()) == precedence) { - Token::Value op = m_scanner->currentToken(); + Token op = m_scanner->currentToken(); m_scanner->next(); ASTPointer<Expression> right = parseBinaryExpression(precedence + 1); nodeFactory.setEndPositionFromNode(right); @@ -1393,8 +1393,8 @@ ASTPointer<Expression> Parser::parseUnaryExpression( RecursionGuard recursionGuard(*this); ASTNodeFactory nodeFactory = _partiallyParsedExpression ? ASTNodeFactory(*this, _partiallyParsedExpression) : ASTNodeFactory(*this); - Token::Value token = m_scanner->currentToken(); - if (!_partiallyParsedExpression && (Token::isUnaryOp(token) || Token::isCountOp(token))) + Token token = m_scanner->currentToken(); + if (!_partiallyParsedExpression && (TokenTraits::isUnaryOp(token) || TokenTraits::isCountOp(token))) { // prefix expression m_scanner->next(); @@ -1407,7 +1407,7 @@ ASTPointer<Expression> Parser::parseUnaryExpression( // potential postfix expression ASTPointer<Expression> subExpression = parseLeftHandSideExpression(_partiallyParsedExpression); token = m_scanner->currentToken(); - if (!Token::isCountOp(token)) + if (!TokenTraits::isCountOp(token)) return subExpression; nodeFactory.markEndPosition(); m_scanner->next(); @@ -1482,7 +1482,7 @@ ASTPointer<Expression> Parser::parsePrimaryExpression() { RecursionGuard recursionGuard(*this); ASTNodeFactory nodeFactory(*this); - Token::Value token = m_scanner->currentToken(); + Token token = m_scanner->currentToken(); ASTPointer<Expression> expression; switch (token) @@ -1493,7 +1493,7 @@ ASTPointer<Expression> Parser::parsePrimaryExpression() expression = nodeFactory.createNode<Literal>(token, getLiteralAndAdvance()); break; case Token::Number: - if (Token::isEtherSubdenomination(m_scanner->peekNextToken())) + if (TokenTraits::isEtherSubdenomination(m_scanner->peekNextToken())) { ASTPointer<ASTString> literal = getLiteralAndAdvance(); nodeFactory.markEndPosition(); @@ -1501,7 +1501,7 @@ ASTPointer<Expression> Parser::parsePrimaryExpression() m_scanner->next(); expression = nodeFactory.createNode<Literal>(token, literal, subdenomination); } - else if (Token::isTimeSubdenomination(m_scanner->peekNextToken())) + else if (TokenTraits::isTimeSubdenomination(m_scanner->peekNextToken())) { ASTPointer<ASTString> literal = getLiteralAndAdvance(); nodeFactory.markEndPosition(); @@ -1531,7 +1531,7 @@ ASTPointer<Expression> Parser::parsePrimaryExpression() // (x,) is one-dimensional tuple, elements in arrays cannot be left out, only in tuples. m_scanner->next(); vector<ASTPointer<Expression>> components; - Token::Value oppositeToken = (token == Token::LParen ? Token::RParen : Token::RBrack); + Token oppositeToken = (token == Token::LParen ? Token::RParen : Token::RBrack); bool isArray = (token == Token::LBrack); if (m_scanner->currentToken() != oppositeToken) @@ -1558,7 +1558,7 @@ ASTPointer<Expression> Parser::parsePrimaryExpression() fatalParserError("Expected even number of hex-nibbles within double-quotes."); break; default: - if (Token::isElementaryTypeName(token)) + if (TokenTraits::isElementaryTypeName(token)) { //used for casts unsigned firstSize; @@ -1595,7 +1595,7 @@ pair<vector<ASTPointer<Expression>>, vector<ASTPointer<ASTString>>> Parser::pars { RecursionGuard recursionGuard(*this); pair<vector<ASTPointer<Expression>>, vector<ASTPointer<ASTString>>> ret; - Token::Value token = m_scanner->currentToken(); + Token token = m_scanner->currentToken(); if (token == Token::LBrace) { // call({arg1 : 1, arg2 : 2 }) @@ -1638,21 +1638,21 @@ Parser::LookAheadInfo Parser::peekStatementType() const // or a mutability specifier, we also have a variable declaration. // If we get an identifier followed by a "[" or ".", it can be both ("lib.type[9] a;" or "variable.el[9] = 7;"). // In all other cases, we have an expression statement. - Token::Value token(m_scanner->currentToken()); - bool mightBeTypeName = (Token::isElementaryTypeName(token) || token == Token::Identifier); + Token token(m_scanner->currentToken()); + bool mightBeTypeName = (TokenTraits::isElementaryTypeName(token) || token == Token::Identifier); if (token == Token::Mapping || token == Token::Function || token == Token::Var) return LookAheadInfo::VariableDeclaration; if (mightBeTypeName) { - Token::Value next = m_scanner->peekNextToken(); + Token next = m_scanner->peekNextToken(); // So far we only allow ``address payable`` in variable declaration statements and in no other // kind of statement. This means, for example, that we do not allow type expressions of the form // ``address payable;``. // If we want to change this in the future, we need to consider another scanner token here. - if (Token::isElementaryTypeName(token) && Token::isStateMutabilitySpecifier(next, false)) + if (TokenTraits::isElementaryTypeName(token) && TokenTraits::isStateMutabilitySpecifier(next, false)) return LookAheadInfo::VariableDeclaration; - if (next == Token::Identifier || Token::isLocationSpecifier(next)) + if (next == Token::Identifier || TokenTraits::isLocationSpecifier(next)) return LookAheadInfo::VariableDeclaration; if (next == Token::LBrack || next == Token::Period) return LookAheadInfo::IndexAccessStructure; diff --git a/libsolidity/parsing/ParserBase.cpp b/libsolidity/parsing/ParserBase.cpp index 71133746..1d4cb1e2 100644 --- a/libsolidity/parsing/ParserBase.cpp +++ b/libsolidity/parsing/ParserBase.cpp @@ -43,12 +43,12 @@ int ParserBase::endPosition() const return m_scanner->currentLocation().end; } -Token::Value ParserBase::currentToken() const +Token ParserBase::currentToken() const { return m_scanner->currentToken(); } -Token::Value ParserBase::peekNextToken() const +Token ParserBase::peekNextToken() const { return m_scanner->peekNextToken(); } @@ -58,31 +58,31 @@ std::string ParserBase::currentLiteral() const return m_scanner->currentLiteral(); } -Token::Value ParserBase::advance() +Token ParserBase::advance() { return m_scanner->next(); } -void ParserBase::expectToken(Token::Value _value, bool _advance) +void ParserBase::expectToken(Token _value, bool _advance) { - Token::Value tok = m_scanner->currentToken(); + Token tok = m_scanner->currentToken(); if (tok != _value) { - auto tokenName = [this](Token::Value _token) + auto tokenName = [this](Token _token) { if (_token == Token::Identifier) return string("identifier"); else if (_token == Token::EOS) return string("end of source"); - else if (Token::isReservedKeyword(_token)) - return string("reserved keyword '") + Token::friendlyName(_token) + "'"; - else if (Token::isElementaryTypeName(_token)) //for the sake of accuracy in reporting + else if (TokenTraits::isReservedKeyword(_token)) + return string("reserved keyword '") + TokenTraits::friendlyName(_token) + "'"; + else if (TokenTraits::isElementaryTypeName(_token)) //for the sake of accuracy in reporting { ElementaryTypeNameToken elemTypeName = m_scanner->currentElementaryTypeNameToken(); return string("'") + elemTypeName.toString() + "'"; } else - return string("'") + Token::friendlyName(_token) + "'"; + return string("'") + TokenTraits::friendlyName(_token) + "'"; }; fatalParserError(string("Expected ") + tokenName(_value) + string(" but got ") + tokenName(tok)); diff --git a/libsolidity/parsing/ParserBase.h b/libsolidity/parsing/ParserBase.h index b28e1b1b..e01f37d8 100644 --- a/libsolidity/parsing/ParserBase.h +++ b/libsolidity/parsing/ParserBase.h @@ -63,11 +63,11 @@ protected: ///@{ ///@name Helper functions /// If current token value is not _value, throw exception otherwise advance token. - void expectToken(Token::Value _value, bool _advance = true); - Token::Value currentToken() const; - Token::Value peekNextToken() const; + void expectToken(Token _value, bool _advance = true); + Token currentToken() const; + Token peekNextToken() const; std::string currentLiteral() const; - Token::Value advance(); + Token advance(); ///@} /// Increases the recursion depth and throws an exception if it is too deep. diff --git a/libsolidity/parsing/Scanner.cpp b/libsolidity/parsing/Scanner.cpp index 87d7c535..e9dad2ad 100644 --- a/libsolidity/parsing/Scanner.cpp +++ b/libsolidity/parsing/Scanner.cpp @@ -214,9 +214,9 @@ void Scanner::addUnicodeAsUTF8(unsigned codepoint) } // Ensure that tokens can be stored in a byte. -BOOST_STATIC_ASSERT(Token::NUM_TOKENS <= 0x100); +BOOST_STATIC_ASSERT(TokenTraits::count() <= 0x100); -Token::Value Scanner::next() +Token Scanner::next() { m_currentToken = m_nextToken; m_skippedComment = m_nextSkippedComment; @@ -225,7 +225,7 @@ Token::Value Scanner::next() return m_currentToken.token; } -Token::Value Scanner::selectToken(char _next, Token::Value _then, Token::Value _else) +Token Scanner::selectToken(char _next, Token _then, Token _else) { advance(); if (m_char == _next) @@ -249,7 +249,7 @@ void Scanner::skipWhitespaceExceptUnicodeLinebreak() advance(); } -Token::Value Scanner::skipSingleLineComment() +Token Scanner::skipSingleLineComment() { // Line terminator is not part of the comment. If it is a // non-ascii line terminator, it will result in a parser error. @@ -259,7 +259,7 @@ Token::Value Scanner::skipSingleLineComment() return Token::Whitespace; } -Token::Value Scanner::scanSingleLineDocComment() +Token Scanner::scanSingleLineDocComment() { LiteralScope literal(this, LITERAL_TYPE_COMMENT); advance(); //consume the last '/' at /// @@ -295,7 +295,7 @@ Token::Value Scanner::scanSingleLineDocComment() return Token::CommentLiteral; } -Token::Value Scanner::skipMultiLineComment() +Token Scanner::skipMultiLineComment() { advance(); while (!isSourcePastEndOfInput()) @@ -316,7 +316,7 @@ Token::Value Scanner::skipMultiLineComment() return Token::Illegal; } -Token::Value Scanner::scanMultiLineDocComment() +Token Scanner::scanMultiLineDocComment() { LiteralScope literal(this, LITERAL_TYPE_COMMENT); bool endFound = false; @@ -369,7 +369,7 @@ Token::Value Scanner::scanMultiLineDocComment() return Token::CommentLiteral; } -Token::Value Scanner::scanSlash() +Token Scanner::scanSlash() { int firstSlashPosition = sourcePos(); advance(); @@ -380,7 +380,7 @@ Token::Value Scanner::scanSlash() else if (m_char == '/') { // doxygen style /// comment - Token::Value comment; + Token comment; m_nextSkippedComment.location.start = firstSlashPosition; comment = scanSingleLineDocComment(); m_nextSkippedComment.location.end = sourcePos(); @@ -406,7 +406,7 @@ Token::Value Scanner::scanSlash() return Token::Whitespace; } // we actually have a multiline documentation comment - Token::Value comment; + Token comment; m_nextSkippedComment.location.start = firstSlashPosition; comment = scanMultiLineDocComment(); m_nextSkippedComment.location.end = sourcePos(); @@ -432,7 +432,7 @@ void Scanner::scanToken() m_nextSkippedComment.literal.clear(); m_nextSkippedComment.extendedTokenInfo = make_tuple(0, 0); - Token::Value token; + Token token; // M and N are for the purposes of grabbing different type sizes unsigned m; unsigned n; @@ -703,7 +703,7 @@ bool Scanner::isUnicodeLinebreak() return false; } -Token::Value Scanner::scanString() +Token Scanner::scanString() { char const quote = m_char; advance(); // consume quote @@ -727,7 +727,7 @@ Token::Value Scanner::scanString() return Token::StringLiteral; } -Token::Value Scanner::scanHexString() +Token Scanner::scanHexString() { char const quote = m_char; advance(); // consume quote @@ -760,7 +760,7 @@ void Scanner::scanDecimalDigits() // Defer further validation of underscore to SyntaxChecker. } -Token::Value Scanner::scanNumber(char _charSeen) +Token Scanner::scanNumber(char _charSeen) { enum { DECIMAL, HEX, BINARY } kind = DECIMAL; LiteralScope literal(this, LITERAL_TYPE_NUMBER); @@ -854,7 +854,7 @@ Token::Value Scanner::scanNumber(char _charSeen) return Token::Number; } -tuple<Token::Value, unsigned, unsigned> Scanner::scanIdentifierOrKeyword() +tuple<Token, unsigned, unsigned> Scanner::scanIdentifierOrKeyword() { solAssert(isIdentifierStart(m_char), ""); LiteralScope literal(this, LITERAL_TYPE_STRING); @@ -863,7 +863,7 @@ tuple<Token::Value, unsigned, unsigned> Scanner::scanIdentifierOrKeyword() while (isIdentifierPart(m_char)) //get full literal addLiteralCharAndAdvance(); literal.complete(); - return Token::fromIdentifierOrKeyword(m_nextToken.literal); + return TokenTraits::fromIdentifierOrKeyword(m_nextToken.literal); } char CharStream::advanceAndGet(size_t _chars) diff --git a/libsolidity/parsing/Scanner.h b/libsolidity/parsing/Scanner.h index 7564c788..02e0553f 100644 --- a/libsolidity/parsing/Scanner.h +++ b/libsolidity/parsing/Scanner.h @@ -112,13 +112,13 @@ public: void reset(); /// @returns the next token and advances input - Token::Value next(); + Token next(); ///@{ ///@name Information about the current token /// @returns the current token - Token::Value currentToken() const + Token currentToken() const { return m_currentToken.token; } @@ -149,7 +149,7 @@ public: ///@name Information about the next token /// @returns the next token without advancing input. - Token::Value peekNextToken() const { return m_nextToken.token; } + Token peekNextToken() const { return m_nextToken.token; } SourceLocation peekLocation() const { return m_nextToken.location; } std::string const& peekLiteral() const { return m_nextToken.literal; } ///@} @@ -168,7 +168,7 @@ private: /// Used for the current and look-ahead token and comments struct TokenDesc { - Token::Value token; + Token token; SourceLocation location; std::string literal; std::tuple<unsigned, unsigned> extendedTokenInfo; @@ -185,9 +185,9 @@ private: bool advance() { m_char = m_source.advanceAndGet(); return !m_source.isPastEndOfInput(); } void rollback(int _amount) { m_char = m_source.rollback(_amount); } - inline Token::Value selectToken(Token::Value _tok) { advance(); return _tok; } + inline Token selectToken(Token _tok) { advance(); return _tok; } /// If the next character is _next, advance and return _then, otherwise return _else. - inline Token::Value selectToken(char _next, Token::Value _then, Token::Value _else); + inline Token selectToken(char _next, Token _then, Token _else); bool scanHexByte(char& o_scannedByte); bool scanUnicode(unsigned& o_codepoint); @@ -199,19 +199,19 @@ private: bool skipWhitespace(); /// Skips all whitespace that are neither '\r' nor '\n'. void skipWhitespaceExceptUnicodeLinebreak(); - Token::Value skipSingleLineComment(); - Token::Value skipMultiLineComment(); + Token skipSingleLineComment(); + Token skipMultiLineComment(); void scanDecimalDigits(); - Token::Value scanNumber(char _charSeen = 0); - std::tuple<Token::Value, unsigned, unsigned> scanIdentifierOrKeyword(); + Token scanNumber(char _charSeen = 0); + std::tuple<Token, unsigned, unsigned> scanIdentifierOrKeyword(); - Token::Value scanString(); - Token::Value scanHexString(); - Token::Value scanSingleLineDocComment(); - Token::Value scanMultiLineDocComment(); + Token scanString(); + Token scanHexString(); + Token scanSingleLineDocComment(); + Token scanMultiLineDocComment(); /// Scans a slash '/' and depending on the characters returns the appropriate token - Token::Value scanSlash(); + Token scanSlash(); /// Scans an escape-sequence which is part of a string and adds the /// decoded character to the current literal. Returns true if a pattern diff --git a/libsolidity/parsing/Token.cpp b/libsolidity/parsing/Token.cpp index 27acb7d4..dccd9037 100644 --- a/libsolidity/parsing/Token.cpp +++ b/libsolidity/parsing/Token.cpp @@ -51,9 +51,9 @@ namespace dev namespace solidity { -void ElementaryTypeNameToken::assertDetails(Token::Value _baseType, unsigned const& _first, unsigned const& _second) +void ElementaryTypeNameToken::assertDetails(Token _baseType, unsigned const& _first, unsigned const& _second) { - solAssert(Token::isElementaryTypeName(_baseType), "Expected elementary type name: " + string(Token::toString(_baseType))); + solAssert(TokenTraits::isElementaryTypeName(_baseType), "Expected elementary type name: " + string(TokenTraits::toString(_baseType))); if (_baseType == Token::BytesM) { solAssert(_second == 0, "There should not be a second size argument to type bytesM."); @@ -61,17 +61,17 @@ void ElementaryTypeNameToken::assertDetails(Token::Value _baseType, unsigned con } else if (_baseType == Token::UIntM || _baseType == Token::IntM) { - solAssert(_second == 0, "There should not be a second size argument to type " + string(Token::toString(_baseType)) + "."); + solAssert(_second == 0, "There should not be a second size argument to type " + string(TokenTraits::toString(_baseType)) + "."); solAssert( _first <= 256 && _first % 8 == 0, - "No elementary type " + string(Token::toString(_baseType)) + to_string(_first) + "." + "No elementary type " + string(TokenTraits::toString(_baseType)) + to_string(_first) + "." ); } else if (_baseType == Token::UFixedMxN || _baseType == Token::FixedMxN) { solAssert( _first >= 8 && _first <= 256 && _first % 8 == 0 && _second <= 80, - "No elementary type " + string(Token::toString(_baseType)) + to_string(_first) + "x" + to_string(_second) + "." + "No elementary type " + string(TokenTraits::toString(_baseType)) + to_string(_first) + "x" + to_string(_second) + "." ); } m_token = _baseType; @@ -79,38 +79,54 @@ void ElementaryTypeNameToken::assertDetails(Token::Value _baseType, unsigned con m_secondNumber = _second; } -#define T(name, string, precedence) #name, -char const* const Token::m_name[NUM_TOKENS] = +namespace TokenTraits { - TOKEN_LIST(T, T) -}; -#undef T +char const* toString(Token tok) +{ + switch (tok) + { +#define T(name, string, precedence) case Token::name: return string; + TOKEN_LIST(T, T) +#undef T + default: // Token::NUM_TOKENS: + return ""; + } +} -#define T(name, string, precedence) string, -char const* const Token::m_string[NUM_TOKENS] = +char const* name(Token tok) { - TOKEN_LIST(T, T) -}; +#define T(name, string, precedence) #name, + static char const* const names[TokenTraits::count()] = { TOKEN_LIST(T, T) }; #undef T + solAssert(static_cast<size_t>(tok) < TokenTraits::count(), ""); + return names[static_cast<size_t>(tok)]; +} -#define T(name, string, precedence) precedence, -int8_t const Token::m_precedence[NUM_TOKENS] = +std::string friendlyName(Token tok) { - TOKEN_LIST(T, T) -}; -#undef T + char const* ret = toString(tok); + if (ret) + return std::string(ret); + ret = name(tok); + solAssert(ret != nullptr, ""); + return std::string(ret); +} -#define KT(a, b, c) 'T', -#define KK(a, b, c) 'K', -char const Token::m_tokenType[] = +#define T(name, string, precedence) precedence, +int precedence(Token tok) { - TOKEN_LIST(KT, KK) -}; + int8_t const static precs[TokenTraits::count()] = + { + TOKEN_LIST(T, T) + }; + return precs[static_cast<size_t>(tok)]; +} +#undef T -int Token::parseSize(string::const_iterator _begin, string::const_iterator _end) +int parseSize(string::const_iterator _begin, string::const_iterator _end) { try { @@ -123,7 +139,20 @@ int Token::parseSize(string::const_iterator _begin, string::const_iterator _end) } } -tuple<Token::Value, unsigned int, unsigned int> Token::fromIdentifierOrKeyword(string const& _literal) +static Token keywordByName(string const& _name) +{ + // The following macros are used inside TOKEN_LIST and cause non-keyword tokens to be ignored + // and keywords to be put inside the keywords variable. +#define KEYWORD(name, string, precedence) {string, Token::name}, +#define TOKEN(name, string, precedence) + static const map<string, Token> keywords({TOKEN_LIST(TOKEN, KEYWORD)}); +#undef KEYWORD +#undef TOKEN + auto it = keywords.find(_name); + return it == keywords.end() ? Token::Identifier : it->second; +} + +tuple<Token, unsigned int, unsigned int> fromIdentifierOrKeyword(string const& _literal) { auto positionM = find_if(_literal.begin(), _literal.end(), ::isdigit); if (positionM != _literal.end()) @@ -131,7 +160,7 @@ tuple<Token::Value, unsigned int, unsigned int> Token::fromIdentifierOrKeyword(s string baseType(_literal.begin(), positionM); auto positionX = find_if_not(positionM, _literal.end(), ::isdigit); int m = parseSize(positionM, positionX); - Token::Value keyword = keywordByName(baseType); + Token keyword = keywordByName(baseType); if (keyword == Token::Bytes) { if (0 < m && m <= 32 && positionX == _literal.end()) @@ -172,20 +201,7 @@ tuple<Token::Value, unsigned int, unsigned int> Token::fromIdentifierOrKeyword(s return make_tuple(keywordByName(_literal), 0, 0); } -Token::Value Token::keywordByName(string const& _name) -{ - // The following macros are used inside TOKEN_LIST and cause non-keyword tokens to be ignored - // and keywords to be put inside the keywords variable. -#define KEYWORD(name, string, precedence) {string, Token::name}, -#define TOKEN(name, string, precedence) - static const map<string, Token::Value> keywords({TOKEN_LIST(TOKEN, KEYWORD)}); -#undef KEYWORD -#undef TOKEN - auto it = keywords.find(_name); - return it == keywords.end() ? Token::Identifier : it->second; -} -#undef KT -#undef KK +} } } diff --git a/libsolidity/parsing/Token.h b/libsolidity/parsing/Token.h index 8ecc850a..81e8dd98 100644 --- a/libsolidity/parsing/Token.h +++ b/libsolidity/parsing/Token.h @@ -45,6 +45,7 @@ #include <libdevcore/Common.h> #include <libsolidity/interface/Exceptions.h> #include <libsolidity/parsing/UndefMacros.h> +#include <iosfwd> namespace dev { @@ -267,119 +268,95 @@ namespace solidity /* Scanner-internal use only. */ \ T(Whitespace, NULL, 0) - -class Token -{ -public: - // All token values. - // attention! msvc issue: - // http://stackoverflow.com/questions/9567868/compile-errors-after-adding-v8-to-my-project-c2143-c2059 - // @todo: avoid TOKEN_LIST macro +// All token values. +// attention! msvc issue: +// http://stackoverflow.com/questions/9567868/compile-errors-after-adding-v8-to-my-project-c2143-c2059 +// @todo: avoid TOKEN_LIST macro +enum class Token : unsigned int { #define T(name, string, precedence) name, - enum Value - { - TOKEN_LIST(T, T) - NUM_TOKENS - }; + TOKEN_LIST(T, T) + NUM_TOKENS #undef T +}; - // @returns a string corresponding to the C++ token name - // (e.g. "LT" for the token LT). - static char const* name(Value tok) - { - solAssert(tok < NUM_TOKENS, ""); - return m_name[tok]; - } +namespace TokenTraits +{ + constexpr size_t count() { return static_cast<size_t>(Token::NUM_TOKENS); } // Predicates - static bool isElementaryTypeName(Value tok) { return Int <= tok && tok < TypesEnd; } - static bool isAssignmentOp(Value tok) { return Assign <= tok && tok <= AssignMod; } - static bool isBinaryOp(Value op) { return Comma <= op && op <= Exp; } - static bool isCommutativeOp(Value op) { return op == BitOr || op == BitXor || op == BitAnd || - op == Add || op == Mul || op == Equal || op == NotEqual; } - static bool isArithmeticOp(Value op) { return Add <= op && op <= Exp; } - static bool isCompareOp(Value op) { return Equal <= op && op <= GreaterThanOrEqual; } + constexpr bool isElementaryTypeName(Token tok) { return Token::Int <= tok && tok < Token::TypesEnd; } + constexpr bool isAssignmentOp(Token tok) { return Token::Assign <= tok && tok <= Token::AssignMod; } + constexpr bool isBinaryOp(Token op) { return Token::Comma <= op && op <= Token::Exp; } + constexpr bool isCommutativeOp(Token op) { return op == Token::BitOr || op == Token::BitXor || op == Token::BitAnd || + op == Token::Add || op == Token::Mul || op == Token::Equal || op == Token::NotEqual; } + constexpr bool isArithmeticOp(Token op) { return Token::Add <= op && op <= Token::Exp; } + constexpr bool isCompareOp(Token op) { return Token::Equal <= op && op <= Token::GreaterThanOrEqual; } - static Value AssignmentToBinaryOp(Value op) - { - solAssert(isAssignmentOp(op) && op != Assign, ""); - return Value(op + (BitOr - AssignBitOr)); - } + constexpr bool isBitOp(Token op) { return (Token::BitOr <= op && op <= Token::BitAnd) || op == Token::BitNot; } + constexpr bool isBooleanOp(Token op) { return (Token::Or <= op && op <= Token::And) || op == Token::Not; } + constexpr bool isUnaryOp(Token op) { return (Token::Not <= op && op <= Token::Delete) || op == Token::Add || op == Token::Sub; } + constexpr bool isCountOp(Token op) { return op == Token::Inc || op == Token::Dec; } + constexpr bool isShiftOp(Token op) { return (Token::SHL <= op) && (op <= Token::SHR); } + constexpr bool isVariableVisibilitySpecifier(Token op) { return op == Token::Public || op == Token::Private || op == Token::Internal; } + constexpr bool isVisibilitySpecifier(Token op) { return isVariableVisibilitySpecifier(op) || op == Token::External; } + constexpr bool isLocationSpecifier(Token op) { return op == Token::Memory || op == Token::Storage || op == Token::CallData; } - static bool isBitOp(Value op) { return (BitOr <= op && op <= BitAnd) || op == BitNot; } - static bool isBooleanOp(Value op) { return (Or <= op && op <= And) || op == Not; } - static bool isUnaryOp(Value op) { return (Not <= op && op <= Delete) || op == Add || op == Sub; } - static bool isCountOp(Value op) { return op == Inc || op == Dec; } - static bool isShiftOp(Value op) { return (SHL <= op) && (op <= SHR); } - static bool isVisibilitySpecifier(Value op) { return isVariableVisibilitySpecifier(op) || op == External; } - static bool isVariableVisibilitySpecifier(Value op) { return op == Public || op == Private || op == Internal; } - static bool isLocationSpecifier(Value op) { return op == Memory || op == Storage || op == CallData; } - static bool isStateMutabilitySpecifier(Value op, bool _allowConstant = true) + constexpr bool isStateMutabilitySpecifier(Token op, bool _allowConstant = true) { - if (op == Constant && _allowConstant) - return true; - return op == Pure || op == View || op == Payable; + return (op == Token::Constant && _allowConstant) + || op == Token::Pure || op == Token::View || op == Token::Payable; } - static bool isEtherSubdenomination(Value op) { return op == SubWei || op == SubSzabo || op == SubFinney || op == SubEther; } - static bool isTimeSubdenomination(Value op) { return op == SubSecond || op == SubMinute || op == SubHour || op == SubDay || op == SubWeek || op == SubYear; } - static bool isReservedKeyword(Value op) { return (Abstract <= op && op <= Unchecked); } - // @returns a string corresponding to the JS token string - // (.e., "<" for the token LT) or NULL if the token doesn't - // have a (unique) string (e.g. an IDENTIFIER). - static char const* toString(Value tok) - { - solAssert(tok < NUM_TOKENS, ""); - return m_string[tok]; - } + constexpr bool isEtherSubdenomination(Token op) { return op == Token::SubWei || op == Token::SubSzabo || op == Token::SubFinney || op == Token::SubEther; } + constexpr bool isTimeSubdenomination(Token op) { return op == Token::SubSecond || op == Token::SubMinute || op == Token::SubHour || op == Token::SubDay || op == Token::SubWeek || op == Token::SubYear; } + constexpr bool isReservedKeyword(Token op) { return (Token::Abstract <= op && op <= Token::Unchecked); } - static std::string friendlyName(Value tok) + inline Token AssignmentToBinaryOp(Token op) { - char const* ret = toString(tok); - if (ret == nullptr) - { - ret = name(tok); - solAssert(ret != nullptr, ""); - } - return std::string(ret); + solAssert(isAssignmentOp(op) && op != Token::Assign, ""); + return static_cast<Token>(static_cast<int>(op) + (static_cast<int>(Token::BitOr) - static_cast<int>(Token::AssignBitOr))); } // @returns the precedence > 0 for binary and compare // operators; returns 0 otherwise. - static int precedence(Value tok) - { - solAssert(tok < NUM_TOKENS, ""); - return m_precedence[tok]; - } + int precedence(Token tok); - static std::tuple<Token::Value, unsigned int, unsigned int> fromIdentifierOrKeyword(std::string const& _literal); + std::tuple<Token, unsigned int, unsigned int> fromIdentifierOrKeyword(std::string const& _literal); -private: - // @returns -1 on error (invalid digit or number too large) - static int parseSize(std::string::const_iterator _begin, std::string::const_iterator _end); - // @returns the keyword with name @a _name or Token::Identifier of no such keyword exists. - static Token::Value keywordByName(std::string const& _name); - static char const* const m_name[NUM_TOKENS]; - static char const* const m_string[NUM_TOKENS]; - static int8_t const m_precedence[NUM_TOKENS]; - static char const m_tokenType[NUM_TOKENS]; -}; + // @returns a string corresponding to the C++ token name + // (e.g. "LT" for the token LT). + char const* name(Token tok); + + // @returns a string corresponding to the JS token string + // (.e., "<" for the token LT) or NULL if the token doesn't + // have a (unique) string (e.g. an IDENTIFIER). + char const* toString(Token tok); + + std::string friendlyName(Token tok); +} + +inline std::ostream& operator<<(std::ostream& os, Token token) +{ + os << TokenTraits::friendlyName(token); + return os; +} class ElementaryTypeNameToken { public: - ElementaryTypeNameToken(Token::Value _token, unsigned const& _firstNumber, unsigned const& _secondNumber) + ElementaryTypeNameToken(Token _token, unsigned const& _firstNumber, unsigned const& _secondNumber) { assertDetails(_token, _firstNumber, _secondNumber); } unsigned int firstNumber() const { return m_firstNumber; } unsigned int secondNumber() const { return m_secondNumber; } - Token::Value token() const { return m_token; } + Token token() const { return m_token; } + ///if tokValue is set to true, then returns the actual token type name, otherwise, returns full type std::string toString(bool const& tokenValue = false) const { - std::string name = Token::toString(m_token); + std::string name = TokenTraits::toString(m_token); if (tokenValue || (firstNumber() == 0 && secondNumber() == 0)) return name; solAssert(name.size() >= 3, "Token name size should be greater than 3. Should not reach here."); @@ -390,11 +367,11 @@ public: } private: - Token::Value m_token; + Token m_token; unsigned int m_firstNumber; unsigned int m_secondNumber; /// throws if type is not properly sized - void assertDetails(Token::Value _baseType, unsigned const& _first, unsigned const& _second); + void assertDetails(Token _baseType, unsigned const& _first, unsigned const& _second); }; } |