diff options
author | chriseth <chris@ethereum.org> | 2018-04-26 16:43:11 +0800 |
---|---|---|
committer | Alex Beregszaszi <alex@rtfs.hu> | 2018-05-16 09:22:45 +0800 |
commit | 67d208d144a179e52e1aab3fbd1bd67fe20176b7 (patch) | |
tree | da475913635f37d7a4a0ca6fc63da1065d0bf435 | |
parent | 2ba0002998d12ea412f17d55b643ec85c02e6a30 (diff) | |
download | dexon-solidity-67d208d144a179e52e1aab3fbd1bd67fe20176b7.tar.gz dexon-solidity-67d208d144a179e52e1aab3fbd1bd67fe20176b7.tar.zst dexon-solidity-67d208d144a179e52e1aab3fbd1bd67fe20176b7.zip |
Parse multi variable declaration statement.
-rw-r--r-- | Changelog.md | 1 | ||||
-rw-r--r-- | libsolidity/parsing/Parser.cpp | 83 |
2 files changed, 76 insertions, 8 deletions
diff --git a/Changelog.md b/Changelog.md index d6f54070..72c27f8e 100644 --- a/Changelog.md +++ b/Changelog.md @@ -7,6 +7,7 @@ Features: * Control Flow Graph: Add Control Flow Graph as analysis structure. * Control Flow Graph: Warn about returning uninitialized storage pointers. * Gas Estimator: Only explore paths with higher gas costs. This reduces accuracy but greatly improves the speed of gas estimation. + * General: Allow multiple variables to be declared as part of a tuple assignment, e.g. ``(uint a, uint b) = ...``. * Optimizer: Remove unnecessary masking of the result of known short instructions (``ADDRESS``, ``CALLER``, ``ORIGIN`` and ``COINBASE``). * Parser: Display nicer error messages by showing the actual tokens and not internal names. * Parser: Use the entire location of the token instead of only its starting position as source location for parser errors. diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index d1be13a5..01c1fa99 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -1086,15 +1086,79 @@ ASTPointer<Statement> Parser::parseSimpleStatement(ASTPointer<ASTString> const& LookAheadInfo statementType; IndexAccessedPath iap; - tie(statementType, iap) = tryParseIndexAccessedPath(); - switch (statementType) + if (m_scanner->currentToken() == Token::LParen) { - case LookAheadInfo::VariableDeclaration: - return parseVariableDeclarationStatement(_docString, typeNameFromIndexAccessStructure(iap)); - case LookAheadInfo::Expression: - return parseExpressionStatement(_docString, expressionFromIndexAccessStructure(iap)); - default: - solAssert(false, ""); + ASTNodeFactory nodeFactory(*this); + size_t emptyComponents = 0; + // First consume all empty components. + expectToken(Token::LParen); + while (m_scanner->currentToken() == Token::Comma) + { + m_scanner->next(); + emptyComponents++; + } + + // Now see whether we have a variable declaration or an expression. + tie(statementType, iap) = tryParseIndexAccessedPath(); + switch (statementType) + { + case LookAheadInfo::VariableDeclaration: + { + vector<ASTPointer<VariableDeclaration>> variables; + ASTPointer<Expression> value; + // We have already parsed something like `(,,,,a.b.c[2][3]` + VarDeclParserOptions options; + options.allowLocationSpecifier = true; + variables = vector<ASTPointer<VariableDeclaration>>(emptyComponents, nullptr); + variables.push_back(parseVariableDeclaration(options, typeNameFromIndexAccessStructure(iap))); + + while (m_scanner->currentToken() != Token::RParen) + { + expectToken(Token::Comma); + if (m_scanner->currentToken() == Token::Comma || m_scanner->currentToken() == Token::RParen) + variables.push_back(nullptr); + else + variables.push_back(parseVariableDeclaration(options)); + } + expectToken(Token::RParen); + expectToken(Token::Assign); + value = parseExpression(); + nodeFactory.setEndPositionFromNode(value); + return nodeFactory.createNode<VariableDeclarationStatement>(_docString, variables, value); + } + case LookAheadInfo::Expression: + { + // Complete parsing the expression in the current component. + vector<ASTPointer<Expression>> components(emptyComponents, nullptr); + components.push_back(parseExpression(expressionFromIndexAccessStructure(iap))); + while (m_scanner->currentToken() != Token::RParen) + { + expectToken(Token::Comma); + if (m_scanner->currentToken() == Token::Comma || m_scanner->currentToken() == Token::RParen) + components.push_back(ASTPointer<Expression>()); + else + components.push_back(parseExpression()); + } + nodeFactory.markEndPosition(); + expectToken(Token::RParen); + return parseExpressionStatement(_docString, nodeFactory.createNode<TupleExpression>(components, false)); + } + default: + solAssert(false, ""); + } + } + else + { + tie(statementType, iap) = tryParseIndexAccessedPath(); + switch (statementType) + { + case LookAheadInfo::VariableDeclaration: + return parseVariableDeclarationStatement(_docString, typeNameFromIndexAccessStructure(iap)); + case LookAheadInfo::Expression: + return parseExpressionStatement(_docString, expressionFromIndexAccessStructure(iap)); + default: + solAssert(false, ""); + } } } @@ -1144,6 +1208,9 @@ ASTPointer<VariableDeclarationStatement> Parser::parseVariableDeclarationStateme ASTPointer<TypeName> const& _lookAheadArrayType ) { + // This does not parse multi variable declaration statements starting directly with + // `(`, they are parsed in parseSimpleStatement, because they are hard to distinguish + // from tuple expressions. RecursionGuard recursionGuard(*this); ASTNodeFactory nodeFactory(*this); if (_lookAheadArrayType) |