aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchriseth <c@ethdev.com>2016-10-11 05:06:44 +0800
committerchriseth <c@ethdev.com>2016-11-16 21:37:17 +0800
commit97a3588701edafe9112f35272b5d4c6e23e574b9 (patch)
treeae688346b781554764aa15b638f076847af82504
parentdd173f83e3a6a9046d1aa7e64cb171598a73b272 (diff)
downloaddexon-solidity-97a3588701edafe9112f35272b5d4c6e23e574b9.tar.gz
dexon-solidity-97a3588701edafe9112f35272b5d4c6e23e574b9.tar.zst
dexon-solidity-97a3588701edafe9112f35272b5d4c6e23e574b9.zip
Function type state variables.
-rw-r--r--libsolidity/parsing/Parser.cpp97
-rw-r--r--libsolidity/parsing/Parser.h2
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp28
-rw-r--r--test/libsolidity/SolidityParser.cpp21
4 files changed, 115 insertions, 33 deletions
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<ContractDefinition> 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<FunctionDefinition> Parser::parseFunctionDefinition(ASTString const* _contractName)
+ASTPointer<ASTNode> Parser::parseFunctionDefinitionOrFunctionTypeStateVariable(ASTString const* _contractName)
{
ASTNodeFactory nodeFactory(*this);
ASTPointer<ASTString> docstring;
@@ -343,28 +345,55 @@ ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(ASTString const*
FunctionHeaderParserResult header = parseFunctionHeader(false, true);
- ASTPointer<Block> block = ASTPointer<Block>();
- 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> block = ASTPointer<Block>();
+ 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<FunctionDefinition>(
+ 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<FunctionDefinition>(
- 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<TypeName> type = nodeFactory.createNode<FunctionTypeName>(
+ 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<StructDefinition> Parser::parseStructDefinition()
@@ -613,6 +642,21 @@ ASTPointer<UserDefinedTypeName> Parser::parseUserDefinedTypeName()
return nodeFactory.createNode<UserDefinedTypeName>(identifierPath);
}
+ASTPointer<TypeName> Parser::parseTypeNameSuffix(ASTPointer<TypeName> type, ASTNodeFactory& nodeFactory)
+{
+ while (m_scanner->currentToken() == Token::LBrack)
+ {
+ m_scanner->next();
+ ASTPointer<Expression> length;
+ if (m_scanner->currentToken() != Token::RBrack)
+ length = parseExpression();
+ nodeFactory.markEndPosition();
+ expectToken(Token::RBrack);
+ type = nodeFactory.createNode<ArrayTypeName>(type, length);
+ }
+ return type;
+}
+
ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar)
{
ASTNodeFactory nodeFactory(*this);
@@ -644,16 +688,7 @@ ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar)
if (type)
// Parse "[...]" postfixes for arrays.
- while (m_scanner->currentToken() == Token::LBrack)
- {
- m_scanner->next();
- ASTPointer<Expression> length;
- if (m_scanner->currentToken() != Token::RBrack)
- length = parseExpression();
- nodeFactory.markEndPosition();
- expectToken(Token::RBrack);
- type = nodeFactory.createNode<ArrayTypeName>(type, length);
- }
+ type = parseTypeNameSuffix(type, nodeFactory);
return type;
}
diff --git a/libsolidity/parsing/Parser.h b/libsolidity/parsing/Parser.h
index a59d2688..9295a7fa 100644
--- a/libsolidity/parsing/Parser.h
+++ b/libsolidity/parsing/Parser.h
@@ -73,6 +73,7 @@ private:
ASTPointer<InheritanceSpecifier> parseInheritanceSpecifier();
Declaration::Visibility parseVisibilitySpecifier(Token::Value _token);
FunctionHeaderParserResult parseFunctionHeader(bool _forceEmptyName, bool _allowModifiers);
+ ASTPointer<ASTNode> parseFunctionDefinitionOrFunctionTypeStateVariable(ASTString const* _contractName);
ASTPointer<FunctionDefinition> parseFunctionDefinition(ASTString const* _contractName);
ASTPointer<StructDefinition> parseStructDefinition();
ASTPointer<EnumDefinition> parseEnumDefinition();
@@ -87,6 +88,7 @@ private:
ASTPointer<ModifierInvocation> parseModifierInvocation();
ASTPointer<Identifier> parseIdentifier();
ASTPointer<UserDefinedTypeName> parseUserDefinedTypeName();
+ ASTPointer<TypeName> parseTypeNameSuffix(ASTPointer<TypeName> type, ASTNodeFactory& nodeFactory);
ASTPointer<TypeName> parseTypeName(bool _allowVar);
ASTPointer<FunctionTypeName> parseFunctionType();
ASTPointer<Mapping> parseMapping();
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 76df1970..0f392cab 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -7669,7 +7669,33 @@ BOOST_AUTO_TEST_CASE(pass_function_types_externally)
BOOST_CHECK(callContractFunction("f2(uint256)", 7) == encodeArgs(u256(8)));
}
-// TODO: storage, arrays
+BOOST_AUTO_TEST_CASE(store_function)
+{
+ char const* sourceCode = R"(
+ contract Other {
+ function addTwo(uint x) returns (uint) { return x + 2; }
+ }
+ contract C {
+ function (unction (uint) external returns (uint)) returns (uint) ev = eval;
+ function (uint) external returns (uint) x;
+ function store(function(uint) external returns (uint) y) {
+ x = y;
+ }
+ function eval(function(uint) external returns (uint) y) returns (uint) {
+ return y(7);
+ }
+ function t() returns (uint) {
+ this.store((new Other()).addTwo);
+ return ev(x);
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("t()") == encodeArgs(u256(9)));
+}
+
+// TODO: public function state variables, arrays
BOOST_AUTO_TEST_CASE(shift_constant_left)
{
diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp
index 69b8d0f0..496f4703 100644
--- a/test/libsolidity/SolidityParser.cpp
+++ b/test/libsolidity/SolidityParser.cpp
@@ -1256,7 +1256,26 @@ BOOST_AUTO_TEST_CASE(function_type_in_expression)
BOOST_AUTO_TEST_CASE(function_type_as_storage_variable)
{
- // TODO disambiguate from fallback function
+ char const* text = R"(
+ contract test {
+ function (uint, uint) internal returns (uint) f1;
+ }
+ )";
+ BOOST_CHECK(successParse(text));
+}
+
+BOOST_AUTO_TEST_CASE(function_type_as_storage_variable_with_modifiers)
+{
+ char const* text = R"(
+ contract test {
+ function (uint, uint) modifier1() returns (uint) f1;
+ }
+ )";
+ BOOST_CHECK(!successParse(text));
+}
+
+BOOST_AUTO_TEST_CASE(function_type_as_storage_variable_with_assignment)
+{
char const* text = R"(
contract test {
function f(uint x, uint y) returns (uint a) {}