diff --git a/AST.cpp b/AST.cpp index bc6be6008..20c117c0f 100644 --- a/AST.cpp +++ b/AST.cpp @@ -56,7 +56,12 @@ void ContractDefinition::checkTypeRequirements() FunctionDefinition const* constructor = getConstructor(); if (constructor && !constructor->getReturnParameters().empty()) BOOST_THROW_EXCEPTION(constructor->getReturnParameterList()->createTypeError( - "Non-empty \"returns\" directive for constructor.")); + "Non-empty \"returns\" directive for constructor.")); + + FunctionDefinition const* fallbackFunction = getFallbackFunction(); + if (fallbackFunction && fallbackFunction->getScope() == this && !fallbackFunction->getParameters().empty()) + BOOST_THROW_EXCEPTION(fallbackFunction->getParameterList().createTypeError( + "Fallback function cannot take parameters.")); for (ASTPointer const& modifier: getFunctionModifiers()) modifier->checkTypeRequirements(); @@ -99,6 +104,15 @@ FunctionDefinition const* ContractDefinition::getConstructor() const return nullptr; } +FunctionDefinition const* ContractDefinition::getFallbackFunction() const +{ + for (ContractDefinition const* contract: getLinearizedBaseContracts()) + for (ASTPointer const& f: contract->getDefinedFunctions()) + if (f->getName().empty()) + return f.get(); + return nullptr; +} + void ContractDefinition::checkIllegalOverrides() const { // TODO unify this at a later point. for this we need to put the constness and the access specifier @@ -147,7 +161,7 @@ vector, FunctionTypePointer>> const& ContractDefinition::getIn for (ContractDefinition const* contract: getLinearizedBaseContracts()) { for (ASTPointer const& f: contract->getDefinedFunctions()) - if (f->isPublic() && !f->isConstructor() && functionsSeen.count(f->getName()) == 0) + if (f->isPublic() && !f->isConstructor() && !f->getName().empty() && functionsSeen.count(f->getName()) == 0) { functionsSeen.insert(f->getName()); FixedHash<4> hash(dev::sha3(f->getCanonicalSignature())); diff --git a/AST.h b/AST.h index 6c207290c..3dc63d333 100755 --- a/AST.h +++ b/AST.h @@ -235,8 +235,10 @@ public: std::vector const& getLinearizedBaseContracts() const { return m_linearizedBaseContracts; } void setLinearizedBaseContracts(std::vector const& _bases) { m_linearizedBaseContracts = _bases; } - /// Returns the constructor or nullptr if no constructor was specified + /// Returns the constructor or nullptr if no constructor was specified. FunctionDefinition const* getConstructor() const; + /// Returns the fallback function or nullptr if no constructor was specified. + FunctionDefinition const* getFallbackFunction() const; private: void checkIllegalOverrides() const; diff --git a/Compiler.cpp b/Compiler.cpp index 1fa31ce7d..3c46d4552 100644 --- a/Compiler.cpp +++ b/Compiler.cpp @@ -146,8 +146,8 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract) map, const eth::AssemblyItem> callDataUnpackerEntryPoints; // retrieve the function signature hash from the calldata - m_context << u256(1) << u256(0); - CompilerUtils(m_context).loadFromMemory(0, 4, false, true); + if (!interfaceFunctions.empty()) + CompilerUtils(m_context).loadFromMemory(0, 4, false, true); // stack now is: 1 0 for (auto const& it: interfaceFunctions) @@ -156,7 +156,15 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract) m_context << eth::dupInstruction(1) << u256(FixedHash<4>::Arith(it.first)) << eth::Instruction::EQ; m_context.appendConditionalJumpTo(callDataUnpackerEntryPoints.at(it.first)); } - m_context << eth::Instruction::STOP; // function not found + if (FunctionDefinition const* fallback = _contract.getFallbackFunction()) + { + eth::AssemblyItem returnTag = m_context.pushNewTag(); + fallback->accept(*this); + m_context << returnTag; + appendReturnValuePacker(FunctionType(*fallback).getReturnParameterTypes()); + } + else + m_context << eth::Instruction::STOP; // function not found for (auto const& it: interfaceFunctions) { diff --git a/Parser.cpp b/Parser.cpp index 5cfc8f462..812b3263d 100644 --- a/Parser.cpp +++ b/Parser.cpp @@ -189,7 +189,11 @@ ASTPointer Parser::parseFunctionDefinition(bool _isPublic, A docstring = make_shared(m_scanner->getCurrentCommentLiteral()); expectToken(Token::FUNCTION); - ASTPointer name(expectIdentifierToken()); + ASTPointer name; + if (m_scanner->getCurrentToken() == Token::LPAREN) + name = make_shared(); // anonymous function + else + name = expectIdentifierToken(); ASTPointer parameters(parseParameterList()); bool isDeclaredConst = false; vector> modifiers; diff --git a/Types.cpp b/Types.cpp index bebb4be17..afc1c1dba 100644 --- a/Types.cpp +++ b/Types.cpp @@ -494,7 +494,7 @@ MemberList const& ContractType::getMembers() const { for (ContractDefinition const* base: m_contract.getLinearizedBaseContracts()) for (ASTPointer const& function: base->getDefinedFunctions()) - if (!function->isConstructor()) + if (!function->isConstructor() && !function->getName().empty()) members.insert(make_pair(function->getName(), make_shared(*function, true))); } else @@ -808,7 +808,7 @@ MemberList const& TypeType::getMembers() const // We are accessing the type of a base contract, so add all public and private // functions. Note that this does not add inherited functions on purpose. for (ASTPointer const& f: contract.getDefinedFunctions()) - if (!f->isConstructor()) + if (!f->isConstructor() && !f->getName().empty()) members[f->getName()] = make_shared(*f); } m_members.reset(new MemberList(members));