diff options
Diffstat (limited to 'libsolidity')
-rw-r--r-- | libsolidity/ast/Types.cpp | 7 | ||||
-rw-r--r-- | libsolidity/parsing/Parser.cpp | 26 | ||||
-rw-r--r-- | libsolidity/parsing/Scanner.cpp | 14 | ||||
-rw-r--r-- | libsolidity/parsing/Scanner.h | 6 | ||||
-rw-r--r-- | libsolidity/parsing/Token.cpp | 122 | ||||
-rw-r--r-- | libsolidity/parsing/Token.h | 25 |
6 files changed, 142 insertions, 58 deletions
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 774be521..f8050898 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -156,10 +156,11 @@ TypePointer Type::fromElementaryTypeName(ElementaryTypeNameToken const& _type) TypePointer Type::fromElementaryTypeName(string const& _name) { - string details; + unsigned short firstNum; + unsigned short secondNum; Token::Value token; - tie(token, details) = Token::fromIdentifierOrKeyword(_name); - return fromElementaryTypeName(ElementaryTypeNameToken(token, details)); + tie(token, firstNum, secondNum) = Token::fromIdentifierOrKeyword(_name); + return fromElementaryTypeName(ElementaryTypeNameToken(token, firstNum, secondNum)); } TypePointer Type::forLiteral(Literal const& _literal) diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index 74ec5cda..e579f18b 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -590,7 +590,10 @@ ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar) Token::Value token = m_scanner->currentToken(); if (Token::isElementaryTypeName(token)) { - ElementaryTypeNameToken elemTypeName(token, m_scanner->currentTokenInfo()); + unsigned firstSize; + unsigned secondSize; + tie(firstSize, secondSize) = m_scanner->currentTokenInfo(); + ElementaryTypeNameToken elemTypeName(token, firstSize, secondSize); type = ASTNodeFactory(*this).createNode<ElementaryTypeName>(elemTypeName); m_scanner->next(); } @@ -628,11 +631,14 @@ ASTPointer<Mapping> Parser::parseMapping() expectToken(Token::Mapping); expectToken(Token::LParen); ASTPointer<ElementaryTypeName> keyType; - if (Token::isElementaryTypeName(m_scanner->currentToken())) - keyType = ASTNodeFactory(*this).createNode<ElementaryTypeName> - (ElementaryTypeNameToken(m_scanner->currentToken(), m_scanner->currentTokenInfo())); - else + Token::Value token = m_scanner->currentToken(); + if (!Token::isElementaryTypeName(token)) fatalParserError(string("Expected elementary type name for mapping key type")); + unsigned firstSize; + unsigned secondSize; + tie(firstSize, secondSize) = m_scanner->currentTokenInfo(); + ElementaryTypeNameToken elemTypeName(token, firstSize, secondSize); + keyType = ASTNodeFactory(*this).createNode<ElementaryTypeName>(elemTypeName); m_scanner->next(); expectToken(Token::Arrow); bool const allowVar = false; @@ -829,7 +835,10 @@ ASTPointer<Statement> Parser::parseSimpleStatement(ASTPointer<ASTString> const& else { startedWithElementary = true; - ElementaryTypeNameToken elemToken(m_scanner->currentToken(), m_scanner->currentTokenInfo()); + unsigned firstNum; + unsigned secondNum; + tie(firstNum, secondNum) = m_scanner->currentTokenInfo(); + ElementaryTypeNameToken elemToken(m_scanner->currentToken(), firstNum, secondNum); path.push_back(ASTNodeFactory(*this).createNode<ElementaryTypeNameExpression>(elemToken)); m_scanner->next(); } @@ -1138,7 +1147,10 @@ ASTPointer<Expression> Parser::parsePrimaryExpression() if (Token::isElementaryTypeName(token)) { //used for casts - ElementaryTypeNameToken elementaryExpression(m_scanner->currentToken(), m_scanner->currentTokenInfo()); + unsigned firstSize; + unsigned secondSize; + tie(firstSize, secondSize) = m_scanner->currentTokenInfo(); + ElementaryTypeNameToken elementaryExpression(m_scanner->currentToken(), firstSize, secondSize); expression = nodeFactory.createNode<ElementaryTypeNameExpression>(elementaryExpression); m_scanner->next(); } diff --git a/libsolidity/parsing/Scanner.cpp b/libsolidity/parsing/Scanner.cpp index 9307b100..510d283e 100644 --- a/libsolidity/parsing/Scanner.cpp +++ b/libsolidity/parsing/Scanner.cpp @@ -381,12 +381,14 @@ Token::Value Scanner::scanSlash() void Scanner::scanToken() { m_nextToken.literal.clear(); - m_nextToken.extendedTokenInfo.clear(); + m_nextToken.extendedTokenInfo = make_tuple(0, 0); m_nextSkippedComment.literal.clear(); - m_nextSkippedComment.extendedTokenInfo.clear(); + m_nextSkippedComment.extendedTokenInfo = make_tuple(0, 0); Token::Value token; - string tokenExtension; + // M and N are for the purposes of grabbing different type sizes + unsigned M; + unsigned N; do { // Remember the position of the next token @@ -554,7 +556,7 @@ void Scanner::scanToken() break; default: if (isIdentifierStart(m_char)) - tie(token, tokenExtension) = scanIdentifierOrKeyword(); + tie(token, M, N) = scanIdentifierOrKeyword(); else if (isDecimalDigit(m_char)) token = scanNumber(); else if (skipWhitespace()) @@ -571,7 +573,7 @@ void Scanner::scanToken() while (token == Token::Whitespace); m_nextToken.location.end = sourcePos(); m_nextToken.token = token; - m_nextToken.extendedTokenInfo = tokenExtension; + m_nextToken.extendedTokenInfo = make_tuple(M,N); } bool Scanner::scanEscape() @@ -709,7 +711,7 @@ Token::Value Scanner::scanNumber(char _charSeen) return Token::Number; } -tuple<Token::Value, string> Scanner::scanIdentifierOrKeyword() +tuple<Token::Value, unsigned, unsigned> Scanner::scanIdentifierOrKeyword() { solAssert(isIdentifierStart(m_char), ""); LiteralScope literal(this, LITERAL_TYPE_STRING); diff --git a/libsolidity/parsing/Scanner.h b/libsolidity/parsing/Scanner.h index fa1f118b..8dde922d 100644 --- a/libsolidity/parsing/Scanner.h +++ b/libsolidity/parsing/Scanner.h @@ -122,7 +122,7 @@ public: SourceLocation currentLocation() const { return m_currentToken.location; } std::string const& currentLiteral() const { return m_currentToken.literal; } - std::string const& currentTokenInfo() const { return m_currentToken.extendedTokenInfo; } + std::tuple<unsigned, unsigned> const& currentTokenInfo() const { return m_currentToken.extendedTokenInfo; } ///@} ///@{ @@ -161,7 +161,7 @@ private: Token::Value token; SourceLocation location; std::string literal; - std::string extendedTokenInfo; + std::tuple<unsigned, unsigned> extendedTokenInfo; }; ///@{ @@ -192,7 +192,7 @@ private: void scanDecimalDigits(); Token::Value scanNumber(char _charSeen = 0); - std::tuple<Token::Value, std::string> scanIdentifierOrKeyword(); + std::tuple<Token::Value, unsigned, unsigned> scanIdentifierOrKeyword(); Token::Value scanString(); Token::Value scanSingleLineDocComment(); diff --git a/libsolidity/parsing/Token.cpp b/libsolidity/parsing/Token.cpp index eaa65344..b07b5c1b 100644 --- a/libsolidity/parsing/Token.cpp +++ b/libsolidity/parsing/Token.cpp @@ -50,36 +50,65 @@ namespace dev namespace solidity { -tuple<string, unsigned int, unsigned int> ElementaryTypeNameToken::parseDetails(Token::Value _baseType, string const& _details) +void ElementaryTypeNameToken::parseDetails(Token::Value _baseType, unsigned const& _first, unsigned const& _second) { solAssert(Token::isElementaryTypeName(_baseType), ""); string baseType = Token::toString(_baseType); - if (_details.length() == 0) - return make_tuple(baseType, 0, 0); + if (_first == 0 && _second == 0) + { + m_name = baseType; + m_firstNumber = _first; + m_secondNumber = _second; + } if (baseType == "bytesM") { + solAssert(_second == 0, "There should not be a second size argument to type bytesM."); for (unsigned m = 1; m <= 32; m++) - if (to_string(m) == _details) - return make_tuple(baseType.substr(0, baseType.size()-1) + to_string(m), m, 0); + if (m == _first) + { + m_name = baseType.substr(0, baseType.size()-1) + to_string(_first); + m_firstNumber = _first; + m_secondNumber = _second; + } } else if (baseType == "uintM" || baseType == "intM") { + solAssert(_second == 0, "There should not be a second size argument to type " + baseType + "."); for (unsigned m = 8; m <= 256; m+=8) - if (to_string(m) == _details) - return make_tuple(baseType.substr(0, baseType.size()-1) + to_string(m), m, 0); + if (m == _first) + { + m_name = baseType.substr(0, baseType.size()-1) + to_string(_first); + m_firstNumber = _first; + m_secondNumber = _second; + } } else if (baseType == "ufixedMxN" || baseType == "fixedMxN") { for (unsigned m = 0; m <= 256; m+=8) for (unsigned n = 8; m + n <= 256; n+=8) - if ((to_string(m) + "x" + to_string(n)) == _details) - return make_tuple(baseType.substr(0, baseType.size()-3) + to_string(m) + "x" + to_string(n), m, n); + if (m == _first && n == _second) + { + m_name = baseType.substr(0, baseType.size()-3) + + to_string(_first) + + "x" + + to_string(_second); + m_firstNumber = _first; + m_secondNumber = _second; + } } - BOOST_THROW_EXCEPTION(Error(Error::Type::TypeError) << - errinfo_comment("Cannot create elementary type name token out of type " + baseType + " and size " + _details) - ); + if (m_name.empty()) + BOOST_THROW_EXCEPTION(Error(Error::Type::TypeError) << + errinfo_comment( + "Cannot create elementary type name token out of type " + + baseType + + " and size(s) " + + to_string(_first) + + " and " + + to_string(_second) + ) + ); } #define T(name, string, precedence) #name, @@ -112,33 +141,68 @@ char const Token::m_tokenType[] = { TOKEN_LIST(KT, KK) }; -tuple<Token::Value, string> Token::fromIdentifierOrKeyword(const string& _literal) +unsigned Token::extractM(string _literal) +{ + try + { + unsigned short m = stoi(_literal.substr(_literal.find_first_of("0123456789"))); + return m; + } + catch(out_of_range& e) + { + return 0; + } +} +pair<unsigned, unsigned> Token::extractMxN(string _literal) +{ + try + { + unsigned short m = stoi(_literal.substr(0, _literal.find_last_of("x") - 1)); + unsigned short n = stoi(_literal.substr(_literal.find_last_of("x") + 1)); + return make_pair(m, n); + } + catch (out_of_range& e) + { + return make_pair(0, 0); + } +} +tuple<Token::Value, unsigned short, unsigned short> Token::fromIdentifierOrKeyword(string const& _literal) { - string token = _literal; - string details; - if (_literal == "uintM" || _literal == "intM" || _literal == "fixedMxN" || _literal == "ufixedMxN" || _literal == "bytesM") - return make_pair(Token::Identifier, details); if (_literal.find_first_of("0123456789") != string::npos) { string baseType = _literal.substr(0, _literal.find_first_of("0123456789")); - short m = stoi(_literal.substr(_literal.find_first_of("0123456789"))); if (baseType == "bytes") { - details = (0 < m && m <= 32) ? to_string(m) : ""; - token = details.empty() ? _literal : baseType + "M"; + unsigned short m = extractM(_literal); + if (0 < m && m <= 32) + return make_tuple(Token::BytesM, m, 0); + return make_tuple(Token::Identifier, 0, 0); } else if (baseType == "uint" || baseType == "int") { - details = (0 < m && m <= 256 && m % 8 == 0) ? to_string(m) : ""; - token = details.empty() ? _literal : baseType + "M"; + unsigned short m = extractM(_literal); + if (0 < m && m <= 256 && m % 8 == 0) + { + if (baseType == "uint") + return make_tuple(Token::UIntM, m, 0); + else + return make_tuple(Token::IntM, m, 0); + } + return make_tuple(Token::Identifier, 0, 0); } else if (baseType == "ufixed" || baseType == "fixed") { - m = stoi(to_string(m).substr(0, to_string(m).find_first_of("x") - 1)); - short n = stoi(_literal.substr(_literal.find_last_of("x") + 1)); - details = (0 < n + m && n + m <= 256 && ((n % 8 == 0) && (m % 8 == 0))) ? - to_string(m) + "x" + to_string(n) : ""; - token = details.empty() ? _literal : baseType + "MxN" ; + unsigned short m; + unsigned short n; + tie(m, n) = extractMxN(_literal); + if (0 < n + m && n + m <= 256 && ((n % 8 == 0) && (m % 8 == 0))) + { + if (baseType == "ufixed") + return make_tuple(Token::UFixedMxN, m, n); + else + return make_tuple(Token::FixedMxN, m, n); + } + return make_tuple(Token::Identifier, 0, 0); } } // The following macros are used inside TOKEN_LIST and cause non-keyword tokens to be ignored @@ -148,8 +212,8 @@ tuple<Token::Value, string> Token::fromIdentifierOrKeyword(const string& _litera static const map<string, Token::Value> keywords({TOKEN_LIST(TOKEN, KEYWORD)}); #undef KEYWORD #undef TOKEN - auto it = keywords.find(token); - return it == keywords.end() ? make_pair(Token::Identifier, details) : make_pair(it->second, details); + auto it = keywords.find(_literal); + return it == keywords.end() ? make_tuple(Token::Identifier, 0, 0) : make_tuple(it->second, 0, 0); } #undef KT diff --git a/libsolidity/parsing/Token.h b/libsolidity/parsing/Token.h index 55b801db..7193627f 100644 --- a/libsolidity/parsing/Token.h +++ b/libsolidity/parsing/Token.h @@ -189,19 +189,19 @@ namespace solidity K(After, "after", 0) \ /* type keywords*/ \ K(Int, "int", 0) \ - K(IntM, "intM", 0) \ + T(IntM, "intM", 0) \ K(UInt, "uint", 0) \ - K(UIntM, "uintM", 0) \ + T(UIntM, "uintM", 0) \ K(Bytes, "bytes", 0) \ - K(BytesM, "bytesM", 0) \ + T(BytesM, "bytesM", 0) \ K(Byte, "byte", 0) \ K(String, "string", 0) \ K(Address, "address", 0) \ K(Bool, "bool", 0) \ K(Fixed, "fixed", 0) \ - K(FixedMxN, "fixedMxN", 0) \ + T(FixedMxN, "fixedMxN", 0) \ K(UFixed, "ufixed", 0) \ - K(UFixedMxN, "ufixedMxN", 0) \ + T(UFixedMxN, "ufixedMxN", 0) \ T(TypesEnd, NULL, 0) /* used as type enum end marker */ \ \ /* Literals */ \ @@ -302,9 +302,14 @@ public: return m_precedence[tok]; } - static std::tuple<Token::Value, std::string> fromIdentifierOrKeyword(std::string const& _name); + static std::tuple<Token::Value, unsigned short, unsigned short> fromIdentifierOrKeyword(std::string const& _literal); private: + // extractM and extractMxN provide a safe way to extract numbers, + // if out_of_range error is thrown, they returns 0s, therefore securing + // the variable's identity as an identifier. + static unsigned extractM(std::string _literal); + static std::pair<unsigned, unsigned> extractMxN(std::string _literal); static char const* const m_name[NUM_TOKENS]; static char const* const m_string[NUM_TOKENS]; static int8_t const m_precedence[NUM_TOKENS]; @@ -314,9 +319,9 @@ private: class ElementaryTypeNameToken { public: - ElementaryTypeNameToken(Token::Value _token, std::string const& _detail) + ElementaryTypeNameToken(Token::Value _token, unsigned const& _firstNumber, unsigned const& _secondNumber) { - std::tie(m_name, m_firstNumber, m_secondNumber) = parseDetails(_token, _detail); + parseDetails(_token, _firstNumber, _secondNumber); m_token = _token; } @@ -331,8 +336,8 @@ private: std::string m_name; unsigned int m_firstNumber; unsigned int m_secondNumber; - /// throws if _details is malformed - std::tuple<std::string, unsigned int, unsigned int> parseDetails(Token::Value _baseType, std::string const& _details); + /// throws if type is not properly sized + void parseDetails(Token::Value _baseType, unsigned const& _first, unsigned const& _second); }; } |