diff options
author | Christian Parpart <christian@ethereum.org> | 2018-11-14 21:59:30 +0800 |
---|---|---|
committer | Alex Beregszaszi <alex@rtfs.hu> | 2018-11-22 02:58:12 +0800 |
commit | 87821c53c3a73d3e35a0e50a7c159d9aa5d6b253 (patch) | |
tree | d0335db1bfe77f91168e14599e943105b7c9a2c3 /libsolidity/parsing | |
parent | d47707abaddfd6820d8ff1f9ec5ec0d2a61ee622 (diff) | |
download | dexon-solidity-87821c53c3a73d3e35a0e50a7c159d9aa5d6b253.tar.gz dexon-solidity-87821c53c3a73d3e35a0e50a7c159d9aa5d6b253.tar.zst dexon-solidity-87821c53c3a73d3e35a0e50a7c159d9aa5d6b253.zip |
Isolating files shared between Yul- and Solidity language frontend.
Diffstat (limited to 'libsolidity/parsing')
-rw-r--r-- | libsolidity/parsing/DocStringParser.cpp | 4 | ||||
-rw-r--r-- | libsolidity/parsing/Parser.cpp | 6 | ||||
-rw-r--r-- | libsolidity/parsing/Parser.h | 2 | ||||
-rw-r--r-- | libsolidity/parsing/ParserBase.cpp | 115 | ||||
-rw-r--r-- | libsolidity/parsing/ParserBase.h | 93 | ||||
-rw-r--r-- | libsolidity/parsing/Scanner.cpp | 920 | ||||
-rw-r--r-- | libsolidity/parsing/Scanner.h | 249 | ||||
-rw-r--r-- | libsolidity/parsing/Token.cpp | 207 | ||||
-rw-r--r-- | libsolidity/parsing/Token.h | 378 | ||||
-rw-r--r-- | libsolidity/parsing/UndefMacros.h | 46 |
10 files changed, 6 insertions, 2014 deletions
diff --git a/libsolidity/parsing/DocStringParser.cpp b/libsolidity/parsing/DocStringParser.cpp index d9588e5c..17a7b691 100644 --- a/libsolidity/parsing/DocStringParser.cpp +++ b/libsolidity/parsing/DocStringParser.cpp @@ -1,7 +1,7 @@ #include <libsolidity/parsing/DocStringParser.h> -#include <libsolidity/interface/ErrorReporter.h> -#include <libsolidity/interface/Exceptions.h> +#include <liblangutil/ErrorReporter.h> +#include <liblangutil/Exceptions.h> #include <boost/range/irange.hpp> #include <boost/range/algorithm.hpp> diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index b17dad9a..f070620d 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -22,11 +22,11 @@ #include <cctype> #include <vector> -#include <libevmasm/SourceLocation.h> +#include <liblangutil/SourceLocation.h> #include <libsolidity/parsing/Parser.h> -#include <libsolidity/parsing/Scanner.h> +#include <liblangutil/Scanner.h> #include <libsolidity/inlineasm/AsmParser.h> -#include <libsolidity/interface/ErrorReporter.h> +#include <liblangutil/ErrorReporter.h> using namespace std; diff --git a/libsolidity/parsing/Parser.h b/libsolidity/parsing/Parser.h index fa974171..f20f01c5 100644 --- a/libsolidity/parsing/Parser.h +++ b/libsolidity/parsing/Parser.h @@ -23,7 +23,7 @@ #pragma once #include <libsolidity/ast/AST.h> -#include <libsolidity/parsing/ParserBase.h> +#include <liblangutil/ParserBase.h> namespace dev { diff --git a/libsolidity/parsing/ParserBase.cpp b/libsolidity/parsing/ParserBase.cpp deleted file mode 100644 index 1d4cb1e2..00000000 --- a/libsolidity/parsing/ParserBase.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* - This file is part of solidity. - - solidity 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. - - solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>. -*/ -/** - * @author Christian <c@ethdev.com> - * @date 2016 - * Solidity parser shared functionality. - */ - -#include <libsolidity/parsing/ParserBase.h> -#include <libsolidity/parsing/Scanner.h> -#include <libsolidity/interface/ErrorReporter.h> - -using namespace std; -using namespace dev; -using namespace dev::solidity; - -std::shared_ptr<string const> const& ParserBase::sourceName() const -{ - return m_scanner->sourceName(); -} - -int ParserBase::position() const -{ - return m_scanner->currentLocation().start; -} - -int ParserBase::endPosition() const -{ - return m_scanner->currentLocation().end; -} - -Token ParserBase::currentToken() const -{ - return m_scanner->currentToken(); -} - -Token ParserBase::peekNextToken() const -{ - return m_scanner->peekNextToken(); -} - -std::string ParserBase::currentLiteral() const -{ - return m_scanner->currentLiteral(); -} - -Token ParserBase::advance() -{ - return m_scanner->next(); -} - -void ParserBase::expectToken(Token _value, bool _advance) -{ - Token tok = m_scanner->currentToken(); - if (tok != _value) - { - auto tokenName = [this](Token _token) - { - if (_token == Token::Identifier) - return string("identifier"); - else if (_token == Token::EOS) - return string("end of source"); - 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("'") + TokenTraits::friendlyName(_token) + "'"; - }; - - fatalParserError(string("Expected ") + tokenName(_value) + string(" but got ") + tokenName(tok)); - } - if (_advance) - m_scanner->next(); -} - -void ParserBase::increaseRecursionDepth() -{ - m_recursionDepth++; - if (m_recursionDepth >= 2560) - fatalParserError("Maximum recursion depth reached during parsing."); -} - -void ParserBase::decreaseRecursionDepth() -{ - solAssert(m_recursionDepth > 0, ""); - m_recursionDepth--; -} - -void ParserBase::parserError(string const& _description) -{ - m_errorReporter.parserError(SourceLocation(position(), endPosition(), sourceName()), _description); -} - -void ParserBase::fatalParserError(string const& _description) -{ - m_errorReporter.fatalParserError(SourceLocation(position(), endPosition(), sourceName()), _description); -} diff --git a/libsolidity/parsing/ParserBase.h b/libsolidity/parsing/ParserBase.h deleted file mode 100644 index e01f37d8..00000000 --- a/libsolidity/parsing/ParserBase.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - This file is part of solidity. - - solidity 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. - - solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>. -*/ -/** - * @author Christian <c@ethdev.com> - * @date 2016 - * Solidity parser shared functionality. - */ - -#pragma once - -#include <memory> -#include <libsolidity/parsing/Token.h> - -namespace dev -{ -namespace solidity -{ - -class ErrorReporter; -class Scanner; - -class ParserBase -{ -public: - explicit ParserBase(ErrorReporter& errorReporter): m_errorReporter(errorReporter) {} - - std::shared_ptr<std::string const> const& sourceName() const; - -protected: - /// Utility class that creates an error and throws an exception if the - /// recursion depth is too deep. - class RecursionGuard - { - public: - explicit RecursionGuard(ParserBase& _parser): m_parser(_parser) - { - m_parser.increaseRecursionDepth(); - } - ~RecursionGuard() { m_parser.decreaseRecursionDepth(); } - private: - ParserBase& m_parser; - }; - - /// Start position of the current token - int position() const; - /// 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, bool _advance = true); - Token currentToken() const; - Token peekNextToken() const; - std::string currentLiteral() const; - Token advance(); - ///@} - - /// Increases the recursion depth and throws an exception if it is too deep. - void increaseRecursionDepth(); - void decreaseRecursionDepth(); - - /// Creates a @ref ParserError and annotates it with the current position and the - /// given @a _description. - void parserError(std::string const& _description); - - /// Creates a @ref ParserError and annotates it with the current position and the - /// given @a _description. Throws the FatalError. - void fatalParserError(std::string const& _description); - - std::shared_ptr<Scanner> m_scanner; - /// The reference to the list of errors and warning to add errors/warnings during parsing - ErrorReporter& m_errorReporter; - /// Current recursion depth during parsing. - size_t m_recursionDepth = 0; -}; - -} -} diff --git a/libsolidity/parsing/Scanner.cpp b/libsolidity/parsing/Scanner.cpp deleted file mode 100644 index e9dad2ad..00000000 --- a/libsolidity/parsing/Scanner.cpp +++ /dev/null @@ -1,920 +0,0 @@ -/* - This file is part of solidity. - - solidity 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. - - solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>. - - This file is derived from the file "scanner.cc", which was part of the - V8 project. The original copyright header follows: - - Copyright 2006-2012, the V8 project authors. All rights reserved. - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -/** - * @author Christian <c@ethdev.com> - * @date 2014 - * Solidity scanner. - */ - -#include <algorithm> -#include <tuple> -#include <libsolidity/interface/Exceptions.h> -#include <libsolidity/parsing/Scanner.h> - -using namespace std; - -namespace dev -{ -namespace solidity -{ - -namespace -{ -bool isDecimalDigit(char c) -{ - return '0' <= c && c <= '9'; -} -bool isHexDigit(char c) -{ - return isDecimalDigit(c) - || ('a' <= c && c <= 'f') - || ('A' <= c && c <= 'F'); -} -bool isLineTerminator(char c) -{ - return c == '\n'; -} -bool isWhiteSpace(char c) -{ - return c == ' ' || c == '\n' || c == '\t' || c == '\r'; -} -bool isIdentifierStart(char c) -{ - return c == '_' || c == '$' || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); -} -bool isIdentifierPart(char c) -{ - return isIdentifierStart(c) || isDecimalDigit(c); -} -int hexValue(char c) -{ - if (c >= '0' && c <= '9') - return c - '0'; - else if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - else return -1; -} -} // end anonymous namespace - - - -/// Scoped helper for literal recording. Automatically drops the literal -/// if aborting the scanning before it's complete. -enum LiteralType { - LITERAL_TYPE_STRING, - LITERAL_TYPE_NUMBER, // not really different from string type in behaviour - LITERAL_TYPE_COMMENT -}; - -class LiteralScope -{ -public: - explicit LiteralScope(Scanner* _self, enum LiteralType _type): m_type(_type) - , m_scanner(_self) - , m_complete(false) - { - if (_type == LITERAL_TYPE_COMMENT) - m_scanner->m_nextSkippedComment.literal.clear(); - else - m_scanner->m_nextToken.literal.clear(); - } - ~LiteralScope() - { - if (!m_complete) - { - if (m_type == LITERAL_TYPE_COMMENT) - m_scanner->m_nextSkippedComment.literal.clear(); - else - m_scanner->m_nextToken.literal.clear(); - } - } - void complete() { m_complete = true; } - -private: - enum LiteralType m_type; - Scanner* m_scanner; - bool m_complete; -}; // end of LiteralScope class - - -void Scanner::reset(CharStream const& _source, string const& _sourceName) -{ - m_source = _source; - m_sourceName = make_shared<string const>(_sourceName); - reset(); -} - -void Scanner::reset() -{ - m_source.reset(); - m_char = m_source.get(); - skipWhitespace(); - scanToken(); - next(); -} - -bool Scanner::scanHexByte(char& o_scannedByte) -{ - char x = 0; - for (int i = 0; i < 2; i++) - { - int d = hexValue(m_char); - if (d < 0) - { - rollback(i); - return false; - } - x = x * 16 + d; - advance(); - } - o_scannedByte = x; - return true; -} - -bool Scanner::scanUnicode(unsigned & o_codepoint) -{ - unsigned x = 0; - for (int i = 0; i < 4; i++) - { - int d = hexValue(m_char); - if (d < 0) - { - rollback(i); - return false; - } - x = x * 16 + d; - advance(); - } - o_codepoint = x; - return true; -} - -// This supports codepoints between 0000 and FFFF. -void Scanner::addUnicodeAsUTF8(unsigned codepoint) -{ - if (codepoint <= 0x7f) - addLiteralChar(codepoint); - else if (codepoint <= 0x7ff) - { - addLiteralChar(0xc0 | (codepoint >> 6)); - addLiteralChar(0x80 | (codepoint & 0x3f)); - } - else - { - addLiteralChar(0xe0 | (codepoint >> 12)); - addLiteralChar(0x80 | ((codepoint >> 6) & 0x3f)); - addLiteralChar(0x80 | (codepoint & 0x3f)); - } -} - -// Ensure that tokens can be stored in a byte. -BOOST_STATIC_ASSERT(TokenTraits::count() <= 0x100); - -Token Scanner::next() -{ - m_currentToken = m_nextToken; - m_skippedComment = m_nextSkippedComment; - scanToken(); - - return m_currentToken.token; -} - -Token Scanner::selectToken(char _next, Token _then, Token _else) -{ - advance(); - if (m_char == _next) - return selectToken(_then); - else - return _else; -} - -bool Scanner::skipWhitespace() -{ - int const startPosition = sourcePos(); - while (isWhiteSpace(m_char)) - advance(); - // Return whether or not we skipped any characters. - return sourcePos() != startPosition; -} - -void Scanner::skipWhitespaceExceptUnicodeLinebreak() -{ - while (isWhiteSpace(m_char) && !isUnicodeLinebreak()) - advance(); -} - -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. - while (!isUnicodeLinebreak()) - if (!advance()) break; - - return Token::Whitespace; -} - -Token Scanner::scanSingleLineDocComment() -{ - LiteralScope literal(this, LITERAL_TYPE_COMMENT); - advance(); //consume the last '/' at /// - - skipWhitespaceExceptUnicodeLinebreak(); - - while (!isSourcePastEndOfInput()) - { - if (isLineTerminator(m_char)) - { - // check if next line is also a documentation comment - skipWhitespace(); - if (!m_source.isPastEndOfInput(3) && - m_source.get(0) == '/' && - m_source.get(1) == '/' && - m_source.get(2) == '/') - { - addCommentLiteralChar('\n'); - m_char = m_source.advanceAndGet(3); - } - else - break; // next line is not a documentation comment, we are done - - } - else if (isUnicodeLinebreak()) - // Any line terminator that is not '\n' is considered to end the - // comment. - break; - addCommentLiteralChar(m_char); - advance(); - } - literal.complete(); - return Token::CommentLiteral; -} - -Token Scanner::skipMultiLineComment() -{ - advance(); - while (!isSourcePastEndOfInput()) - { - char ch = m_char; - advance(); - - // If we have reached the end of the multi-line comment, we - // consume the '/' and insert a whitespace. This way all - // multi-line comments are treated as whitespace. - if (ch == '*' && m_char == '/') - { - m_char = ' '; - return Token::Whitespace; - } - } - // Unterminated multi-line comment. - return Token::Illegal; -} - -Token Scanner::scanMultiLineDocComment() -{ - LiteralScope literal(this, LITERAL_TYPE_COMMENT); - bool endFound = false; - bool charsAdded = false; - - while (isWhiteSpace(m_char) && !isLineTerminator(m_char)) - advance(); - - while (!isSourcePastEndOfInput()) - { - //handle newlines in multline comments - if (isLineTerminator(m_char)) - { - skipWhitespace(); - if (!m_source.isPastEndOfInput(1) && m_source.get(0) == '*' && m_source.get(1) == '*') - { // it is unknown if this leads to the end of the comment - addCommentLiteralChar('*'); - advance(); - } - else if (!m_source.isPastEndOfInput(1) && m_source.get(0) == '*' && m_source.get(1) != '/') - { // skip first '*' in subsequent lines - if (charsAdded) - addCommentLiteralChar('\n'); - m_char = m_source.advanceAndGet(2); - } - else if (!m_source.isPastEndOfInput(1) && m_source.get(0) == '*' && m_source.get(1) == '/') - { // if after newline the comment ends, don't insert the newline - m_char = m_source.advanceAndGet(2); - endFound = true; - break; - } - else if (charsAdded) - addCommentLiteralChar('\n'); - } - - if (!m_source.isPastEndOfInput(1) && m_source.get(0) == '*' && m_source.get(1) == '/') - { - m_char = m_source.advanceAndGet(2); - endFound = true; - break; - } - addCommentLiteralChar(m_char); - charsAdded = true; - advance(); - } - literal.complete(); - if (!endFound) - return Token::Illegal; - else - return Token::CommentLiteral; -} - -Token Scanner::scanSlash() -{ - int firstSlashPosition = sourcePos(); - advance(); - if (m_char == '/') - { - if (!advance()) /* double slash comment directly before EOS */ - return Token::Whitespace; - else if (m_char == '/') - { - // doxygen style /// comment - Token comment; - m_nextSkippedComment.location.start = firstSlashPosition; - comment = scanSingleLineDocComment(); - m_nextSkippedComment.location.end = sourcePos(); - m_nextSkippedComment.token = comment; - return Token::Whitespace; - } - else - return skipSingleLineComment(); - } - else if (m_char == '*') - { - // doxygen style /** natspec comment - if (!advance()) /* slash star comment before EOS */ - return Token::Illegal; - else if (m_char == '*') - { - advance(); //consume the last '*' at /** - - // "/**/" - if (m_char == '/') - { - advance(); //skip the closing slash - return Token::Whitespace; - } - // we actually have a multiline documentation comment - Token comment; - m_nextSkippedComment.location.start = firstSlashPosition; - comment = scanMultiLineDocComment(); - m_nextSkippedComment.location.end = sourcePos(); - m_nextSkippedComment.token = comment; - if (comment == Token::Illegal) - return Token::Illegal; - else - return Token::Whitespace; - } - else - return skipMultiLineComment(); - } - else if (m_char == '=') - return selectToken(Token::AssignDiv); - else - return Token::Div; -} - -void Scanner::scanToken() -{ - m_nextToken.literal.clear(); - m_nextToken.extendedTokenInfo = make_tuple(0, 0); - m_nextSkippedComment.literal.clear(); - m_nextSkippedComment.extendedTokenInfo = make_tuple(0, 0); - - Token token; - // M and N are for the purposes of grabbing different type sizes - unsigned m; - unsigned n; - do - { - // Remember the position of the next token - m_nextToken.location.start = sourcePos(); - switch (m_char) - { - case '"': - case '\'': - token = scanString(); - break; - case '<': - // < <= << <<= - advance(); - if (m_char == '=') - token = selectToken(Token::LessThanOrEqual); - else if (m_char == '<') - token = selectToken('=', Token::AssignShl, Token::SHL); - else - token = Token::LessThan; - break; - case '>': - // > >= >> >>= >>> >>>= - advance(); - if (m_char == '=') - token = selectToken(Token::GreaterThanOrEqual); - else if (m_char == '>') - { - // >> >>= >>> >>>= - advance(); - if (m_char == '=') - token = selectToken(Token::AssignSar); - else if (m_char == '>') - token = selectToken('=', Token::AssignShr, Token::SHR); - else - token = Token::SAR; - } - else - token = Token::GreaterThan; - break; - case '=': - // = == => - advance(); - if (m_char == '=') - token = selectToken(Token::Equal); - else if (m_char == '>') - token = selectToken(Token::Arrow); - else - token = Token::Assign; - break; - case '!': - // ! != - advance(); - if (m_char == '=') - token = selectToken(Token::NotEqual); - else - token = Token::Not; - break; - case '+': - // + ++ += - advance(); - if (m_char == '+') - token = selectToken(Token::Inc); - else if (m_char == '=') - token = selectToken(Token::AssignAdd); - else - token = Token::Add; - break; - case '-': - // - -- -= - advance(); - if (m_char == '-') - token = selectToken(Token::Dec); - else if (m_char == '=') - token = selectToken(Token::AssignSub); - else - token = Token::Sub; - break; - case '*': - // * ** *= - advance(); - if (m_char == '*') - token = selectToken(Token::Exp); - else if (m_char == '=') - token = selectToken(Token::AssignMul); - else - token = Token::Mul; - break; - case '%': - // % %= - token = selectToken('=', Token::AssignMod, Token::Mod); - break; - case '/': - // / // /* /= - token = scanSlash(); - break; - case '&': - // & && &= - advance(); - if (m_char == '&') - token = selectToken(Token::And); - else if (m_char == '=') - token = selectToken(Token::AssignBitAnd); - else - token = Token::BitAnd; - break; - case '|': - // | || |= - advance(); - if (m_char == '|') - token = selectToken(Token::Or); - else if (m_char == '=') - token = selectToken(Token::AssignBitOr); - else - token = Token::BitOr; - break; - case '^': - // ^ ^= - token = selectToken('=', Token::AssignBitXor, Token::BitXor); - break; - case '.': - // . Number - advance(); - if (isDecimalDigit(m_char)) - token = scanNumber('.'); - else - token = Token::Period; - break; - case ':': - token = selectToken(Token::Colon); - break; - case ';': - token = selectToken(Token::Semicolon); - break; - case ',': - token = selectToken(Token::Comma); - break; - case '(': - token = selectToken(Token::LParen); - break; - case ')': - token = selectToken(Token::RParen); - break; - case '[': - token = selectToken(Token::LBrack); - break; - case ']': - token = selectToken(Token::RBrack); - break; - case '{': - token = selectToken(Token::LBrace); - break; - case '}': - token = selectToken(Token::RBrace); - break; - case '?': - token = selectToken(Token::Conditional); - break; - case '~': - token = selectToken(Token::BitNot); - break; - default: - if (isIdentifierStart(m_char)) - { - tie(token, m, n) = scanIdentifierOrKeyword(); - - // Special case for hexadecimal literals - if (token == Token::Hex) - { - // reset - m = 0; - n = 0; - - // Special quoted hex string must follow - if (m_char == '"' || m_char == '\'') - token = scanHexString(); - else - token = Token::IllegalHex; - } - } - else if (isDecimalDigit(m_char)) - token = scanNumber(); - else if (skipWhitespace()) - token = Token::Whitespace; - else if (isSourcePastEndOfInput()) - token = Token::EOS; - else - token = selectToken(Token::Illegal); - break; - } - // Continue scanning for tokens as long as we're just skipping - // whitespace. - } - while (token == Token::Whitespace); - m_nextToken.location.end = sourcePos(); - m_nextToken.token = token; - m_nextToken.extendedTokenInfo = make_tuple(m, n); -} - -bool Scanner::scanEscape() -{ - char c = m_char; - advance(); - // Skip escaped newlines. - if (isLineTerminator(c)) - return true; - switch (c) - { - case '\'': // fall through - case '"': // fall through - case '\\': - break; - case 'b': - c = '\b'; - break; - case 'f': - c = '\f'; - break; - case 'n': - c = '\n'; - break; - case 'r': - c = '\r'; - break; - case 't': - c = '\t'; - break; - case 'v': - c = '\v'; - break; - case 'u': - { - unsigned codepoint; - if (!scanUnicode(codepoint)) - return false; - addUnicodeAsUTF8(codepoint); - return true; - } - case 'x': - if (!scanHexByte(c)) - return false; - break; - default: - return false; - } - - addLiteralChar(c); - return true; -} - -bool Scanner::isUnicodeLinebreak() -{ - if (0x0a <= m_char && m_char <= 0x0d) - // line feed, vertical tab, form feed, carriage return - return true; - else if (!m_source.isPastEndOfInput(1) && uint8_t(m_source.get(0)) == 0xc2 && uint8_t(m_source.get(1)) == 0x85) - // NEL - U+0085, C2 85 in utf8 - return true; - else if (!m_source.isPastEndOfInput(2) && uint8_t(m_source.get(0)) == 0xe2 && uint8_t(m_source.get(1)) == 0x80 && ( - uint8_t(m_source.get(2)) == 0xa8 || uint8_t(m_source.get(2)) == 0xa9 - )) - // LS - U+2028, E2 80 A8 in utf8 - // PS - U+2029, E2 80 A9 in utf8 - return true; - else - return false; -} - -Token Scanner::scanString() -{ - char const quote = m_char; - advance(); // consume quote - LiteralScope literal(this, LITERAL_TYPE_STRING); - while (m_char != quote && !isSourcePastEndOfInput() && !isUnicodeLinebreak()) - { - char c = m_char; - advance(); - if (c == '\\') - { - if (isSourcePastEndOfInput() || !scanEscape()) - return Token::Illegal; - } - else - addLiteralChar(c); - } - if (m_char != quote) - return Token::Illegal; - literal.complete(); - advance(); // consume quote - return Token::StringLiteral; -} - -Token Scanner::scanHexString() -{ - char const quote = m_char; - advance(); // consume quote - LiteralScope literal(this, LITERAL_TYPE_STRING); - while (m_char != quote && !isSourcePastEndOfInput()) - { - char c = m_char; - if (!scanHexByte(c)) - return Token::IllegalHex; - addLiteralChar(c); - } - if (m_char != quote) - return Token::IllegalHex; - literal.complete(); - advance(); // consume quote - return Token::StringLiteral; -} - -// Parse for regex [:digit:]+(_[:digit:]+)* -void Scanner::scanDecimalDigits() -{ - // MUST begin with a decimal digit. - if (!isDecimalDigit(m_char)) - return; - - // May continue with decimal digit or underscore for grouping. - do addLiteralCharAndAdvance(); - while (!m_source.isPastEndOfInput() && (isDecimalDigit(m_char) || m_char == '_')); - - // Defer further validation of underscore to SyntaxChecker. -} - -Token Scanner::scanNumber(char _charSeen) -{ - enum { DECIMAL, HEX, BINARY } kind = DECIMAL; - LiteralScope literal(this, LITERAL_TYPE_NUMBER); - if (_charSeen == '.') - { - // we have already seen a decimal point of the float - addLiteralChar('.'); - if (m_char == '_') - return Token::Illegal; - scanDecimalDigits(); // we know we have at least one digit - } - else - { - solAssert(_charSeen == 0, ""); - // if the first character is '0' we must check for octals and hex - if (m_char == '0') - { - addLiteralCharAndAdvance(); - // either 0, 0exxx, 0Exxx, 0.xxx or a hex number - if (m_char == 'x') - { - // hex number - kind = HEX; - addLiteralCharAndAdvance(); - if (!isHexDigit(m_char)) - return Token::Illegal; // we must have at least one hex digit after 'x' - - while (isHexDigit(m_char) || m_char == '_') // We keep the underscores for later validation - 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) - { - scanDecimalDigits(); // optional - if (m_char == '.') - { - if (!m_source.isPastEndOfInput(1) && m_source.get(1) == '_') - { - // Assume the input may be a floating point number with leading '_' in fraction part. - // Recover by consuming it all but returning `Illegal` right away. - addLiteralCharAndAdvance(); // '.' - addLiteralCharAndAdvance(); // '_' - scanDecimalDigits(); - } - if (m_source.isPastEndOfInput() || !isDecimalDigit(m_source.get(1))) - { - // A '.' has to be followed by a number. - literal.complete(); - return Token::Number; - } - addLiteralCharAndAdvance(); - scanDecimalDigits(); - } - } - } - // scan exponent, if any - if (m_char == 'e' || m_char == 'E') - { - solAssert(kind != HEX, "'e'/'E' must be scanned as part of the hex number"); - if (kind != DECIMAL) - return Token::Illegal; - else if (!m_source.isPastEndOfInput(1) && m_source.get(1) == '_') - { - // Recover from wrongly placed underscore as delimiter in literal with scientific - // notation by consuming until the end. - addLiteralCharAndAdvance(); // 'e' - addLiteralCharAndAdvance(); // '_' - scanDecimalDigits(); - literal.complete(); - return Token::Number; - } - // scan exponent - addLiteralCharAndAdvance(); // 'e' | 'E' - if (m_char == '+' || m_char == '-') - addLiteralCharAndAdvance(); - if (!isDecimalDigit(m_char)) - return Token::Illegal; // we must have at least one decimal digit after 'e'/'E' - scanDecimalDigits(); - } - // The source character immediately following a numeric literal must - // not be an identifier start or a decimal digit; see ECMA-262 - // section 7.8.3, page 17 (note that we read only one decimal digit - // if the value is 0). - if (isDecimalDigit(m_char) || isIdentifierStart(m_char)) - return Token::Illegal; - literal.complete(); - return Token::Number; -} - -tuple<Token, unsigned, unsigned> Scanner::scanIdentifierOrKeyword() -{ - solAssert(isIdentifierStart(m_char), ""); - LiteralScope literal(this, LITERAL_TYPE_STRING); - addLiteralCharAndAdvance(); - // Scan the rest of the identifier characters. - while (isIdentifierPart(m_char)) //get full literal - addLiteralCharAndAdvance(); - literal.complete(); - return TokenTraits::fromIdentifierOrKeyword(m_nextToken.literal); -} - -char CharStream::advanceAndGet(size_t _chars) -{ - if (isPastEndOfInput()) - return 0; - m_position += _chars; - if (isPastEndOfInput()) - return 0; - return m_source[m_position]; -} - -char CharStream::rollback(size_t _amount) -{ - solAssert(m_position >= _amount, ""); - m_position -= _amount; - return get(); -} - -string CharStream::lineAtPosition(int _position) const -{ - // if _position points to \n, it returns the line before the \n - using size_type = string::size_type; - size_type searchStart = min<size_type>(m_source.size(), _position); - if (searchStart > 0) - searchStart--; - size_type lineStart = m_source.rfind('\n', searchStart); - if (lineStart == string::npos) - lineStart = 0; - else - lineStart++; - return m_source.substr(lineStart, min(m_source.find('\n', lineStart), - m_source.size()) - lineStart); -} - -tuple<int, int> CharStream::translatePositionToLineColumn(int _position) const -{ - using size_type = string::size_type; - size_type searchPosition = min<size_type>(m_source.size(), _position); - int lineNumber = count(m_source.begin(), m_source.begin() + searchPosition, '\n'); - size_type lineStart; - if (searchPosition == 0) - lineStart = 0; - else - { - lineStart = m_source.rfind('\n', searchPosition - 1); - lineStart = lineStart == string::npos ? 0 : lineStart + 1; - } - return tuple<int, int>(lineNumber, searchPosition - lineStart); -} - - -} -} diff --git a/libsolidity/parsing/Scanner.h b/libsolidity/parsing/Scanner.h deleted file mode 100644 index 14eeb66e..00000000 --- a/libsolidity/parsing/Scanner.h +++ /dev/null @@ -1,249 +0,0 @@ -/* - This file is part of solidity. - - solidity 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. - - solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>. - - This file is derived from the file "scanner.h", which was part of the - V8 project. The original copyright header follows: - - Copyright 2006-2012, the V8 project authors. All rights reserved. - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -/** - * @author Christian <c@ethdev.com> - * @date 2014 - * Solidity scanner. - */ - -#pragma once - -#include <libdevcore/Common.h> -#include <libdevcore/CommonData.h> -#include <libevmasm/SourceLocation.h> -#include <libsolidity/parsing/Token.h> - -namespace dev -{ -namespace solidity -{ - - -class AstRawString; -class AstValueFactory; -class ParserRecorder; - -class CharStream -{ -public: - CharStream(): m_position(0) {} - explicit CharStream(std::string const& _source): m_source(_source), m_position(0) {} - int position() const { return m_position; } - bool isPastEndOfInput(size_t _charsForward = 0) const { return (m_position + _charsForward) >= m_source.size(); } - char get(size_t _charsForward = 0) const { return m_source[m_position + _charsForward]; } - char advanceAndGet(size_t _chars = 1); - char rollback(size_t _amount); - - void reset() { m_position = 0; } - - std::string const& source() const { return m_source; } - - ///@{ - ///@name Error printing helper functions - /// Functions that help pretty-printing parse errors - /// Do only use in error cases, they are quite expensive. - std::string lineAtPosition(int _position) const; - std::tuple<int, int> translatePositionToLineColumn(int _position) const; - ///@} - -private: - std::string m_source; - size_t m_position; -}; - - - -class Scanner -{ - friend class LiteralScope; -public: - - explicit Scanner(CharStream const& _source = CharStream(), std::string const& _sourceName = "") { reset(_source, _sourceName); } - - std::string source() const { return m_source.source(); } - - /// Resets the scanner as if newly constructed with _source and _sourceName as input. - void reset(CharStream const& _source, std::string const& _sourceName); - /// Resets scanner to the start of input. - void reset(); - - /// @returns the next token and advances input - Token next(); - - ///@{ - ///@name Information about the current token - - /// @returns the current token - Token currentToken() const - { - return m_currentToken.token; - } - ElementaryTypeNameToken currentElementaryTypeNameToken() const - { - unsigned firstSize; - unsigned secondSize; - std::tie(firstSize, secondSize) = m_currentToken.extendedTokenInfo; - return ElementaryTypeNameToken(m_currentToken.token, firstSize, secondSize); - } - - SourceLocation currentLocation() const { return m_currentToken.location; } - std::string const& currentLiteral() const { return m_currentToken.literal; } - std::tuple<unsigned, unsigned> const& currentTokenInfo() const { return m_currentToken.extendedTokenInfo; } - ///@} - - ///@{ - ///@name Information about the current comment token - - SourceLocation currentCommentLocation() const { return m_skippedComment.location; } - std::string const& currentCommentLiteral() const { return m_skippedComment.literal; } - /// Called by the parser during FunctionDefinition parsing to clear the current comment - void clearCurrentCommentLiteral() { m_skippedComment.literal.clear(); } - - ///@} - - ///@{ - ///@name Information about the next token - - /// @returns the next token without advancing input. - Token peekNextToken() const { return m_nextToken.token; } - SourceLocation peekLocation() const { return m_nextToken.location; } - std::string const& peekLiteral() const { return m_nextToken.literal; } - ///@} - - std::shared_ptr<std::string const> const& sourceName() const { return m_sourceName; } - - ///@{ - ///@name Error printing helper functions - /// Functions that help pretty-printing parse errors - /// Do only use in error cases, they are quite expensive. - std::string lineAtPosition(int _position) const { return m_source.lineAtPosition(_position); } - std::tuple<int, int> translatePositionToLineColumn(int _position) const { return m_source.translatePositionToLineColumn(_position); } - std::string sourceAt(SourceLocation const& _location) const - { - solAssert(!_location.isEmpty(), ""); - solAssert(m_sourceName && _location.sourceName, ""); - solAssert(*m_sourceName == *_location.sourceName, ""); - return m_source.source().substr(_location.start, _location.end - _location.start); - } - ///@} - -private: - /// Used for the current and look-ahead token and comments - struct TokenDesc - { - Token token; - SourceLocation location; - std::string literal; - std::tuple<unsigned, unsigned> extendedTokenInfo; - }; - - ///@{ - ///@name Literal buffer support - inline void addLiteralChar(char c) { m_nextToken.literal.push_back(c); } - inline void addCommentLiteralChar(char c) { m_nextSkippedComment.literal.push_back(c); } - inline void addLiteralCharAndAdvance() { addLiteralChar(m_char); advance(); } - void addUnicodeAsUTF8(unsigned codepoint); - ///@} - - bool advance() { m_char = m_source.advanceAndGet(); return !m_source.isPastEndOfInput(); } - void rollback(int _amount) { m_char = m_source.rollback(_amount); } - - inline Token selectToken(Token _tok) { advance(); return _tok; } - /// If the next character is _next, advance and return _then, otherwise return _else. - inline Token selectToken(char _next, Token _then, Token _else); - - bool scanHexByte(char& o_scannedByte); - bool scanUnicode(unsigned& o_codepoint); - - /// Scans a single Solidity token. - void scanToken(); - - /// Skips all whitespace and @returns true if something was skipped. - bool skipWhitespace(); - /// Skips all whitespace that are neither '\r' nor '\n'. - void skipWhitespaceExceptUnicodeLinebreak(); - Token skipSingleLineComment(); - Token skipMultiLineComment(); - - void scanDecimalDigits(); - Token scanNumber(char _charSeen = 0); - std::tuple<Token, unsigned, unsigned> scanIdentifierOrKeyword(); - - Token scanString(); - Token scanHexString(); - Token scanSingleLineDocComment(); - Token scanMultiLineDocComment(); - /// Scans a slash '/' and depending on the characters returns the appropriate token - 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 - /// is scanned. - bool scanEscape(); - - /// @returns true iff we are currently positioned at a unicode line break. - bool isUnicodeLinebreak(); - - /// Return the current source position. - int sourcePos() const { return m_source.position(); } - bool isSourcePastEndOfInput() const { return m_source.isPastEndOfInput(); } - - TokenDesc m_skippedComment; // desc for current skipped comment - TokenDesc m_nextSkippedComment; // desc for next skipped comment - - TokenDesc m_currentToken; // desc for current token (as returned by Next()) - TokenDesc m_nextToken; // desc for next token (one token look-ahead) - - CharStream m_source; - std::shared_ptr<std::string const> m_sourceName; - - /// one character look-ahead, equals 0 at end of input - char m_char; -}; - -} -} diff --git a/libsolidity/parsing/Token.cpp b/libsolidity/parsing/Token.cpp deleted file mode 100644 index dccd9037..00000000 --- a/libsolidity/parsing/Token.cpp +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright 2006-2012, the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Modifications as part of solidity under the following license: -// -// solidity 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. -// -// solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>. - -#include <map> -#include <libsolidity/parsing/Token.h> -#include <boost/range/iterator_range.hpp> - -using namespace std; - -namespace dev -{ -namespace solidity -{ - -void ElementaryTypeNameToken::assertDetails(Token _baseType, unsigned const& _first, unsigned const& _second) -{ - 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."); - solAssert(_first <= 32, "No elementary type bytes" + to_string(_first) + "."); - } - else if (_baseType == Token::UIntM || _baseType == Token::IntM) - { - 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(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(TokenTraits::toString(_baseType)) + to_string(_first) + "x" + to_string(_second) + "." - ); - } - m_token = _baseType; - m_firstNumber = _first; - m_secondNumber = _second; -} - -namespace TokenTraits -{ - -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 ""; - } -} - -char const* name(Token tok) -{ -#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)]; -} - -std::string friendlyName(Token tok) -{ - char const* ret = toString(tok); - if (ret) - return std::string(ret); - - ret = name(tok); - solAssert(ret != nullptr, ""); - return std::string(ret); -} - -#define T(name, string, precedence) precedence, -int precedence(Token tok) -{ - int8_t const static precs[TokenTraits::count()] = - { - TOKEN_LIST(T, T) - }; - return precs[static_cast<size_t>(tok)]; -} -#undef T - -int parseSize(string::const_iterator _begin, string::const_iterator _end) -{ - try - { - unsigned int m = boost::lexical_cast<int>(boost::make_iterator_range(_begin, _end)); - return m; - } - catch(boost::bad_lexical_cast const&) - { - return -1; - } -} - -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()) - { - string baseType(_literal.begin(), positionM); - auto positionX = find_if_not(positionM, _literal.end(), ::isdigit); - int m = parseSize(positionM, positionX); - Token keyword = keywordByName(baseType); - if (keyword == Token::Bytes) - { - if (0 < m && m <= 32 && positionX == _literal.end()) - return make_tuple(Token::BytesM, m, 0); - } - else if (keyword == Token::UInt || keyword == Token::Int) - { - if (0 < m && m <= 256 && m % 8 == 0 && positionX == _literal.end()) - { - if (keyword == Token::UInt) - return make_tuple(Token::UIntM, m, 0); - else - return make_tuple(Token::IntM, m, 0); - } - } - else if (keyword == Token::UFixed || keyword == Token::Fixed) - { - if ( - positionM < positionX && - positionX < _literal.end() && - *positionX == 'x' && - all_of(positionX + 1, _literal.end(), ::isdigit) - ) { - int n = parseSize(positionX + 1, _literal.end()); - if ( - 8 <= m && m <= 256 && m % 8 == 0 && - 0 <= n && n <= 80 - ) { - if (keyword == Token::UFixed) - return make_tuple(Token::UFixedMxN, m, n); - else - return make_tuple(Token::FixedMxN, m, n); - } - } - } - return make_tuple(Token::Identifier, 0, 0); - } - - return make_tuple(keywordByName(_literal), 0, 0); -} - -} -} -} diff --git a/libsolidity/parsing/Token.h b/libsolidity/parsing/Token.h deleted file mode 100644 index 81e8dd98..00000000 --- a/libsolidity/parsing/Token.h +++ /dev/null @@ -1,378 +0,0 @@ -// Copyright 2006-2012, the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Modifications as part of solidity under the following license: -// -// solidity 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. -// -// solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>. - -#pragma once - -#include <libdevcore/Common.h> -#include <libsolidity/interface/Exceptions.h> -#include <libsolidity/parsing/UndefMacros.h> -#include <iosfwd> - -namespace dev -{ -namespace solidity -{ - -// TOKEN_LIST takes a list of 3 macros M, all of which satisfy the -// same signature M(name, string, precedence), where name is the -// symbolic token name, string is the corresponding syntactic symbol -// (or NULL, for literals), and precedence is the precedence (or 0). -// The parameters are invoked for token categories as follows: -// -// T: Non-keyword tokens -// K: Keyword tokens - -// IGNORE_TOKEN is a convenience macro that can be supplied as -// an argument (at any position) for a TOKEN_LIST call. It does -// nothing with tokens belonging to the respective category. - -#define IGNORE_TOKEN(name, string, precedence) - -#define TOKEN_LIST(T, K) \ - /* End of source indicator. */ \ - T(EOS, "EOS", 0) \ - \ - /* Punctuators (ECMA-262, section 7.7, page 15). */ \ - T(LParen, "(", 0) \ - T(RParen, ")", 0) \ - T(LBrack, "[", 0) \ - T(RBrack, "]", 0) \ - T(LBrace, "{", 0) \ - T(RBrace, "}", 0) \ - T(Colon, ":", 0) \ - T(Semicolon, ";", 0) \ - T(Period, ".", 0) \ - T(Conditional, "?", 3) \ - T(Arrow, "=>", 0) \ - \ - /* Assignment operators. */ \ - /* IsAssignmentOp() relies on this block of enum values being */ \ - /* contiguous and sorted in the same order!*/ \ - T(Assign, "=", 2) \ - /* The following have to be in exactly the same order as the simple binary operators*/ \ - T(AssignBitOr, "|=", 2) \ - T(AssignBitXor, "^=", 2) \ - T(AssignBitAnd, "&=", 2) \ - T(AssignShl, "<<=", 2) \ - T(AssignSar, ">>=", 2) \ - T(AssignShr, ">>>=", 2) \ - T(AssignAdd, "+=", 2) \ - T(AssignSub, "-=", 2) \ - T(AssignMul, "*=", 2) \ - T(AssignDiv, "/=", 2) \ - T(AssignMod, "%=", 2) \ - \ - /* Binary operators sorted by precedence. */ \ - /* IsBinaryOp() relies on this block of enum values */ \ - /* being contiguous and sorted in the same order! */ \ - T(Comma, ",", 1) \ - T(Or, "||", 4) \ - T(And, "&&", 5) \ - T(BitOr, "|", 8) \ - T(BitXor, "^", 9) \ - T(BitAnd, "&", 10) \ - T(SHL, "<<", 11) \ - T(SAR, ">>", 11) \ - T(SHR, ">>>", 11) \ - T(Add, "+", 12) \ - T(Sub, "-", 12) \ - T(Mul, "*", 13) \ - T(Div, "/", 13) \ - T(Mod, "%", 13) \ - T(Exp, "**", 14) \ - \ - /* Compare operators sorted by precedence. */ \ - /* IsCompareOp() relies on this block of enum values */ \ - /* being contiguous and sorted in the same order! */ \ - T(Equal, "==", 6) \ - T(NotEqual, "!=", 6) \ - T(LessThan, "<", 7) \ - T(GreaterThan, ">", 7) \ - T(LessThanOrEqual, "<=", 7) \ - T(GreaterThanOrEqual, ">=", 7) \ - \ - /* Unary operators. */ \ - /* IsUnaryOp() relies on this block of enum values */ \ - /* being contiguous and sorted in the same order! */ \ - T(Not, "!", 0) \ - T(BitNot, "~", 0) \ - T(Inc, "++", 0) \ - T(Dec, "--", 0) \ - K(Delete, "delete", 0) \ - \ - /* Keywords */ \ - K(Anonymous, "anonymous", 0) \ - K(As, "as", 0) \ - K(Assembly, "assembly", 0) \ - K(Break, "break", 0) \ - K(Constant, "constant", 0) \ - K(Constructor, "constructor", 0) \ - K(Continue, "continue", 0) \ - K(Contract, "contract", 0) \ - K(Do, "do", 0) \ - K(Else, "else", 0) \ - K(Enum, "enum", 0) \ - K(Emit, "emit", 0) \ - K(Event, "event", 0) \ - K(External, "external", 0) \ - K(For, "for", 0) \ - K(Function, "function", 0) \ - 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) \ - K(Library, "library", 0) \ - K(Mapping, "mapping", 0) \ - K(Memory, "memory", 0) \ - K(Modifier, "modifier", 0) \ - K(New, "new", 0) \ - K(Payable, "payable", 0) \ - K(Public, "public", 0) \ - K(Pragma, "pragma", 0) \ - K(Private, "private", 0) \ - K(Pure, "pure", 0) \ - K(Return, "return", 0) \ - K(Returns, "returns", 0) \ - K(Storage, "storage", 0) \ - K(CallData, "calldata", 0) \ - K(Struct, "struct", 0) \ - K(Throw, "throw", 0) \ - K(Using, "using", 0) \ - K(Var, "var", 0) \ - K(View, "view", 0) \ - K(While, "while", 0) \ - \ - /* Ether subdenominations */ \ - K(SubWei, "wei", 0) \ - K(SubSzabo, "szabo", 0) \ - K(SubFinney, "finney", 0) \ - K(SubEther, "ether", 0) \ - K(SubSecond, "seconds", 0) \ - K(SubMinute, "minutes", 0) \ - K(SubHour, "hours", 0) \ - K(SubDay, "days", 0) \ - K(SubWeek, "weeks", 0) \ - K(SubYear, "years", 0) \ - /* type keywords*/ \ - K(Int, "int", 0) \ - K(UInt, "uint", 0) \ - K(Bytes, "bytes", 0) \ - K(Byte, "byte", 0) \ - K(String, "string", 0) \ - K(Address, "address", 0) \ - K(Bool, "bool", 0) \ - K(Fixed, "fixed", 0) \ - K(UFixed, "ufixed", 0) \ - T(IntM, "intM", 0) \ - T(UIntM, "uintM", 0) \ - T(BytesM, "bytesM", 0) \ - T(FixedMxN, "fixedMxN", 0) \ - T(UFixedMxN, "ufixedMxN", 0) \ - T(TypesEnd, NULL, 0) /* used as type enum end marker */ \ - \ - /* Literals */ \ - K(TrueLiteral, "true", 0) \ - K(FalseLiteral, "false", 0) \ - T(Number, NULL, 0) \ - T(StringLiteral, NULL, 0) \ - T(CommentLiteral, NULL, 0) \ - \ - /* Identifiers (not keywords or future reserved words). */ \ - T(Identifier, NULL, 0) \ - \ - /* Keywords reserved for future use. */ \ - K(Abstract, "abstract", 0) \ - K(After, "after", 0) \ - K(Alias, "alias", 0) \ - K(Apply, "apply", 0) \ - K(Auto, "auto", 0) \ - K(Case, "case", 0) \ - K(Catch, "catch", 0) \ - K(CopyOf, "copyof", 0) \ - K(Default, "default", 0) \ - K(Define, "define", 0) \ - K(Final, "final", 0) \ - K(Immutable, "immutable", 0) \ - K(Implements, "implements", 0) \ - K(In, "in", 0) \ - K(Inline, "inline", 0) \ - K(Let, "let", 0) \ - K(Macro, "macro", 0) \ - K(Match, "match", 0) \ - K(Mutable, "mutable", 0) \ - K(NullLiteral, "null", 0) \ - K(Of, "of", 0) \ - K(Override, "override", 0) \ - K(Partial, "partial", 0) \ - K(Promise, "promise", 0) \ - K(Reference, "reference", 0) \ - K(Relocatable, "relocatable", 0) \ - K(Sealed, "sealed", 0) \ - K(Sizeof, "sizeof", 0) \ - K(Static, "static", 0) \ - K(Supports, "supports", 0) \ - K(Switch, "switch", 0) \ - K(Try, "try", 0) \ - K(Type, "type", 0) \ - K(Typedef, "typedef", 0) \ - K(TypeOf, "typeof", 0) \ - K(Unchecked, "unchecked", 0) \ - \ - /* Illegal token - not able to scan. */ \ - T(Illegal, "ILLEGAL", 0) \ - /* Illegal hex token */ \ - T(IllegalHex, "ILLEGAL_HEX", 0) \ - \ - /* Scanner-internal use only. */ \ - T(Whitespace, NULL, 0) - -// 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, - TOKEN_LIST(T, T) - NUM_TOKENS -#undef T -}; - -namespace TokenTraits -{ - constexpr size_t count() { return static_cast<size_t>(Token::NUM_TOKENS); } - - // Predicates - 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; } - - 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; } - - constexpr bool isStateMutabilitySpecifier(Token op, bool _allowConstant = true) - { - return (op == Token::Constant && _allowConstant) - || op == Token::Pure || op == Token::View || op == Token::Payable; - } - - 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); } - - inline Token AssignmentToBinaryOp(Token op) - { - 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. - int precedence(Token tok); - - std::tuple<Token, unsigned int, unsigned int> fromIdentifierOrKeyword(std::string const& _literal); - - // @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 _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 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 = 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."); - if (m_token == Token::FixedMxN || m_token == Token::UFixedMxN) - return name.substr(0, name.size() - 3) + std::to_string(m_firstNumber) + "x" + std::to_string(m_secondNumber); - else - return name.substr(0, name.size() - 1) + std::to_string(m_firstNumber); - } - -private: - Token m_token; - unsigned int m_firstNumber; - unsigned int m_secondNumber; - /// throws if type is not properly sized - void assertDetails(Token _baseType, unsigned const& _first, unsigned const& _second); -}; - -} -} diff --git a/libsolidity/parsing/UndefMacros.h b/libsolidity/parsing/UndefMacros.h deleted file mode 100644 index d96e242e..00000000 --- a/libsolidity/parsing/UndefMacros.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - This file is part of solidity. - - solidity 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. - - solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>. -*/ -/** @file UndefMacros.h - * @author Lefteris <lefteris@ethdev.com> - * @date 2015 - * - * This header should be used to #undef some really evil macros defined by - * windows.h which result in conflict with our Token.h - */ -#pragma once - -#if defined(_MSC_VER) || defined(__MINGW32__) - -#undef DELETE -#undef IN -#undef VOID -#undef THIS -#undef CONST - -// Conflicting define on MinGW in windows.h -// windows.h(19): #define interface struct -#ifdef interface -#undef interface -#endif - -#elif defined(DELETE) || defined(IN) || defined(VOID) || defined(THIS) || defined(CONST) || defined(interface) - -#error "The preceding macros in this header file are reserved for V8's "\ -"TOKEN_LIST. Please add a platform specific define above to undefine "\ -"overlapping macros." - -#endif |