Function type state variables.

This commit is contained in:
chriseth 2016-10-10 23:06:44 +02:00
parent dd173f83e3
commit 97a3588701
4 changed files with 115 additions and 33 deletions

View File

@ -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;
} }

View File

@ -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();

View File

@ -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)
{ {

View File

@ -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) {}