From 4524ad08701939cc22d28494c57dda1cdfba9e10 Mon Sep 17 00:00:00 2001 From: Rhett Aultman Date: Sat, 30 Jul 2016 00:13:05 -0700 Subject: Add support for do/while loops This commit adds support for a standard do while ; form of statement. While loops were already being supported; supporting a do/while loop mostly involves reusing code from while loops but putting the conditional checking last. --- libsolidity/parsing/Parser.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'libsolidity/parsing/Parser.cpp') diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index 0e99d1e7..52b53619 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -722,6 +722,8 @@ ASTPointer Parser::parseStatement() return parseIfStatement(docString); case Token::While: return parseWhileStatement(docString); + case Token::Do: + return parseDoWhileStatement(docString); case Token::For: return parseForStatement(docString); case Token::LBrace: @@ -816,9 +818,24 @@ ASTPointer Parser::parseWhileStatement(ASTPointer con expectToken(Token::RParen); ASTPointer body = parseStatement(); nodeFactory.setEndPositionFromNode(body); - return nodeFactory.createNode(_docString, condition, body); + return nodeFactory.createNode(_docString, condition, body, false); } +ASTPointer Parser::parseDoWhileStatement(ASTPointer const& _docString) +{ + ASTNodeFactory nodeFactory(*this); + expectToken(Token::Do); + ASTPointer body = parseStatement(); + expectToken(Token::While); + expectToken(Token::LParen); + ASTPointer condition = parseExpression(); + expectToken(Token::RParen); + nodeFactory.markEndPosition(); + expectToken(Token::Semicolon); + return nodeFactory.createNode(_docString, condition, body, true); +} + + ASTPointer Parser::parseForStatement(ASTPointer const& _docString) { ASTNodeFactory nodeFactory(*this); -- cgit v1.2.3 From eee629652e3ee851419805ad1cb54d168fa77763 Mon Sep 17 00:00:00 2001 From: Yoichi Hirai Date: Wed, 9 Nov 2016 14:08:51 +0100 Subject: parsing: ban empty enum definition. --- libsolidity/parsing/Parser.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'libsolidity/parsing/Parser.cpp') diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index 52b53619..df3ed7b2 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -406,6 +406,8 @@ ASTPointer Parser::parseEnumDefinition() if (m_scanner->currentToken() != Token::Identifier) fatalParserError(string("Expected Identifier after ','")); } + if (members.size() == 0) + parserError({"enum with no members is not allowed."}); nodeFactory.markEndPosition(); expectToken(Token::RBrace); -- cgit v1.2.3 From cc8583ec7d6fd86ca7e129475fde32b76d102e79 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 27 Sep 2016 21:37:32 +0200 Subject: Function types. --- libsolidity/parsing/Parser.cpp | 83 +++++++++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 33 deletions(-) (limited to 'libsolidity/parsing/Parser.cpp') diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index df3ed7b2..421e358f 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -288,59 +288,61 @@ Declaration::Visibility Parser::parseVisibilitySpecifier(Token::Value _token) return visibility; } -ASTPointer Parser::parseFunctionDefinition(ASTString const* _contractName) +Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _forceEmptyName, bool _allowModifiers) { - ASTNodeFactory nodeFactory(*this); - ASTPointer docstring; - if (m_scanner->currentCommentLiteral() != "") - docstring = make_shared(m_scanner->currentCommentLiteral()); - + FunctionHeaderParserResult result; expectToken(Token::Function); - ASTPointer name; - if (m_scanner->currentToken() == Token::LParen) - name = make_shared(); // anonymous function + if (_forceEmptyName || m_scanner->currentToken() == Token::LParen) + result.name = make_shared(); // anonymous function else - name = expectIdentifierToken(); + result.name = expectIdentifierToken(); VarDeclParserOptions options; options.allowLocationSpecifier = true; - ASTPointer parameters(parseParameterList(options)); - bool isDeclaredConst = false; - bool isPayable = false; - Declaration::Visibility visibility(Declaration::Visibility::Default); - vector> modifiers; + result.parameters = parseParameterList(options); while (true) { Token::Value token = m_scanner->currentToken(); if (token == Token::Const) { - isDeclaredConst = true; + result.isDeclaredConst = true; m_scanner->next(); } else if (m_scanner->currentToken() == Token::Payable) { - isPayable = true; + result.isPayable = true; m_scanner->next(); } - else if (token == Token::Identifier) - modifiers.push_back(parseModifierInvocation()); + else if (_allowModifiers && token == Token::Identifier) + result.modifiers.push_back(parseModifierInvocation()); else if (Token::isVisibilitySpecifier(token)) { - if (visibility != Declaration::Visibility::Default) + if (result.visibility != Declaration::Visibility::Default) fatalParserError(string("Multiple visibility specifiers.")); - visibility = parseVisibilitySpecifier(token); + result.visibility = parseVisibilitySpecifier(token); } else break; } - ASTPointer returnParameters; if (m_scanner->currentToken() == Token::Returns) { bool const permitEmptyParameterList = false; m_scanner->next(); - returnParameters = parseParameterList(options, permitEmptyParameterList); + result.returnParameters = parseParameterList(options, permitEmptyParameterList); } else - returnParameters = createEmptyParameterList(); + result.returnParameters = createEmptyParameterList(); + return result; +} + +ASTPointer Parser::parseFunctionDefinition(ASTString const* _contractName) +{ + ASTNodeFactory nodeFactory(*this); + ASTPointer docstring; + if (m_scanner->currentCommentLiteral() != "") + docstring = make_shared(m_scanner->currentCommentLiteral()); + + FunctionHeaderParserResult header = parseFunctionHeader(false, true); + ASTPointer block = ASTPointer(); nodeFactory.markEndPosition(); if (m_scanner->currentToken() != Token::Semicolon) @@ -350,17 +352,17 @@ ASTPointer Parser::parseFunctionDefinition(ASTString const* } else m_scanner->next(); // just consume the ';' - bool const c_isConstructor = (_contractName && *name == *_contractName); + bool const c_isConstructor = (_contractName && *header.name == *_contractName); return nodeFactory.createNode( - name, - visibility, + header.name, + header.visibility, c_isConstructor, docstring, - parameters, - isDeclaredConst, - modifiers, - returnParameters, - isPayable, + header.parameters, + header.isDeclaredConst, + header.modifiers, + header.returnParameters, + header.isPayable, block ); } @@ -631,6 +633,8 @@ ASTPointer Parser::parseTypeName(bool _allowVar) fatalParserError(string("Expected explicit type name.")); m_scanner->next(); } + else if (token == Token::Function) + type = parseFunctionType(); else if (token == Token::Mapping) type = parseMapping(); else if (token == Token::Identifier) @@ -653,6 +657,19 @@ ASTPointer Parser::parseTypeName(bool _allowVar) return type; } +ASTPointer Parser::parseFunctionType() +{ + ASTNodeFactory nodeFactory(*this); + FunctionHeaderParserResult header = parseFunctionHeader(true, false); + return nodeFactory.createNode( + header.parameters, + header.returnParameters, + header.visibility, + header.isDeclaredConst, + header.isPayable + ); +} + ASTPointer Parser::parseMapping() { ASTNodeFactory nodeFactory(*this); @@ -1278,7 +1295,7 @@ Parser::LookAheadInfo Parser::peekStatementType() const Token::Value token(m_scanner->currentToken()); bool mightBeTypeName = (Token::isElementaryTypeName(token) || token == Token::Identifier); - if (token == Token::Mapping || token == Token::Var) + if (token == Token::Mapping || token == Token::Function || token == Token::Var) return LookAheadInfo::VariableDeclarationStatement; if (mightBeTypeName) { -- cgit v1.2.3 From 97a3588701edafe9112f35272b5d4c6e23e574b9 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 10 Oct 2016 23:06:44 +0200 Subject: Function type state variables. --- libsolidity/parsing/Parser.cpp | 97 ++++++++++++++++++++++++++++-------------- 1 file changed, 66 insertions(+), 31 deletions(-) (limited to 'libsolidity/parsing/Parser.cpp') diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index 421e358f..e844861b 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -217,7 +217,9 @@ ASTPointer Parser::parseContractDefinition(bool _isLibrary) if (currentTokenValue == Token::RBrace) break; else if (currentTokenValue == Token::Function) - subNodes.push_back(parseFunctionDefinition(name.get())); + // 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())); else if (currentTokenValue == Token::Struct) subNodes.push_back(parseStructDefinition()); else if (currentTokenValue == Token::Enum) @@ -334,7 +336,7 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _forceEmptyN return result; } -ASTPointer Parser::parseFunctionDefinition(ASTString const* _contractName) +ASTPointer Parser::parseFunctionDefinitionOrFunctionTypeStateVariable(ASTString const* _contractName) { ASTNodeFactory nodeFactory(*this); ASTPointer docstring; @@ -343,28 +345,55 @@ ASTPointer Parser::parseFunctionDefinition(ASTString const* FunctionHeaderParserResult header = parseFunctionHeader(false, true); - ASTPointer block = ASTPointer(); - nodeFactory.markEndPosition(); - if (m_scanner->currentToken() != Token::Semicolon) + if ( + !header.modifiers.empty() || + !header.name->empty() || + m_scanner->currentToken() == Token::Semicolon || + m_scanner->currentToken() == Token::LBrace + ) { - block = parseBlock(); - nodeFactory.setEndPositionFromNode(block); + // this has to be a function + ASTPointer block = ASTPointer(); + nodeFactory.markEndPosition(); + if (m_scanner->currentToken() != Token::Semicolon) + { + block = parseBlock(); + nodeFactory.setEndPositionFromNode(block); + } + else + m_scanner->next(); // just consume the ';' + bool const c_isConstructor = (_contractName && *header.name == *_contractName); + return nodeFactory.createNode( + header.name, + header.visibility, + c_isConstructor, + docstring, + header.parameters, + header.isDeclaredConst, + header.modifiers, + header.returnParameters, + header.isPayable, + block + ); } else - m_scanner->next(); // just consume the ';' - bool const c_isConstructor = (_contractName && *header.name == *_contractName); - return nodeFactory.createNode( - header.name, - header.visibility, - c_isConstructor, - docstring, - header.parameters, - header.isDeclaredConst, - header.modifiers, - header.returnParameters, - header.isPayable, - block - ); + { + // this has to be a state variable + ASTPointer type = nodeFactory.createNode( + header.parameters, + header.returnParameters, + header.visibility, + header.isDeclaredConst, + header.isPayable + ); + type = parseTypeNameSuffix(type, nodeFactory); + VarDeclParserOptions options; + options.isStateVariable = true; + options.allowInitialValue = true; + auto node = parseVariableDeclaration(options, type); + expectToken(Token::Semicolon); + return node; + } } ASTPointer Parser::parseStructDefinition() @@ -613,6 +642,21 @@ ASTPointer Parser::parseUserDefinedTypeName() return nodeFactory.createNode(identifierPath); } +ASTPointer Parser::parseTypeNameSuffix(ASTPointer type, ASTNodeFactory& nodeFactory) +{ + while (m_scanner->currentToken() == Token::LBrack) + { + m_scanner->next(); + ASTPointer length; + if (m_scanner->currentToken() != Token::RBrack) + length = parseExpression(); + nodeFactory.markEndPosition(); + expectToken(Token::RBrack); + type = nodeFactory.createNode(type, length); + } + return type; +} + ASTPointer Parser::parseTypeName(bool _allowVar) { ASTNodeFactory nodeFactory(*this); @@ -644,16 +688,7 @@ ASTPointer Parser::parseTypeName(bool _allowVar) if (type) // Parse "[...]" postfixes for arrays. - while (m_scanner->currentToken() == Token::LBrack) - { - m_scanner->next(); - ASTPointer length; - if (m_scanner->currentToken() != Token::RBrack) - length = parseExpression(); - nodeFactory.markEndPosition(); - expectToken(Token::RBrack); - type = nodeFactory.createNode(type, length); - } + type = parseTypeNameSuffix(type, nodeFactory); return type; } -- cgit v1.2.3 From 7a292c9a05eb38f10f6e619db0805105433fda30 Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 11 Nov 2016 15:23:50 +0100 Subject: Fix parser for function type disambiguity. --- libsolidity/parsing/Parser.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'libsolidity/parsing/Parser.cpp') diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index e844861b..02b7d5e0 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -315,7 +315,18 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _forceEmptyN m_scanner->next(); } else if (_allowModifiers && token == Token::Identifier) - result.modifiers.push_back(parseModifierInvocation()); + { + // This can either be a modifier (function declaration) or the name of the + // variable (function type name plus variable). + if ( + m_scanner->peekNextToken() == Token::Semicolon || + m_scanner->peekNextToken() == Token::Assign + ) + // Variable declaration, break here. + break; + else + result.modifiers.push_back(parseModifierInvocation()); + } else if (Token::isVisibilitySpecifier(token)) { if (result.visibility != Declaration::Visibility::Default) -- cgit v1.2.3