aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/parsing/Parser.cpp
diff options
context:
space:
mode:
authorchriseth <chris@ethereum.org>2018-11-14 02:33:35 +0800
committerGitHub <noreply@github.com>2018-11-14 02:33:35 +0800
commit1d4f565a64988a3400847d2655ca24f73f234bc6 (patch)
treecaaa6c26e307513505349b50ca4f2a8a9506752b /libsolidity/parsing/Parser.cpp
parent59dbf8f1085b8b92e8b7eb0ce380cbeb642e97eb (diff)
parent91b6b8a88e76016e0324036cb7a7f9300a1e2439 (diff)
downloaddexon-solidity-1d4f565a64988a3400847d2655ca24f73f234bc6.tar
dexon-solidity-1d4f565a64988a3400847d2655ca24f73f234bc6.tar.gz
dexon-solidity-1d4f565a64988a3400847d2655ca24f73f234bc6.tar.bz2
dexon-solidity-1d4f565a64988a3400847d2655ca24f73f234bc6.tar.lz
dexon-solidity-1d4f565a64988a3400847d2655ca24f73f234bc6.tar.xz
dexon-solidity-1d4f565a64988a3400847d2655ca24f73f234bc6.tar.zst
dexon-solidity-1d4f565a64988a3400847d2655ca24f73f234bc6.zip
Merge pull request #5416 from ethereum/develop
Merge develop into release for 0.5.0
Diffstat (limited to 'libsolidity/parsing/Parser.cpp')
-rw-r--r--libsolidity/parsing/Parser.cpp281
1 files changed, 172 insertions, 109 deletions
diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp
index e2e1eebc..b17dad9a 100644
--- a/libsolidity/parsing/Parser.cpp
+++ b/libsolidity/parsing/Parser.cpp
@@ -20,7 +20,7 @@
* Solidity parser.
*/
-#include <ctype.h>
+#include <cctype>
#include <vector>
#include <libevmasm/SourceLocation.h>
#include <libsolidity/parsing/Parser.h>
@@ -57,7 +57,7 @@ public:
solAssert(m_location.sourceName, "");
if (m_location.end < 0)
markEndPosition();
- return make_shared<NodeType>(m_location, forward<Args>(_args)...);
+ return make_shared<NodeType>(m_location, std::forward<Args>(_args)...);
}
private:
@@ -75,7 +75,7 @@ ASTPointer<SourceUnit> Parser::parse(shared_ptr<Scanner> const& _scanner)
vector<ASTPointer<ASTNode>> nodes;
while (m_scanner->currentToken() != Token::EOS)
{
- switch (auto token = m_scanner->currentToken())
+ switch (m_scanner->currentToken())
{
case Token::Pragma:
nodes.push_back(parsePragmaDirective());
@@ -86,7 +86,7 @@ ASTPointer<SourceUnit> Parser::parse(shared_ptr<Scanner> const& _scanner)
case Token::Interface:
case Token::Contract:
case Token::Library:
- nodes.push_back(parseContractDefinition(token));
+ nodes.push_back(parseContractDefinition());
break;
default:
fatalParserError(string("Expected pragma, import directive or contract/interface/library definition."));
@@ -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);
}
@@ -198,31 +198,35 @@ ASTPointer<ImportDirective> Parser::parseImportDirective()
return nodeFactory.createNode<ImportDirective>(path, unitAlias, move(symbolAliases));
}
-ContractDefinition::ContractKind Parser::tokenToContractKind(Token::Value _token)
+ContractDefinition::ContractKind Parser::parseContractKind()
{
- switch(_token)
+ ContractDefinition::ContractKind kind;
+ switch(m_scanner->currentToken())
{
case Token::Interface:
- return ContractDefinition::ContractKind::Interface;
+ kind = ContractDefinition::ContractKind::Interface;
+ break;
case Token::Contract:
- return ContractDefinition::ContractKind::Contract;
+ kind = ContractDefinition::ContractKind::Contract;
+ break;
case Token::Library:
- return ContractDefinition::ContractKind::Library;
+ kind = ContractDefinition::ContractKind::Library;
+ break;
default:
- fatalParserError("Unsupported contract type.");
+ solAssert(false, "Invalid contract kind.");
}
- // FIXME: fatalParserError is not considered as throwing here
- return ContractDefinition::ContractKind::Contract;
+ m_scanner->next();
+ return kind;
}
-ASTPointer<ContractDefinition> Parser::parseContractDefinition(Token::Value _expectedKind)
+ASTPointer<ContractDefinition> Parser::parseContractDefinition()
{
RecursionGuard recursionGuard(*this);
ASTNodeFactory nodeFactory(*this);
ASTPointer<ASTString> docString;
if (m_scanner->currentCommentLiteral() != "")
docString = make_shared<ASTString>(m_scanner->currentCommentLiteral());
- expectToken(_expectedKind);
+ ContractDefinition::ContractKind contractKind = parseContractKind();
ASTPointer<ASTString> name = expectIdentifierToken();
vector<ASTPointer<InheritanceSpecifier>> baseContracts;
if (m_scanner->currentToken() == Token::Is)
@@ -236,16 +240,13 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition(Token::Value _exp
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::Identifier && m_scanner->currentLiteral() == "constructor")
- )
+ else if (currentTokenValue == Token::Function || currentTokenValue == Token::Constructor)
// This can be a function or a state variable of function type (especially
// complicated to distinguish fallback function from function type state variable)
- subNodes.push_back(parseFunctionDefinitionOrFunctionTypeStateVariable(name.get()));
+ subNodes.push_back(parseFunctionDefinitionOrFunctionTypeStateVariable());
else if (currentTokenValue == Token::Struct)
subNodes.push_back(parseStructDefinition());
else if (currentTokenValue == Token::Enum)
@@ -253,7 +254,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition(Token::Value _exp
else if (
currentTokenValue == Token::Identifier ||
currentTokenValue == Token::Mapping ||
- Token::isElementaryTypeName(currentTokenValue)
+ TokenTraits::isElementaryTypeName(currentTokenValue)
)
{
VarDeclParserOptions options;
@@ -278,7 +279,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition(Token::Value _exp
docString,
baseContracts,
subNodes,
- tokenToContractKind(_expectedKind)
+ contractKind
);
}
@@ -300,70 +301,92 @@ ASTPointer<InheritanceSpecifier> Parser::parseInheritanceSpecifier()
return nodeFactory.createNode<InheritanceSpecifier>(name, std::move(arguments));
}
-Declaration::Visibility Parser::parseVisibilitySpecifier(Token::Value _token)
+Declaration::Visibility Parser::parseVisibilitySpecifier()
{
Declaration::Visibility visibility(Declaration::Visibility::Default);
- if (_token == Token::Public)
- visibility = Declaration::Visibility::Public;
- else if (_token == Token::Internal)
- visibility = Declaration::Visibility::Internal;
- else if (_token == Token::Private)
- visibility = Declaration::Visibility::Private;
- else if (_token == Token::External)
- visibility = Declaration::Visibility::External;
- else
- solAssert(false, "Invalid visibility specifier.");
+ Token token = m_scanner->currentToken();
+ switch (token)
+ {
+ case Token::Public:
+ visibility = Declaration::Visibility::Public;
+ break;
+ case Token::Internal:
+ visibility = Declaration::Visibility::Internal;
+ break;
+ case Token::Private:
+ visibility = Declaration::Visibility::Private;
+ break;
+ case Token::External:
+ visibility = Declaration::Visibility::External;
+ break;
+ default:
+ solAssert(false, "Invalid visibility specifier.");
+ }
m_scanner->next();
return visibility;
}
-StateMutability Parser::parseStateMutability(Token::Value _token)
+StateMutability Parser::parseStateMutability()
{
StateMutability stateMutability(StateMutability::NonPayable);
- if (_token == Token::Payable)
- stateMutability = StateMutability::Payable;
- // FIXME: constant should be removed at the next breaking release
- else if (_token == Token::View || _token == Token::Constant)
- stateMutability = StateMutability::View;
- else if (_token == Token::Pure)
- stateMutability = StateMutability::Pure;
- else
- solAssert(false, "Invalid state mutability specifier.");
+ Token token = m_scanner->currentToken();
+ switch(token)
+ {
+ case Token::Payable:
+ stateMutability = StateMutability::Payable;
+ break;
+ case Token::View:
+ stateMutability = StateMutability::View;
+ break;
+ case Token::Pure:
+ stateMutability = StateMutability::Pure;
+ break;
+ case Token::Constant:
+ stateMutability = StateMutability::View;
+ parserError(
+ "The state mutability modifier \"constant\" was removed in version 0.5.0. "
+ "Use \"view\" or \"pure\" instead."
+ );
+ break;
+ default:
+ solAssert(false, "Invalid state mutability specifier.");
+ }
m_scanner->next();
return stateMutability;
}
-Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(
- bool _forceEmptyName,
- bool _allowModifiers,
- ASTString const* _contractName
-)
+Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _forceEmptyName, bool _allowModifiers)
{
RecursionGuard recursionGuard(*this);
FunctionHeaderParserResult result;
result.isConstructor = false;
- if (m_scanner->currentToken() == Token::Identifier && m_scanner->currentLiteral() == "constructor")
+ if (m_scanner->currentToken() == Token::Constructor)
result.isConstructor = true;
else if (m_scanner->currentToken() != Token::Function)
solAssert(false, "Function or constructor expected.");
m_scanner->next();
- if (result.isConstructor || _forceEmptyName || m_scanner->currentToken() == Token::LParen)
+ if (result.isConstructor)
+ result.name = make_shared<ASTString>();
+ else if (_forceEmptyName || m_scanner->currentToken() == Token::LParen)
result.name = make_shared<ASTString>();
+ else if (m_scanner->currentToken() == Token::Constructor)
+ fatalParserError(string(
+ "This function is named \"constructor\" but is not the constructor of the contract. "
+ "If you intend this to be a constructor, use \"constructor(...) { ... }\" without the \"function\" keyword to define it."
+ ));
else
result.name = expectIdentifierToken();
- if (!result.name->empty() && _contractName && *result.name == *_contractName)
- result.isConstructor = true;
VarDeclParserOptions options;
options.allowLocationSpecifier = true;
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),
@@ -378,7 +401,7 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(
else
result.modifiers.push_back(parseModifierInvocation());
}
- else if (Token::isVisibilitySpecifier(token))
+ else if (TokenTraits::isVisibilitySpecifier(token))
{
if (result.visibility != Declaration::Visibility::Default)
{
@@ -398,9 +421,9 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(
m_scanner->next();
}
else
- result.visibility = parseVisibilitySpecifier(token);
+ result.visibility = parseVisibilitySpecifier();
}
- else if (Token::isStateMutabilitySpecifier(token))
+ else if (TokenTraits::isStateMutabilitySpecifier(token))
{
if (result.stateMutability != StateMutability::NonPayable)
{
@@ -412,7 +435,7 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(
m_scanner->next();
}
else
- result.stateMutability = parseStateMutability(token);
+ result.stateMutability = parseStateMutability();
}
else
break;
@@ -428,7 +451,7 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(
return result;
}
-ASTPointer<ASTNode> Parser::parseFunctionDefinitionOrFunctionTypeStateVariable(ASTString const* _contractName)
+ASTPointer<ASTNode> Parser::parseFunctionDefinitionOrFunctionTypeStateVariable()
{
RecursionGuard recursionGuard(*this);
ASTNodeFactory nodeFactory(*this);
@@ -436,7 +459,7 @@ ASTPointer<ASTNode> Parser::parseFunctionDefinitionOrFunctionTypeStateVariable(A
if (m_scanner->currentCommentLiteral() != "")
docstring = make_shared<ASTString>(m_scanner->currentCommentLiteral());
- FunctionHeaderParserResult header = parseFunctionHeader(false, true, _contractName);
+ FunctionHeaderParserResult header = parseFunctionHeader(false, true);
if (
header.isConstructor ||
@@ -531,7 +554,7 @@ ASTPointer<EnumDefinition> Parser::parseEnumDefinition()
if (m_scanner->currentToken() != Token::Identifier)
fatalParserError(string("Expected identifier after ','"));
}
- if (members.size() == 0)
+ if (members.empty())
parserError({"enum with no members is not allowed."});
nodeFactory.markEndPosition();
@@ -559,14 +582,15 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(
bool isIndexed = false;
bool isDeclaredConst = false;
Declaration::Visibility visibility(Declaration::Visibility::Default);
- VariableDeclaration::Location location = VariableDeclaration::Location::Default;
+ VariableDeclaration::Location location = VariableDeclaration::Location::Unspecified;
ASTPointer<ASTString> identifier;
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)
{
parserError(string(
@@ -577,7 +601,7 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(
m_scanner->next();
}
else
- visibility = parseVisibilitySpecifier(token);
+ visibility = parseVisibilitySpecifier();
}
else
{
@@ -585,36 +609,47 @@ 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::Default)
+ if (location != VariableDeclaration::Location::Unspecified)
parserError(string("Location already specified."));
else if (!type)
parserError(string("Location specifier needs explicit type name."));
else
- location = (
- token == Token::Memory ?
- VariableDeclaration::Location::Memory :
- VariableDeclaration::Location::Storage
- );
+ {
+ switch (token)
+ {
+ case Token::Storage:
+ location = VariableDeclaration::Location::Storage;
+ break;
+ case Token::Memory:
+ location = VariableDeclaration::Location::Memory;
+ break;
+ case Token::CallData:
+ location = VariableDeclaration::Location::CallData;
+ break;
+ default:
+ solAssert(false, "Unknown data location.");
+ }
+ }
}
else
break;
+ nodeFactory.markEndPosition();
m_scanner->next();
}
}
- nodeFactory.markEndPosition();
if (_options.allowEmptyName && m_scanner->currentToken() != Token::Identifier)
{
identifier = make_shared<ASTString>("");
solAssert(!_options.allowVar, ""); // allowEmptyName && allowVar makes no sense
- if (type)
- nodeFactory.setEndPositionFromNode(type);
- // if type is null this has already caused an error
}
else
+ {
+ nodeFactory.markEndPosition();
identifier = expectIdentifierToken();
+ }
ASTPointer<Expression> value;
if (_options.allowInitialValue)
{
@@ -771,15 +806,31 @@ 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;
tie(firstSize, secondSize) = m_scanner->currentTokenInfo();
ElementaryTypeNameToken elemTypeName(token, firstSize, secondSize);
- type = ASTNodeFactory(*this).createNode<ElementaryTypeName>(elemTypeName);
+ ASTNodeFactory nodeFactory(*this);
+ nodeFactory.markEndPosition();
m_scanner->next();
+ auto stateMutability = boost::make_optional(elemTypeName.token() == Token::Address, StateMutability::NonPayable);
+ if (TokenTraits::isStateMutabilitySpecifier(m_scanner->currentToken(), false))
+ {
+ if (elemTypeName.token() == Token::Address)
+ {
+ nodeFactory.markEndPosition();
+ stateMutability = parseStateMutability();
+ }
+ else
+ {
+ parserError("State mutability can only be specified for address types.");
+ m_scanner->next();
+ }
+ }
+ type = nodeFactory.createNode<ElementaryTypeName>(elemTypeName, stateMutability);
}
else if (token == Token::Var)
{
@@ -823,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;
@@ -928,10 +979,11 @@ ASTPointer<Statement> Parser::parseStatement()
}
case Token::Assembly:
return parseInlineAssembly(docString);
+ case Token::Emit:
+ statement = parseEmitStatement(docString);
+ break;
case Token::Identifier:
- if (m_scanner->currentLiteral() == "emit")
- statement = parseEmitStatement(docString);
- else if (m_insideModifier && m_scanner->currentLiteral() == "_")
+ if (m_insideModifier && m_scanner->currentLiteral() == "_")
{
statement = ASTNodeFactory(*this).createNode<PlaceholderStatement>(docString);
m_scanner->next();
@@ -1051,6 +1103,8 @@ ASTPointer<ForStatement> Parser::parseForStatement(ASTPointer<ASTString> const&
ASTPointer<EmitStatement> Parser::parseEmitStatement(ASTPointer<ASTString> const& _docString)
{
+ expectToken(Token::Emit, false);
+
ASTNodeFactory nodeFactory(*this);
m_scanner->next();
ASTNodeFactory eventCallNodeFactory(*this);
@@ -1198,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));
@@ -1288,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();
@@ -1319,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);
@@ -1339,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();
@@ -1353,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();
@@ -1428,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)
@@ -1439,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();
@@ -1447,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();
@@ -1477,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)
@@ -1500,8 +1554,11 @@ ASTPointer<Expression> Parser::parsePrimaryExpression()
expression = nodeFactory.createNode<TupleExpression>(components, isArray);
break;
}
+ case Token::IllegalHex:
+ 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;
@@ -1538,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 })
@@ -1577,19 +1634,25 @@ Parser::LookAheadInfo Parser::peekStatementType() const
// Distinguish between variable declaration (and potentially assignment) and expression statement
// (which include assignments to other expressions and pre-declared variables).
// We have a variable declaration if we get a keyword that specifies a type name.
- // If it is an identifier or an elementary type name followed by an identifier, we also have
- // a variable declaration.
+ // If it is an identifier or an elementary type name followed by an identifier
+ // 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();
- if (next == Token::Identifier || Token::isLocationSpecifier(next))
+ 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 (TokenTraits::isElementaryTypeName(token) && TokenTraits::isStateMutabilitySpecifier(next, false))
+ return LookAheadInfo::VariableDeclaration;
+ if (next == Token::Identifier || TokenTraits::isLocationSpecifier(next))
return LookAheadInfo::VariableDeclaration;
if (next == Token::LBrack || next == Token::Period)
return LookAheadInfo::IndexAccessStructure;