mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Function type state variables.
This commit is contained in:
parent
dd173f83e3
commit
97a3588701
@ -217,7 +217,9 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition(bool _isLibrary)
|
|||||||
if (currentTokenValue == Token::RBrace)
|
if (currentTokenValue == Token::RBrace)
|
||||||
break;
|
break;
|
||||||
else if (currentTokenValue == Token::Function)
|
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)
|
else if (currentTokenValue == Token::Struct)
|
||||||
subNodes.push_back(parseStructDefinition());
|
subNodes.push_back(parseStructDefinition());
|
||||||
else if (currentTokenValue == Token::Enum)
|
else if (currentTokenValue == Token::Enum)
|
||||||
@ -334,7 +336,7 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _forceEmptyN
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(ASTString const* _contractName)
|
ASTPointer<ASTNode> Parser::parseFunctionDefinitionOrFunctionTypeStateVariable(ASTString const* _contractName)
|
||||||
{
|
{
|
||||||
ASTNodeFactory nodeFactory(*this);
|
ASTNodeFactory nodeFactory(*this);
|
||||||
ASTPointer<ASTString> docstring;
|
ASTPointer<ASTString> docstring;
|
||||||
@ -343,6 +345,14 @@ ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(ASTString const*
|
|||||||
|
|
||||||
FunctionHeaderParserResult header = parseFunctionHeader(false, true);
|
FunctionHeaderParserResult header = parseFunctionHeader(false, true);
|
||||||
|
|
||||||
|
if (
|
||||||
|
!header.modifiers.empty() ||
|
||||||
|
!header.name->empty() ||
|
||||||
|
m_scanner->currentToken() == Token::Semicolon ||
|
||||||
|
m_scanner->currentToken() == Token::LBrace
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// this has to be a function
|
||||||
ASTPointer<Block> block = ASTPointer<Block>();
|
ASTPointer<Block> block = ASTPointer<Block>();
|
||||||
nodeFactory.markEndPosition();
|
nodeFactory.markEndPosition();
|
||||||
if (m_scanner->currentToken() != Token::Semicolon)
|
if (m_scanner->currentToken() != Token::Semicolon)
|
||||||
@ -365,6 +375,25 @@ ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(ASTString const*
|
|||||||
header.isPayable,
|
header.isPayable,
|
||||||
block
|
block
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 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()
|
ASTPointer<StructDefinition> Parser::parseStructDefinition()
|
||||||
@ -613,6 +642,21 @@ ASTPointer<UserDefinedTypeName> Parser::parseUserDefinedTypeName()
|
|||||||
return nodeFactory.createNode<UserDefinedTypeName>(identifierPath);
|
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)
|
ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar)
|
||||||
{
|
{
|
||||||
ASTNodeFactory nodeFactory(*this);
|
ASTNodeFactory nodeFactory(*this);
|
||||||
@ -644,16 +688,7 @@ ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar)
|
|||||||
|
|
||||||
if (type)
|
if (type)
|
||||||
// Parse "[...]" postfixes for arrays.
|
// Parse "[...]" postfixes for arrays.
|
||||||
while (m_scanner->currentToken() == Token::LBrack)
|
type = parseTypeNameSuffix(type, nodeFactory);
|
||||||
{
|
|
||||||
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;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,6 +73,7 @@ private:
|
|||||||
ASTPointer<InheritanceSpecifier> parseInheritanceSpecifier();
|
ASTPointer<InheritanceSpecifier> parseInheritanceSpecifier();
|
||||||
Declaration::Visibility parseVisibilitySpecifier(Token::Value _token);
|
Declaration::Visibility parseVisibilitySpecifier(Token::Value _token);
|
||||||
FunctionHeaderParserResult parseFunctionHeader(bool _forceEmptyName, bool _allowModifiers);
|
FunctionHeaderParserResult parseFunctionHeader(bool _forceEmptyName, bool _allowModifiers);
|
||||||
|
ASTPointer<ASTNode> parseFunctionDefinitionOrFunctionTypeStateVariable(ASTString const* _contractName);
|
||||||
ASTPointer<FunctionDefinition> parseFunctionDefinition(ASTString const* _contractName);
|
ASTPointer<FunctionDefinition> parseFunctionDefinition(ASTString const* _contractName);
|
||||||
ASTPointer<StructDefinition> parseStructDefinition();
|
ASTPointer<StructDefinition> parseStructDefinition();
|
||||||
ASTPointer<EnumDefinition> parseEnumDefinition();
|
ASTPointer<EnumDefinition> parseEnumDefinition();
|
||||||
@ -87,6 +88,7 @@ private:
|
|||||||
ASTPointer<ModifierInvocation> parseModifierInvocation();
|
ASTPointer<ModifierInvocation> parseModifierInvocation();
|
||||||
ASTPointer<Identifier> parseIdentifier();
|
ASTPointer<Identifier> parseIdentifier();
|
||||||
ASTPointer<UserDefinedTypeName> parseUserDefinedTypeName();
|
ASTPointer<UserDefinedTypeName> parseUserDefinedTypeName();
|
||||||
|
ASTPointer<TypeName> parseTypeNameSuffix(ASTPointer<TypeName> type, ASTNodeFactory& nodeFactory);
|
||||||
ASTPointer<TypeName> parseTypeName(bool _allowVar);
|
ASTPointer<TypeName> parseTypeName(bool _allowVar);
|
||||||
ASTPointer<FunctionTypeName> parseFunctionType();
|
ASTPointer<FunctionTypeName> parseFunctionType();
|
||||||
ASTPointer<Mapping> parseMapping();
|
ASTPointer<Mapping> parseMapping();
|
||||||
|
@ -7669,7 +7669,33 @@ BOOST_AUTO_TEST_CASE(pass_function_types_externally)
|
|||||||
BOOST_CHECK(callContractFunction("f2(uint256)", 7) == encodeArgs(u256(8)));
|
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)
|
BOOST_AUTO_TEST_CASE(shift_constant_left)
|
||||||
{
|
{
|
||||||
|
@ -1256,7 +1256,26 @@ BOOST_AUTO_TEST_CASE(function_type_in_expression)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(function_type_as_storage_variable)
|
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"(
|
char const* text = R"(
|
||||||
contract test {
|
contract test {
|
||||||
function f(uint x, uint y) returns (uint a) {}
|
function f(uint x, uint y) returns (uint a) {}
|
||||||
|
Loading…
Reference in New Issue
Block a user