aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libsolidity/AST.cpp18
-rw-r--r--libsolidity/AST.h12
-rw-r--r--libsolidity/Parser.cpp12
-rw-r--r--libsolidity/Parser.h8
-rw-r--r--libsolidity/Token.h3
-rw-r--r--libsolidity/grammar.txt2
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp33
-rw-r--r--test/libsolidity/SolidityParser.cpp10
8 files changed, 85 insertions, 13 deletions
diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp
index 1b22c44f..5e51d222 100644
--- a/libsolidity/AST.cpp
+++ b/libsolidity/AST.cpp
@@ -103,6 +103,9 @@ void ContractDefinition::checkTypeRequirements()
));
hashes.insert(hash);
}
+
+ if (isLibrary())
+ checkLibraryRequirements();
}
map<FixedHash<4>, FunctionTypePointer> ContractDefinition::interfaceFunctions() const
@@ -332,6 +335,17 @@ void ContractDefinition::checkExternalTypeClashes() const
));
}
+void ContractDefinition::checkLibraryRequirements() const
+{
+ solAssert(m_isLibrary, "");
+ if (!m_baseContracts.empty())
+ BOOST_THROW_EXCEPTION(createTypeError("Library is not allowed to inherit."));
+
+ for (auto const& var: m_stateVariables)
+ if (!var->isConstant())
+ BOOST_THROW_EXCEPTION(var->createTypeError("Library cannot have non-constant state variables"));
+}
+
vector<ASTPointer<EventDefinition>> const& ContractDefinition::interfaceEvents() const
{
if (!m_interfaceEvents)
@@ -449,6 +463,10 @@ void InheritanceSpecifier::checkTypeRequirements()
ContractDefinition const* base = dynamic_cast<ContractDefinition const*>(&m_baseName->referencedDeclaration());
solAssert(base, "Base contract not available.");
+
+ if (base->isLibrary())
+ BOOST_THROW_EXCEPTION(createTypeError("Libraries cannot be inherited from."));
+
TypePointers parameterTypes = ContractType(*base).constructorType()->parameterTypes();
if (!m_arguments.empty() && parameterTypes.size() != m_arguments.size())
BOOST_THROW_EXCEPTION(createTypeError(
diff --git a/libsolidity/AST.h b/libsolidity/AST.h
index 48790e6a..da6a7d58 100644
--- a/libsolidity/AST.h
+++ b/libsolidity/AST.h
@@ -215,7 +215,7 @@ protected:
/// @}
/**
- * Definition of a contract. This is the only AST nodes where child nodes are not visited in
+ * Definition of a contract or library. This is the only AST nodes where child nodes are not visited in
* document order. It first visits all struct declarations, then all variable declarations and
* finally all function declarations.
*/
@@ -232,7 +232,8 @@ public:
std::vector<ASTPointer<VariableDeclaration>> const& _stateVariables,
std::vector<ASTPointer<FunctionDefinition>> const& _definedFunctions,
std::vector<ASTPointer<ModifierDefinition>> const& _functionModifiers,
- std::vector<ASTPointer<EventDefinition>> const& _events
+ std::vector<ASTPointer<EventDefinition>> const& _events,
+ bool _isLibrary
):
Declaration(_location, _name),
Documented(_documentation),
@@ -243,7 +244,8 @@ public:
m_stateVariables(_stateVariables),
m_definedFunctions(_definedFunctions),
m_functionModifiers(_functionModifiers),
- m_events(_events)
+ m_events(_events),
+ m_isLibrary(_isLibrary)
{}
virtual void accept(ASTVisitor& _visitor) override;
@@ -257,6 +259,7 @@ public:
std::vector<ASTPointer<FunctionDefinition>> const& definedFunctions() const { return m_definedFunctions; }
std::vector<ASTPointer<EventDefinition>> const& events() const { return m_events; }
std::vector<ASTPointer<EventDefinition>> const& interfaceEvents() const;
+ bool isLibrary() const { return m_isLibrary; }
virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
@@ -297,6 +300,8 @@ private:
/// Checks that different functions with external visibility end up having different
/// external argument types (i.e. different signature).
void checkExternalTypeClashes() const;
+ /// Checks that all requirements for a library are fulfilled if this is a library.
+ void checkLibraryRequirements() const;
std::vector<std::pair<FixedHash<4>, FunctionTypePointer>> const& interfaceFunctionList() const;
@@ -307,6 +312,7 @@ private:
std::vector<ASTPointer<FunctionDefinition>> m_definedFunctions;
std::vector<ASTPointer<ModifierDefinition>> m_functionModifiers;
std::vector<ASTPointer<EventDefinition>> m_events;
+ bool m_isLibrary;
// parsed Natspec documentation of the contract.
std::string m_userDocumentation;
diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp
index 7f779ed0..24f7734c 100644
--- a/libsolidity/Parser.cpp
+++ b/libsolidity/Parser.cpp
@@ -71,13 +71,14 @@ ASTPointer<SourceUnit> Parser::parse(shared_ptr<Scanner> const& _scanner)
vector<ASTPointer<ASTNode>> nodes;
while (m_scanner->currentToken() != Token::EOS)
{
- switch (m_scanner->currentToken())
+ switch (auto token = m_scanner->currentToken())
{
case Token::Import:
nodes.push_back(parseImportDirective());
break;
case Token::Contract:
- nodes.push_back(parseContractDefinition());
+ case Token::Library:
+ nodes.push_back(parseContractDefinition(token == Token::Library));
break;
default:
BOOST_THROW_EXCEPTION(createParserError(std::string("Expected import directive or contract definition.")));
@@ -113,13 +114,13 @@ ASTPointer<ImportDirective> Parser::parseImportDirective()
return nodeFactory.createNode<ImportDirective>(url);
}
-ASTPointer<ContractDefinition> Parser::parseContractDefinition()
+ASTPointer<ContractDefinition> Parser::parseContractDefinition(bool _isLibrary)
{
ASTNodeFactory nodeFactory(*this);
ASTPointer<ASTString> docString;
if (m_scanner->currentCommentLiteral() != "")
docString = make_shared<ASTString>(m_scanner->currentCommentLiteral());
- expectToken(Token::Contract);
+ expectToken(_isLibrary ? Token::Library : Token::Contract);
ASTPointer<ASTString> name = expectIdentifierToken();
vector<ASTPointer<InheritanceSpecifier>> baseContracts;
vector<ASTPointer<StructDefinition>> structs;
@@ -177,7 +178,8 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
stateVariables,
functions,
modifiers,
- events
+ events,
+ _isLibrary
);
}
diff --git a/libsolidity/Parser.h b/libsolidity/Parser.h
index 36302f74..79eb73f0 100644
--- a/libsolidity/Parser.h
+++ b/libsolidity/Parser.h
@@ -61,15 +61,17 @@ private:
///@{
///@name Parsing functions for the AST nodes
ASTPointer<ImportDirective> parseImportDirective();
- ASTPointer<ContractDefinition> parseContractDefinition();
+ ASTPointer<ContractDefinition> parseContractDefinition(bool _isLibrary);
ASTPointer<InheritanceSpecifier> parseInheritanceSpecifier();
Declaration::Visibility parseVisibilitySpecifier(Token::Value _token);
ASTPointer<FunctionDefinition> parseFunctionDefinition(ASTString const* _contractName);
ASTPointer<StructDefinition> parseStructDefinition();
ASTPointer<EnumDefinition> parseEnumDefinition();
ASTPointer<EnumValue> parseEnumValue();
- ASTPointer<VariableDeclaration> parseVariableDeclaration(VarDeclParserOptions const& _options = VarDeclParserOptions(),
- ASTPointer<TypeName> const& _lookAheadArrayType = ASTPointer<TypeName>());
+ ASTPointer<VariableDeclaration> parseVariableDeclaration(
+ VarDeclParserOptions const& _options = VarDeclParserOptions(),
+ ASTPointer<TypeName> const& _lookAheadArrayType = ASTPointer<TypeName>()
+ );
ASTPointer<ModifierDefinition> parseModifierDefinition();
ASTPointer<EventDefinition> parseEventDefinition();
ASTPointer<ModifierInvocation> parseModifierInvocation();
diff --git a/libsolidity/Token.h b/libsolidity/Token.h
index bc242ecf..1632a693 100644
--- a/libsolidity/Token.h
+++ b/libsolidity/Token.h
@@ -160,6 +160,7 @@ namespace solidity
K(Internal, "internal", 0) \
K(Import, "import", 0) \
K(Is, "is", 0) \
+ K(Library, "library", 0) \
K(Mapping, "mapping", 0) \
K(Memory, "memory", 0) \
K(Modifier, "modifier", 0) \
@@ -305,7 +306,7 @@ namespace solidity
/* Identifiers (not keywords or future reserved words). */ \
T(Identifier, NULL, 0) \
\
- /* Keywords reserved for future. use. */ \
+ /* Keywords reserved for future use. */ \
K(As, "as", 0) \
K(Case, "case", 0) \
K(Catch, "catch", 0) \
diff --git a/libsolidity/grammar.txt b/libsolidity/grammar.txt
index 6503516c..467aebee 100644
--- a/libsolidity/grammar.txt
+++ b/libsolidity/grammar.txt
@@ -1,4 +1,4 @@
-ContractDefinition = 'contract' Identifier
+ContractDefinition = ( 'contract' | 'library' ) Identifier
( 'is' InheritanceSpecifier (',' InheritanceSpecifier )* )?
'{' ContractPart* '}'
ContractPart = StateVariableDeclaration | StructDefinition | ModifierDefinition | FunctionDefinition | EnumDefinition
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index 883d7807..adff9499 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -2194,6 +2194,39 @@ BOOST_AUTO_TEST_CASE(string_bytes_conversion)
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
}
+BOOST_AUTO_TEST_CASE(inheriting_from_library)
+{
+ char const* text = R"(
+ library Lib {}
+ contract Test is Lib {}
+ )";
+ BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(inheriting_library)
+{
+ char const* text = R"(
+ contract Test {}
+ library Lib is Test {}
+ )";
+ BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(library_having_variables)
+{
+ char const* text = R"(
+ library Lib { uint x; }
+ )";
+ BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(valid_library)
+{
+ char const* text = R"(
+ library Lib { uint constant x = 9; }
+ )";
+ BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
+}
BOOST_AUTO_TEST_CASE(creating_contract_within_the_contract)
{
diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp
index 14b9e9e4..1e034863 100644
--- a/test/libsolidity/SolidityParser.cpp
+++ b/test/libsolidity/SolidityParser.cpp
@@ -924,6 +924,16 @@ BOOST_AUTO_TEST_CASE(empty_comment)
BOOST_CHECK_NO_THROW(parseText(text));
}
+BOOST_AUTO_TEST_CASE(library_simple)
+{
+ char const* text = R"(
+ library Lib {
+ function f() { }
+ }
+ )";
+ BOOST_CHECK_NO_THROW(parseText(text));
+}
+
BOOST_AUTO_TEST_SUITE_END()
}