Function types.

This commit is contained in:
chriseth
2016-11-16 14:37:17 +01:00
parent c811691861
commit cc8583ec7d
17 changed files with 381 additions and 61 deletions
@@ -83,6 +83,23 @@ void ReferencesResolver::endVisit(UserDefinedTypeName const& _typeName)
fatalTypeError(_typeName.location(), "Name has to refer to a struct, enum or contract.");
}
void ReferencesResolver::endVisit(FunctionTypeName const& _typeName)
{
switch (_typeName.visibility())
{
case VariableDeclaration::Visibility::Default:
case VariableDeclaration::Visibility::Internal:
case VariableDeclaration::Visibility::External:
break;
default:
typeError(_typeName.location(), "Invalid visibility, can only be \"external\" or \"internal\".");
}
// Do we allow storage references for external functions?
_typeName.annotation().type = make_shared<FunctionType>(_typeName);
}
void ReferencesResolver::endVisit(Mapping const& _typeName)
{
TypePointer keyType = _typeName.keyType().annotation().type;
@@ -62,6 +62,7 @@ private:
virtual bool visit(Identifier const& _identifier) override;
virtual bool visit(ElementaryTypeName const& _typeName) override;
virtual void endVisit(UserDefinedTypeName const& _typeName) override;
virtual void endVisit(FunctionTypeName const& _typeName) override;
virtual void endVisit(Mapping const& _typeName) override;
virtual void endVisit(ArrayTypeName const& _typeName) override;
virtual bool visit(InlineAssembly const& _inlineAssembly) override;
+35
View File
@@ -822,6 +822,41 @@ private:
std::vector<ASTString> m_namePath;
};
/**
* A literal function type. Its source form is "function (paramType1, paramType2) internal / external returns (retType1, retType2)"
*/
class FunctionTypeName: public TypeName
{
public:
FunctionTypeName(
SourceLocation const& _location,
ASTPointer<ParameterList> const& _parameterTypes,
ASTPointer<ParameterList> const& _returnTypes,
Declaration::Visibility _visibility,
bool _isDeclaredConst,
bool _isPayable
):
TypeName(_location), m_parameterTypes(_parameterTypes), m_returnTypes(_returnTypes),
m_visibility(_visibility), m_isDeclaredConst(_isDeclaredConst), m_isPayable(_isPayable)
{}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
std::vector<ASTPointer<VariableDeclaration>> const& parameterTypes() const { return m_parameterTypes->parameters(); }
std::vector<ASTPointer<VariableDeclaration>> const& returnParameterTypes() const { return m_returnTypes->parameters(); }
Declaration::Visibility visibility() const { return m_visibility; }
bool isDeclaredConst() const { return m_isDeclaredConst; }
bool isPayable() const { return m_isPayable; }
private:
ASTPointer<ParameterList> m_parameterTypes;
ASTPointer<ParameterList> m_returnTypes;
Declaration::Visibility m_visibility;
bool m_isDeclaredConst;
bool m_isPayable;
};
/**
* A mapping type. Its source form is "mapping('keyType' => 'valueType')"
*/
+1
View File
@@ -54,6 +54,7 @@ class MagicVariableDeclaration;
class TypeName;
class ElementaryTypeName;
class UserDefinedTypeName;
class FunctionTypeName;
class Mapping;
class ArrayTypeName;
class Statement;
+14
View File
@@ -226,6 +226,15 @@ bool ASTJsonConverter::visit(UserDefinedTypeName const& _node)
return true;
}
bool ASTJsonConverter::visit(FunctionTypeName const& _node)
{
addJsonNode(_node, "FunctionTypeName", {
make_pair("payable", _node.isPayable()),
make_pair("constant", _node.isDeclaredConst())
});
return true;
}
bool ASTJsonConverter::visit(Mapping const& _node)
{
addJsonNode(_node, "Mapping", {}, true);
@@ -507,6 +516,11 @@ void ASTJsonConverter::endVisit(UserDefinedTypeName const&)
{
}
void ASTJsonConverter::endVisit(FunctionTypeName const&)
{
goUp();
}
void ASTJsonConverter::endVisit(Mapping const&)
{
goUp();
+2
View File
@@ -69,6 +69,7 @@ public:
bool visit(TypeName const& _node) override;
bool visit(ElementaryTypeName const& _node) override;
bool visit(UserDefinedTypeName const& _node) override;
bool visit(FunctionTypeName const& _node) override;
bool visit(Mapping const& _node) override;
bool visit(ArrayTypeName const& _node) override;
bool visit(InlineAssembly const& _node) override;
@@ -114,6 +115,7 @@ public:
void endVisit(TypeName const&) override;
void endVisit(ElementaryTypeName const&) override;
void endVisit(UserDefinedTypeName const&) override;
void endVisit(FunctionTypeName const&) override;
void endVisit(Mapping const&) override;
void endVisit(ArrayTypeName const&) override;
void endVisit(InlineAssembly const&) override;
+12
View File
@@ -164,6 +164,13 @@ bool ASTPrinter::visit(UserDefinedTypeName const& _node)
return goDeeper();
}
bool ASTPrinter::visit(FunctionTypeName const& _node)
{
writeLine("FunctionTypeName");
printSourcePart(_node);
return goDeeper();
}
bool ASTPrinter::visit(Mapping const& _node)
{
writeLine("Mapping");
@@ -442,6 +449,11 @@ void ASTPrinter::endVisit(UserDefinedTypeName const&)
m_indentation--;
}
void ASTPrinter::endVisit(FunctionTypeName const&)
{
m_indentation--;
}
void ASTPrinter::endVisit(Mapping const&)
{
m_indentation--;
+2
View File
@@ -63,6 +63,7 @@ public:
bool visit(TypeName const& _node) override;
bool visit(ElementaryTypeName const& _node) override;
bool visit(UserDefinedTypeName const& _node) override;
bool visit(FunctionTypeName const& _node) override;
bool visit(Mapping const& _node) override;
bool visit(ArrayTypeName const& _node) override;
bool visit(InlineAssembly const& _node) override;
@@ -106,6 +107,7 @@ public:
void endVisit(TypeName const&) override;
void endVisit(ElementaryTypeName const&) override;
void endVisit(UserDefinedTypeName const&) override;
void endVisit(FunctionTypeName const&) override;
void endVisit(Mapping const&) override;
void endVisit(ArrayTypeName const&) override;
void endVisit(InlineAssembly const&) override;
+4
View File
@@ -61,6 +61,7 @@ public:
virtual bool visit(TypeName& _node) { return visitNode(_node); }
virtual bool visit(ElementaryTypeName& _node) { return visitNode(_node); }
virtual bool visit(UserDefinedTypeName& _node) { return visitNode(_node); }
virtual bool visit(FunctionTypeName& _node) { return visitNode(_node); }
virtual bool visit(Mapping& _node) { return visitNode(_node); }
virtual bool visit(ArrayTypeName& _node) { return visitNode(_node); }
virtual bool visit(InlineAssembly& _node) { return visitNode(_node); }
@@ -106,6 +107,7 @@ public:
virtual void endVisit(TypeName& _node) { endVisitNode(_node); }
virtual void endVisit(ElementaryTypeName& _node) { endVisitNode(_node); }
virtual void endVisit(UserDefinedTypeName& _node) { endVisitNode(_node); }
virtual void endVisit(FunctionTypeName& _node) { endVisitNode(_node); }
virtual void endVisit(Mapping& _node) { endVisitNode(_node); }
virtual void endVisit(ArrayTypeName& _node) { endVisitNode(_node); }
virtual void endVisit(InlineAssembly& _node) { endVisitNode(_node); }
@@ -163,6 +165,7 @@ public:
virtual bool visit(TypeName const& _node) { return visitNode(_node); }
virtual bool visit(ElementaryTypeName const& _node) { return visitNode(_node); }
virtual bool visit(UserDefinedTypeName const& _node) { return visitNode(_node); }
virtual bool visit(FunctionTypeName const& _node) { return visitNode(_node); }
virtual bool visit(Mapping const& _node) { return visitNode(_node); }
virtual bool visit(ArrayTypeName const& _node) { return visitNode(_node); }
virtual bool visit(Block const& _node) { return visitNode(_node); }
@@ -208,6 +211,7 @@ public:
virtual void endVisit(TypeName const& _node) { endVisitNode(_node); }
virtual void endVisit(ElementaryTypeName const& _node) { endVisitNode(_node); }
virtual void endVisit(UserDefinedTypeName const& _node) { endVisitNode(_node); }
virtual void endVisit(FunctionTypeName const& _node) { endVisitNode(_node); }
virtual void endVisit(Mapping const& _node) { endVisitNode(_node); }
virtual void endVisit(ArrayTypeName const& _node) { endVisitNode(_node); }
virtual void endVisit(Block const& _node) { endVisitNode(_node); }
+20
View File
@@ -327,6 +327,26 @@ void UserDefinedTypeName::accept(ASTConstVisitor& _visitor) const
_visitor.endVisit(*this);
}
void FunctionTypeName::accept(ASTVisitor& _visitor)
{
if (_visitor.visit(*this))
{
m_parameterTypes->accept(_visitor);
m_returnTypes->accept(_visitor);
}
_visitor.endVisit(*this);
}
void FunctionTypeName::accept(ASTConstVisitor& _visitor) const
{
if (_visitor.visit(*this))
{
m_parameterTypes->accept(_visitor);
m_returnTypes->accept(_visitor);
}
_visitor.endVisit(*this);
}
void Mapping::accept(ASTVisitor& _visitor)
{
if (_visitor.visit(*this))
+61 -4
View File
@@ -1805,6 +1805,23 @@ FunctionType::FunctionType(EventDefinition const& _event):
swap(paramNames, m_parameterNames);
}
FunctionType::FunctionType(FunctionTypeName const& _typeName):
m_location(_typeName.visibility() == VariableDeclaration::Visibility::External ? Location::External : Location::Internal),
m_isConstant(_typeName.isDeclaredConst()),
m_isPayable(_typeName.isPayable())
{
for (auto const& t: _typeName.parameterTypes())
{
solAssert(t->annotation().type, "Type not set for parameter.");
m_parameterTypes.push_back(t->annotation().type);
}
for (auto const& t: _typeName.returnParameterTypes())
{
solAssert(t->annotation().type, "Type not set for return parameter.");
m_returnParameterTypes.push_back(t->annotation().type);
}
}
FunctionTypePointer FunctionType::newExpressionType(ContractDefinition const& _contract)
{
FunctionDefinition const* constructor = _contract.constructor();
@@ -1885,17 +1902,47 @@ string FunctionType::toString(bool _short) const
string name = "function (";
for (auto it = m_parameterTypes.begin(); it != m_parameterTypes.end(); ++it)
name += (*it)->toString(_short) + (it + 1 == m_parameterTypes.end() ? "" : ",");
name += ") returns (";
name += ") ";
if (m_isConstant)
name += "constant ";
if (m_isPayable)
name += "payable ";
if (m_location == Location::External)
name += "external ";
name += "returns (";
for (auto it = m_returnParameterTypes.begin(); it != m_returnParameterTypes.end(); ++it)
name += (*it)->toString(_short) + (it + 1 == m_returnParameterTypes.end() ? "" : ",");
return name + ")";
}
unsigned FunctionType::calldataEncodedSize(bool _padded) const
{
unsigned size = storageBytes();
if (_padded)
size = ((size + 31) / 32) * 32;
return size;
}
u256 FunctionType::storageSize() const
{
BOOST_THROW_EXCEPTION(
InternalCompilerError()
<< errinfo_comment("Storage size of non-storable function type requested."));
if (m_location == Location::External || m_location == Location::Internal)
return 1;
else
BOOST_THROW_EXCEPTION(
InternalCompilerError()
<< errinfo_comment("Storage size of non-storable function type requested."));
}
unsigned FunctionType::storageBytes() const
{
if (m_location == Location::External)
return 20 + 4;
else if (m_location == Location::Internal)
return 8; // it should really not be possible to create larger programs
else
BOOST_THROW_EXCEPTION(
InternalCompilerError()
<< errinfo_comment("Storage size of non-storable function type requested."));
}
unsigned FunctionType::sizeOnStack() const
@@ -2018,6 +2065,16 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con
}
}
TypePointer FunctionType::interfaceType(bool _inLibrary) const
{
if (m_location != Location::External && m_location != Location::Internal)
return TypePointer();
if (_inLibrary)
return shared_from_this();
else
return make_shared<FixedBytesType>(storageBytes());
}
bool FunctionType::canTakeArguments(TypePointers const& _argumentTypes, TypePointer const& _selfType) const
{
solAssert(!bound() || _selfType, "");
+8 -2
View File
@@ -821,6 +821,8 @@ public:
explicit FunctionType(VariableDeclaration const& _varDecl);
/// Creates the function type of an event.
explicit FunctionType(EventDefinition const& _event);
/// Creates the type of a function type name.
explicit FunctionType(FunctionTypeName const& _typeName);
/// Function type constructor to be used for a plain type (not derived from a declaration).
FunctionType(
strings const& _parameterTypes,
@@ -891,11 +893,15 @@ public:
virtual bool operator==(Type const& _other) const override;
virtual std::string toString(bool _short) const override;
virtual bool canBeStored() const override { return false; }
virtual unsigned calldataEncodedSize(bool _padded) const override;
virtual bool canBeStored() const override { return m_location == Location::Internal || m_location == Location::External; }
virtual u256 storageSize() const override;
virtual bool canLiveOutsideStorage() const override { return false; }
virtual unsigned storageBytes() const override;
virtual bool isValueType() const override { return true; }
virtual bool canLiveOutsideStorage() const override { return m_location == Location::Internal || m_location == Location::External; }
virtual unsigned sizeOnStack() const override;
virtual MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
virtual TypePointer interfaceType(bool _inLibrary) const override;
/// @returns TypePointer of a new FunctionType object. All input/return parameters are an
/// appropriate external types (i.e. the interfaceType()s) of input/return parameters of
+72 -55
View File
@@ -288,6 +288,52 @@ Declaration::Visibility Parser::parseVisibilitySpecifier(Token::Value _token)
return visibility;
}
Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _forceEmptyName, bool _allowModifiers)
{
FunctionHeaderParserResult result;
expectToken(Token::Function);
if (_forceEmptyName || m_scanner->currentToken() == Token::LParen)
result.name = make_shared<ASTString>(); // anonymous function
else
result.name = expectIdentifierToken();
VarDeclParserOptions options;
options.allowLocationSpecifier = true;
result.parameters = parseParameterList(options);
while (true)
{
Token::Value token = m_scanner->currentToken();
if (token == Token::Const)
{
result.isDeclaredConst = true;
m_scanner->next();
}
else if (m_scanner->currentToken() == Token::Payable)
{
result.isPayable = true;
m_scanner->next();
}
else if (_allowModifiers && token == Token::Identifier)
result.modifiers.push_back(parseModifierInvocation());
else if (Token::isVisibilitySpecifier(token))
{
if (result.visibility != Declaration::Visibility::Default)
fatalParserError(string("Multiple visibility specifiers."));
result.visibility = parseVisibilitySpecifier(token);
}
else
break;
}
if (m_scanner->currentToken() == Token::Returns)
{
bool const permitEmptyParameterList = false;
m_scanner->next();
result.returnParameters = parseParameterList(options, permitEmptyParameterList);
}
else
result.returnParameters = createEmptyParameterList();
return result;
}
ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(ASTString const* _contractName)
{
ASTNodeFactory nodeFactory(*this);
@@ -295,52 +341,8 @@ ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(ASTString const*
if (m_scanner->currentCommentLiteral() != "")
docstring = make_shared<ASTString>(m_scanner->currentCommentLiteral());
expectToken(Token::Function);
ASTPointer<ASTString> name;
if (m_scanner->currentToken() == Token::LParen)
name = make_shared<ASTString>(); // anonymous function
else
name = expectIdentifierToken();
VarDeclParserOptions options;
options.allowLocationSpecifier = true;
ASTPointer<ParameterList> parameters(parseParameterList(options));
bool isDeclaredConst = false;
bool isPayable = false;
Declaration::Visibility visibility(Declaration::Visibility::Default);
vector<ASTPointer<ModifierInvocation>> modifiers;
while (true)
{
Token::Value token = m_scanner->currentToken();
if (token == Token::Const)
{
isDeclaredConst = true;
m_scanner->next();
}
else if (m_scanner->currentToken() == Token::Payable)
{
isPayable = true;
m_scanner->next();
}
else if (token == Token::Identifier)
modifiers.push_back(parseModifierInvocation());
else if (Token::isVisibilitySpecifier(token))
{
if (visibility != Declaration::Visibility::Default)
fatalParserError(string("Multiple visibility specifiers."));
visibility = parseVisibilitySpecifier(token);
}
else
break;
}
ASTPointer<ParameterList> returnParameters;
if (m_scanner->currentToken() == Token::Returns)
{
bool const permitEmptyParameterList = false;
m_scanner->next();
returnParameters = parseParameterList(options, permitEmptyParameterList);
}
else
returnParameters = createEmptyParameterList();
FunctionHeaderParserResult header = parseFunctionHeader(false, true);
ASTPointer<Block> block = ASTPointer<Block>();
nodeFactory.markEndPosition();
if (m_scanner->currentToken() != Token::Semicolon)
@@ -350,17 +352,17 @@ ASTPointer<FunctionDefinition> 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<FunctionDefinition>(
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<TypeName> 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<TypeName> Parser::parseTypeName(bool _allowVar)
return type;
}
ASTPointer<FunctionTypeName> Parser::parseFunctionType()
{
ASTNodeFactory nodeFactory(*this);
FunctionHeaderParserResult header = parseFunctionHeader(true, false);
return nodeFactory.createNode<FunctionTypeName>(
header.parameters,
header.returnParameters,
header.visibility,
header.isDeclaredConst,
header.isPayable
);
}
ASTPointer<Mapping> 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)
{
+14
View File
@@ -53,6 +53,18 @@ private:
bool allowLocationSpecifier = false;
};
/// This struct is shared for parsing a function header and a function type.
struct FunctionHeaderParserResult
{
ASTPointer<ASTString> name;
ASTPointer<ParameterList> parameters;
ASTPointer<ParameterList> returnParameters;
Declaration::Visibility visibility = Declaration::Visibility::Default;
bool isDeclaredConst = false;
bool isPayable = false;
std::vector<ASTPointer<ModifierInvocation>> modifiers;
};
///@{
///@name Parsing functions for the AST nodes
ASTPointer<PragmaDirective> parsePragmaDirective();
@@ -60,6 +72,7 @@ private:
ASTPointer<ContractDefinition> parseContractDefinition(bool _isLibrary);
ASTPointer<InheritanceSpecifier> parseInheritanceSpecifier();
Declaration::Visibility parseVisibilitySpecifier(Token::Value _token);
FunctionHeaderParserResult parseFunctionHeader(bool _forceEmptyName, bool _allowModifiers);
ASTPointer<FunctionDefinition> parseFunctionDefinition(ASTString const* _contractName);
ASTPointer<StructDefinition> parseStructDefinition();
ASTPointer<EnumDefinition> parseEnumDefinition();
@@ -75,6 +88,7 @@ private:
ASTPointer<Identifier> parseIdentifier();
ASTPointer<UserDefinedTypeName> parseUserDefinedTypeName();
ASTPointer<TypeName> parseTypeName(bool _allowVar);
ASTPointer<FunctionTypeName> parseFunctionType();
ASTPointer<Mapping> parseMapping();
ASTPointer<ParameterList> parseParameterList(
VarDeclParserOptions const& _options,