|
@ -41,8 +41,11 @@ class Parser::ASTNodeFactory |
|
|
public: |
|
|
public: |
|
|
ASTNodeFactory(Parser const& _parser): |
|
|
ASTNodeFactory(Parser const& _parser): |
|
|
m_parser(_parser), m_location(_parser.getPosition(), -1, _parser.getSourceName()) {} |
|
|
m_parser(_parser), m_location(_parser.getPosition(), -1, _parser.getSourceName()) {} |
|
|
|
|
|
ASTNodeFactory(Parser const& _parser, ASTPointer<ASTNode> const& _childNode): |
|
|
|
|
|
m_parser(_parser), m_location(_childNode->getLocation()) {} |
|
|
|
|
|
|
|
|
void markEndPosition() { m_location.end = m_parser.getEndPosition(); } |
|
|
void markEndPosition() { m_location.end = m_parser.getEndPosition(); } |
|
|
|
|
|
void setLocation(Location const& _location) { m_location = _location; } |
|
|
void setLocationEmpty() { m_location.end = m_location.start; } |
|
|
void setLocationEmpty() { m_location.end = m_location.start; } |
|
|
/// Set the end position to the one of the given node.
|
|
|
/// Set the end position to the one of the given node.
|
|
|
void setEndPositionFromNode(ASTPointer<ASTNode> const& _node) { m_location.end = _node->getLocation().end; } |
|
|
void setEndPositionFromNode(ASTPointer<ASTNode> const& _node) { m_location.end = _node->getLocation().end; } |
|
@ -299,12 +302,20 @@ ASTPointer<EnumDefinition> Parser::parseEnumDefinition() |
|
|
return nodeFactory.createNode<EnumDefinition>(name, members); |
|
|
return nodeFactory.createNode<EnumDefinition>(name, members); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(VarDeclParserOptions const& _options) |
|
|
ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration( |
|
|
|
|
|
VarDeclParserOptions const& _options, ASTPointer<TypeName> const& _lookAheadArrayType) |
|
|
{ |
|
|
{ |
|
|
ASTNodeFactory nodeFactory(*this); |
|
|
ASTNodeFactory nodeFactory = _lookAheadArrayType ? |
|
|
ASTPointer<TypeName> type = parseTypeName(_options.allowVar); |
|
|
ASTNodeFactory(*this, _lookAheadArrayType) : ASTNodeFactory(*this); |
|
|
if (type != nullptr) |
|
|
ASTPointer<TypeName> type; |
|
|
nodeFactory.setEndPositionFromNode(type); |
|
|
if (_lookAheadArrayType) |
|
|
|
|
|
type = _lookAheadArrayType; |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
type = parseTypeName(_options.allowVar); |
|
|
|
|
|
if (type != nullptr) |
|
|
|
|
|
nodeFactory.setEndPositionFromNode(type); |
|
|
|
|
|
} |
|
|
bool isIndexed = false; |
|
|
bool isIndexed = false; |
|
|
ASTPointer<ASTString> identifier; |
|
|
ASTPointer<ASTString> identifier; |
|
|
Token::Value token = m_scanner->getCurrentToken(); |
|
|
Token::Value token = m_scanner->getCurrentToken(); |
|
@ -407,6 +418,7 @@ ASTPointer<Identifier> Parser::parseIdentifier() |
|
|
|
|
|
|
|
|
ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar) |
|
|
ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar) |
|
|
{ |
|
|
{ |
|
|
|
|
|
ASTNodeFactory nodeFactory(*this); |
|
|
ASTPointer<TypeName> type; |
|
|
ASTPointer<TypeName> type; |
|
|
Token::Value token = m_scanner->getCurrentToken(); |
|
|
Token::Value token = m_scanner->getCurrentToken(); |
|
|
if (Token::isElementaryTypeName(token)) |
|
|
if (Token::isElementaryTypeName(token)) |
|
@ -421,9 +433,7 @@ ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar) |
|
|
m_scanner->next(); |
|
|
m_scanner->next(); |
|
|
} |
|
|
} |
|
|
else if (token == Token::Mapping) |
|
|
else if (token == Token::Mapping) |
|
|
{ |
|
|
|
|
|
type = parseMapping(); |
|
|
type = parseMapping(); |
|
|
} |
|
|
|
|
|
else if (token == Token::Identifier) |
|
|
else if (token == Token::Identifier) |
|
|
{ |
|
|
{ |
|
|
ASTNodeFactory nodeFactory(*this); |
|
|
ASTNodeFactory nodeFactory(*this); |
|
@ -432,6 +442,18 @@ ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar) |
|
|
} |
|
|
} |
|
|
else |
|
|
else |
|
|
BOOST_THROW_EXCEPTION(createParserError("Expected type name")); |
|
|
BOOST_THROW_EXCEPTION(createParserError("Expected type name")); |
|
|
|
|
|
|
|
|
|
|
|
// Parse "[...]" postfixes for arrays.
|
|
|
|
|
|
while (m_scanner->getCurrentToken() == Token::LBrack) |
|
|
|
|
|
{ |
|
|
|
|
|
m_scanner->next(); |
|
|
|
|
|
ASTPointer<Expression> length; |
|
|
|
|
|
if (m_scanner->getCurrentToken() != Token::RBrack) |
|
|
|
|
|
length = parseExpression(); |
|
|
|
|
|
nodeFactory.markEndPosition(); |
|
|
|
|
|
expectToken(Token::RBrack); |
|
|
|
|
|
type = nodeFactory.createNode<ArrayTypeName>(type, length); |
|
|
|
|
|
} |
|
|
return type; |
|
|
return type; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -530,7 +552,7 @@ ASTPointer<Statement> Parser::parseStatement() |
|
|
} |
|
|
} |
|
|
// fall-through
|
|
|
// fall-through
|
|
|
default: |
|
|
default: |
|
|
statement = parseVarDeclOrExprStmt(); |
|
|
statement = parseSimpleStatement(); |
|
|
} |
|
|
} |
|
|
expectToken(Token::Semicolon); |
|
|
expectToken(Token::Semicolon); |
|
|
return statement; |
|
|
return statement; |
|
@ -579,7 +601,7 @@ ASTPointer<ForStatement> Parser::parseForStatement() |
|
|
|
|
|
|
|
|
// LTODO: Maybe here have some predicate like peekExpression() instead of checking for semicolon and RParen?
|
|
|
// LTODO: Maybe here have some predicate like peekExpression() instead of checking for semicolon and RParen?
|
|
|
if (m_scanner->getCurrentToken() != Token::Semicolon) |
|
|
if (m_scanner->getCurrentToken() != Token::Semicolon) |
|
|
initExpression = parseVarDeclOrExprStmt(); |
|
|
initExpression = parseSimpleStatement(); |
|
|
expectToken(Token::Semicolon); |
|
|
expectToken(Token::Semicolon); |
|
|
|
|
|
|
|
|
if (m_scanner->getCurrentToken() != Token::Semicolon) |
|
|
if (m_scanner->getCurrentToken() != Token::Semicolon) |
|
@ -598,48 +620,88 @@ ASTPointer<ForStatement> Parser::parseForStatement() |
|
|
body); |
|
|
body); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
ASTPointer<Statement> Parser::parseVarDeclOrExprStmt() |
|
|
ASTPointer<Statement> Parser::parseSimpleStatement() |
|
|
{ |
|
|
{ |
|
|
if (peekVariableDeclarationStatement()) |
|
|
// These two cases are very hard to distinguish:
|
|
|
|
|
|
// x[7 * 20 + 3] a; - x[7 * 20 + 3] = 9;
|
|
|
|
|
|
// In the first case, x is a type name, in the second it is the name of a variable.
|
|
|
|
|
|
int isVariableDeclaration = peekVariableDeclarationStatement(); |
|
|
|
|
|
if (isVariableDeclaration == 1) |
|
|
return parseVariableDeclarationStatement(); |
|
|
return parseVariableDeclarationStatement(); |
|
|
else |
|
|
else if (isVariableDeclaration == -1) |
|
|
return parseExpressionStatement(); |
|
|
return parseExpressionStatement(); |
|
|
|
|
|
|
|
|
|
|
|
// At this point, we have '(Identifier|ElementaryTypeName) "["'.
|
|
|
|
|
|
// We parse '(Identifier|ElementaryTypeName) ( "[" Expression "]" )+' and then decide whether to hand this over
|
|
|
|
|
|
// to ExpressionStatement or create a VariableDeclarationStatement out of it.
|
|
|
|
|
|
ASTPointer<PrimaryExpression> primary; |
|
|
|
|
|
if (m_scanner->getCurrentToken() == Token::Identifier) |
|
|
|
|
|
primary = parseIdentifier(); |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
primary = ASTNodeFactory(*this).createNode<ElementaryTypeNameExpression>(m_scanner->getCurrentToken()); |
|
|
|
|
|
m_scanner->next(); |
|
|
|
|
|
} |
|
|
|
|
|
vector<pair<ASTPointer<Expression>, Location>> indices; |
|
|
|
|
|
solAssert(m_scanner->getCurrentToken() == Token::LBrack, ""); |
|
|
|
|
|
Location indexLocation = primary->getLocation(); |
|
|
|
|
|
bool encounteredEmptyBrackets = false; |
|
|
|
|
|
do |
|
|
|
|
|
{ |
|
|
|
|
|
expectToken(Token::LBrack); |
|
|
|
|
|
ASTPointer<Expression> index; |
|
|
|
|
|
if (m_scanner->getCurrentToken() == Token::RBrack) |
|
|
|
|
|
encounteredEmptyBrackets = true; |
|
|
|
|
|
else |
|
|
|
|
|
index = parseExpression(); |
|
|
|
|
|
indexLocation.end = getEndPosition(); |
|
|
|
|
|
indices.push_back(make_pair(index, indexLocation)); |
|
|
|
|
|
expectToken(Token::RBrack); |
|
|
|
|
|
} |
|
|
|
|
|
while (m_scanner->getCurrentToken() == Token::LBrack); |
|
|
|
|
|
|
|
|
|
|
|
if (m_scanner->getCurrentToken() == Token::Identifier || encounteredEmptyBrackets) |
|
|
|
|
|
return parseVariableDeclarationStatement(typeNameFromArrayIndexStructure(primary, indices)); |
|
|
|
|
|
else |
|
|
|
|
|
return parseExpressionStatement(expressionFromArrayIndexStructure(primary, indices)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
ASTPointer<VariableDeclarationStatement> Parser::parseVariableDeclarationStatement() |
|
|
ASTPointer<VariableDeclarationStatement> Parser::parseVariableDeclarationStatement( |
|
|
|
|
|
ASTPointer<TypeName> const& _lookAheadArrayType) |
|
|
{ |
|
|
{ |
|
|
ASTNodeFactory nodeFactory(*this); |
|
|
|
|
|
VarDeclParserOptions options; |
|
|
VarDeclParserOptions options; |
|
|
options.allowVar = true; |
|
|
options.allowVar = true; |
|
|
options.allowInitialValue = true; |
|
|
options.allowInitialValue = true; |
|
|
ASTPointer<VariableDeclaration> variable = parseVariableDeclaration(options); |
|
|
ASTPointer<VariableDeclaration> variable = parseVariableDeclaration(options, _lookAheadArrayType); |
|
|
|
|
|
ASTNodeFactory nodeFactory(*this, variable); |
|
|
return nodeFactory.createNode<VariableDeclarationStatement>(variable); |
|
|
return nodeFactory.createNode<VariableDeclarationStatement>(variable); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
ASTPointer<ExpressionStatement> Parser::parseExpressionStatement() |
|
|
ASTPointer<ExpressionStatement> Parser::parseExpressionStatement( |
|
|
|
|
|
ASTPointer<Expression> const& _lookAheadArrayExpression) |
|
|
{ |
|
|
{ |
|
|
ASTNodeFactory nodeFactory(*this); |
|
|
ASTPointer<Expression> expression = parseExpression(_lookAheadArrayExpression); |
|
|
ASTPointer<Expression> expression = parseExpression(); |
|
|
return ASTNodeFactory(*this, expression).createNode<ExpressionStatement>(expression); |
|
|
nodeFactory.setEndPositionFromNode(expression); |
|
|
|
|
|
return nodeFactory.createNode<ExpressionStatement>(expression); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
ASTPointer<Expression> Parser::parseExpression() |
|
|
ASTPointer<Expression> Parser::parseExpression( |
|
|
|
|
|
ASTPointer<Expression> const& _lookAheadArrayExpression) |
|
|
{ |
|
|
{ |
|
|
ASTNodeFactory nodeFactory(*this); |
|
|
ASTPointer<Expression> expression = parseBinaryExpression(4, _lookAheadArrayExpression); |
|
|
ASTPointer<Expression> expression = parseBinaryExpression(); |
|
|
|
|
|
if (!Token::isAssignmentOp(m_scanner->getCurrentToken())) |
|
|
if (!Token::isAssignmentOp(m_scanner->getCurrentToken())) |
|
|
return expression; |
|
|
return expression; |
|
|
Token::Value assignmentOperator = expectAssignmentOperator(); |
|
|
Token::Value assignmentOperator = expectAssignmentOperator(); |
|
|
ASTPointer<Expression> rightHandSide = parseExpression(); |
|
|
ASTPointer<Expression> rightHandSide = parseExpression(); |
|
|
|
|
|
ASTNodeFactory nodeFactory(*this, expression); |
|
|
nodeFactory.setEndPositionFromNode(rightHandSide); |
|
|
nodeFactory.setEndPositionFromNode(rightHandSide); |
|
|
return nodeFactory.createNode<Assignment>(expression, assignmentOperator, rightHandSide); |
|
|
return nodeFactory.createNode<Assignment>(expression, assignmentOperator, rightHandSide); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
ASTPointer<Expression> Parser::parseBinaryExpression(int _minPrecedence) |
|
|
ASTPointer<Expression> Parser::parseBinaryExpression(int _minPrecedence, |
|
|
|
|
|
ASTPointer<Expression> const& _lookAheadArrayExpression) |
|
|
{ |
|
|
{ |
|
|
ASTNodeFactory nodeFactory(*this); |
|
|
ASTPointer<Expression> expression = parseUnaryExpression(_lookAheadArrayExpression); |
|
|
ASTPointer<Expression> expression = parseUnaryExpression(); |
|
|
ASTNodeFactory nodeFactory(*this, expression); |
|
|
int precedence = Token::precedence(m_scanner->getCurrentToken()); |
|
|
int precedence = Token::precedence(m_scanner->getCurrentToken()); |
|
|
for (; precedence >= _minPrecedence; --precedence) |
|
|
for (; precedence >= _minPrecedence; --precedence) |
|
|
while (Token::precedence(m_scanner->getCurrentToken()) == precedence) |
|
|
while (Token::precedence(m_scanner->getCurrentToken()) == precedence) |
|
@ -653,11 +715,13 @@ ASTPointer<Expression> Parser::parseBinaryExpression(int _minPrecedence) |
|
|
return expression; |
|
|
return expression; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
ASTPointer<Expression> Parser::parseUnaryExpression() |
|
|
ASTPointer<Expression> Parser::parseUnaryExpression( |
|
|
|
|
|
ASTPointer<Expression> const& _lookAheadArrayExpression) |
|
|
{ |
|
|
{ |
|
|
ASTNodeFactory nodeFactory(*this); |
|
|
ASTNodeFactory nodeFactory = _lookAheadArrayExpression ? |
|
|
|
|
|
ASTNodeFactory(*this, _lookAheadArrayExpression) : ASTNodeFactory(*this); |
|
|
Token::Value token = m_scanner->getCurrentToken(); |
|
|
Token::Value token = m_scanner->getCurrentToken(); |
|
|
if (Token::isUnaryOp(token) || Token::isCountOp(token)) |
|
|
if (!_lookAheadArrayExpression && (Token::isUnaryOp(token) || Token::isCountOp(token))) |
|
|
{ |
|
|
{ |
|
|
// prefix expression
|
|
|
// prefix expression
|
|
|
m_scanner->next(); |
|
|
m_scanner->next(); |
|
@ -668,7 +732,7 @@ ASTPointer<Expression> Parser::parseUnaryExpression() |
|
|
else |
|
|
else |
|
|
{ |
|
|
{ |
|
|
// potential postfix expression
|
|
|
// potential postfix expression
|
|
|
ASTPointer<Expression> subExpression = parseLeftHandSideExpression(); |
|
|
ASTPointer<Expression> subExpression = parseLeftHandSideExpression(_lookAheadArrayExpression); |
|
|
token = m_scanner->getCurrentToken(); |
|
|
token = m_scanner->getCurrentToken(); |
|
|
if (!Token::isCountOp(token)) |
|
|
if (!Token::isCountOp(token)) |
|
|
return subExpression; |
|
|
return subExpression; |
|
@ -678,11 +742,16 @@ ASTPointer<Expression> Parser::parseUnaryExpression() |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
ASTPointer<Expression> Parser::parseLeftHandSideExpression() |
|
|
ASTPointer<Expression> Parser::parseLeftHandSideExpression( |
|
|
|
|
|
ASTPointer<Expression> const& _lookAheadArrayExpression) |
|
|
{ |
|
|
{ |
|
|
ASTNodeFactory nodeFactory(*this); |
|
|
ASTNodeFactory nodeFactory = _lookAheadArrayExpression ? |
|
|
|
|
|
ASTNodeFactory(*this, _lookAheadArrayExpression) : ASTNodeFactory(*this); |
|
|
|
|
|
|
|
|
ASTPointer<Expression> expression; |
|
|
ASTPointer<Expression> expression; |
|
|
if (m_scanner->getCurrentToken() == Token::New) |
|
|
if (_lookAheadArrayExpression) |
|
|
|
|
|
expression = _lookAheadArrayExpression; |
|
|
|
|
|
else if (m_scanner->getCurrentToken() == Token::New) |
|
|
{ |
|
|
{ |
|
|
expectToken(Token::New); |
|
|
expectToken(Token::New); |
|
|
ASTPointer<Identifier> contractName(parseIdentifier()); |
|
|
ASTPointer<Identifier> contractName(parseIdentifier()); |
|
@ -774,10 +843,7 @@ ASTPointer<Expression> Parser::parsePrimaryExpression() |
|
|
m_scanner->next(); |
|
|
m_scanner->next(); |
|
|
} |
|
|
} |
|
|
else |
|
|
else |
|
|
{ |
|
|
|
|
|
BOOST_THROW_EXCEPTION(createParserError("Expected primary expression.")); |
|
|
BOOST_THROW_EXCEPTION(createParserError("Expected primary expression.")); |
|
|
return ASTPointer<Expression>(); // this is not reached
|
|
|
|
|
|
} |
|
|
|
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
return expression; |
|
|
return expression; |
|
@ -824,18 +890,55 @@ pair<vector<ASTPointer<Expression>>, vector<ASTPointer<ASTString>>> Parser::pars |
|
|
return ret; |
|
|
return ret; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int Parser::peekVariableDeclarationStatement() 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 we get an identifier followed by a "[", it can be both ("type[9] a;" or "arr[9] = 7;").
|
|
|
|
|
|
// In all other cases, we have an expression statement.
|
|
|
|
|
|
Token::Value token(m_scanner->getCurrentToken()); |
|
|
|
|
|
bool mightBeTypeName = (Token::isElementaryTypeName(token) || token == Token::Identifier); |
|
|
|
|
|
if (token == Token::Mapping || token == Token::Var || |
|
|
|
|
|
(mightBeTypeName && m_scanner->peekNextToken() == Token::Identifier)) |
|
|
|
|
|
return 1; |
|
|
|
|
|
if (mightBeTypeName && m_scanner->peekNextToken() == Token::LBrack) |
|
|
|
|
|
return 0; |
|
|
|
|
|
return -1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
bool Parser::peekVariableDeclarationStatement() |
|
|
ASTPointer<TypeName> Parser::typeNameFromArrayIndexStructure( |
|
|
|
|
|
ASTPointer<PrimaryExpression> const& _primary, vector<pair<ASTPointer<Expression>, Location>> const& _indices) |
|
|
{ |
|
|
{ |
|
|
// distinguish between variable declaration (and potentially assignment) and expression statement
|
|
|
ASTNodeFactory nodeFactory(*this, _primary); |
|
|
// (which include assignments to other expressions and pre-declared variables)
|
|
|
ASTPointer<TypeName> type; |
|
|
// We have a variable declaration if we get a keyword that specifies a type name, or
|
|
|
if (auto identifier = dynamic_cast<Identifier const*>(_primary.get())) |
|
|
// in the case of a user-defined type, we have two identifiers following each other.
|
|
|
type = nodeFactory.createNode<UserDefinedTypeName>(make_shared<ASTString>(identifier->getName())); |
|
|
return (m_scanner->getCurrentToken() == Token::Mapping || |
|
|
else if (auto typeName = dynamic_cast<ElementaryTypeNameExpression const*>(_primary.get())) |
|
|
m_scanner->getCurrentToken() == Token::Var || |
|
|
type = nodeFactory.createNode<ElementaryTypeName>(typeName->getTypeToken()); |
|
|
((Token::isElementaryTypeName(m_scanner->getCurrentToken()) || |
|
|
else |
|
|
m_scanner->getCurrentToken() == Token::Identifier) && |
|
|
solAssert(false, "Invalid type name for array look-ahead."); |
|
|
m_scanner->peekNextToken() == Token::Identifier)); |
|
|
for (auto const& lengthExpression: _indices) |
|
|
|
|
|
{ |
|
|
|
|
|
nodeFactory.setLocation(lengthExpression.second); |
|
|
|
|
|
type = nodeFactory.createNode<ArrayTypeName>(type, lengthExpression.first); |
|
|
|
|
|
} |
|
|
|
|
|
return type; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ASTPointer<Expression> Parser::expressionFromArrayIndexStructure( |
|
|
|
|
|
ASTPointer<PrimaryExpression> const& _primary, vector<pair<ASTPointer<Expression>, Location>> const& _indices) |
|
|
|
|
|
{ |
|
|
|
|
|
ASTNodeFactory nodeFactory(*this, _primary); |
|
|
|
|
|
ASTPointer<Expression> expression(_primary); |
|
|
|
|
|
for (auto const& index: _indices) |
|
|
|
|
|
{ |
|
|
|
|
|
nodeFactory.setLocation(index.second); |
|
|
|
|
|
expression = nodeFactory.createNode<IndexAccess>(expression, index.first); |
|
|
|
|
|
} |
|
|
|
|
|
return expression; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void Parser::expectToken(Token::Value _value) |
|
|
void Parser::expectToken(Token::Value _value) |
|
|