void Compiler::appendInitAndConstructorCode(ContractDefinition const& _contract) { // Determine the arguments that are used for the base constructors. std::vector<ContractDefinition const*> const& bases = _contract.getLinearizedBaseContracts(); for (ContractDefinition const* contract: bases) { if (FunctionDefinition const* constructor = contract->getConstructor()) for (auto const& modifier: constructor->getModifiers()) { auto baseContract = dynamic_cast<ContractDefinition const*>( &modifier->getName()->getReferencedDeclaration()); if (baseContract) if (m_baseArguments.count(baseContract->getConstructor()) == 0) m_baseArguments[baseContract->getConstructor()] = &modifier->getArguments(); } for (ASTPointer<InheritanceSpecifier> const& base: contract->getBaseContracts()) { ContractDefinition const* baseContract = dynamic_cast<ContractDefinition const*>( &base->getName()->getReferencedDeclaration()); solAssert(baseContract, ""); if (m_baseArguments.count(baseContract->getConstructor()) == 0) m_baseArguments[baseContract->getConstructor()] = &base->getArguments(); } } // Initialization of state variables in base-to-derived order. for (ContractDefinition const* contract: boost::adaptors::reverse(bases)) initializeStateVariables(*contract); if (FunctionDefinition const* constructor = _contract.getConstructor()) appendConstructor(*constructor); else if (auto c = m_context.getNextConstructor(_contract)) appendBaseConstructor(*c); }
void Compiler::appendFunctionSelector(ContractDefinition const& _contract) { map<FixedHash<4>, FunctionTypePointer> interfaceFunctions = _contract.getInterfaceFunctions(); map<FixedHash<4>, const eth::AssemblyItem> callDataUnpackerEntryPoints; FunctionDefinition const* fallback = _contract.getFallbackFunction(); eth::AssemblyItem notFound = m_context.newTag(); // shortcut messages without data if we have many functions in order to be able to receive // ether with constant gas if (interfaceFunctions.size() > 5 || fallback) { m_context << eth::Instruction::CALLDATASIZE << eth::Instruction::ISZERO; m_context.appendConditionalJumpTo(notFound); } // retrieve the function signature hash from the calldata if (!interfaceFunctions.empty()) CompilerUtils(m_context).loadFromMemory(0, IntegerType(CompilerUtils::dataStartOffset * 8), true); // stack now is: 1 0 <funhash> for (auto const& it: interfaceFunctions) { callDataUnpackerEntryPoints.insert(std::make_pair(it.first, m_context.newTag())); m_context << eth::dupInstruction(1) << u256(FixedHash<4>::Arith(it.first)) << eth::Instruction::EQ; m_context.appendConditionalJumpTo(callDataUnpackerEntryPoints.at(it.first)); } m_context.appendJumpTo(notFound); m_context << notFound; if (fallback) { 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) { FunctionTypePointer const& functionType = it.second; solAssert(functionType->hasDeclaration(), ""); CompilerContext::LocationSetter locationSetter(m_context, functionType->getDeclaration()); m_context << callDataUnpackerEntryPoints.at(it.first); eth::AssemblyItem returnTag = m_context.pushNewTag(); appendCalldataUnpacker(functionType->getParameterTypes()); m_context.appendJumpTo(m_context.getFunctionEntryLabel(functionType->getDeclaration())); m_context << returnTag; appendReturnValuePacker(functionType->getReturnParameterTypes()); } }
Json::Value functionHashes(ContractDefinition const& _contract) { Json::Value functionHashes(Json::objectValue); for (auto const& it: _contract.interfaceFunctions()) functionHashes[it.second->externalSignature()] = toHex(it.first.ref()); return functionHashes; }
bool DocStringAnalyser::visit(ContractDefinition const& _node) { static const set<string> validTags = set<string>{"author", "title", "dev", "notice", "why3"}; parseDocStrings(_node, _node.annotation(), validTags, "contracts"); return true; }
void Compiler::initializeContext(ContractDefinition const& _contract, map<ContractDefinition const*, bytes const*> const& _contracts) { CompilerUtils(m_context).initialiseFreeMemoryPointer(); m_context.setCompiledContracts(_contracts); m_context.setInheritanceHierarchy(_contract.getLinearizedBaseContracts()); registerStateVariables(_contract); m_context.resetVisitedNodes(&_contract); }
bool ASTPrinter::visit(ContractDefinition const& _node) { writeLine("ContractDefinition \"" + _node.getName() + "\""); printSourcePart(_node); return goDeeper(); }
bool Why3Translator::visit(ContractDefinition const& _contract) { if (m_seenContract) error(_contract, "More than one contract not supported."); m_seenContract = true; m_currentContract.contract = &_contract; if (_contract.isLibrary()) error(_contract, "Libraries not supported."); addLine("module Contract_" + _contract.name()); indent(); addLine("use import int.Int"); addLine("use import ref.Ref"); addLine("use import map.Map"); addLine("use import array.Array"); addLine("use import int.ComputerDivision"); addLine("use import mach.int.Unsigned"); addLine("use import UInt256"); addLine("exception Revert"); addLine("exception Return"); if (_contract.stateVariables().empty()) addLine("type state = ()"); else { addLine("type state = {"); indent(); m_currentContract.stateVariables = _contract.stateVariables(); for (VariableDeclaration const* variable: m_currentContract.stateVariables) { string varType; try { varType = toFormalType(*variable->annotation().type); } catch (NoFormalType &err) { string const* typeNamePtr = boost::get_error_info<errinfo_noFormalTypeFrom>(err); string typeName = typeNamePtr ? " \"" + *typeNamePtr + "\"" : ""; fatalError(*variable, "Type" + typeName + " not supported for state variable."); } addLine("mutable _" + variable->name() + ": " + varType); } unindent(); addLine("}"); } addLine("type account = {"); indent(); addLine("mutable balance: uint256;"); addLine("storage: state"); unindent(); addLine("}"); addLine("val external_call (this: account): bool"); indent(); addLine("ensures { result = false -> this = (old this) }"); addLine("writes { this }"); addSourceFromDocStrings(m_currentContract.contract->annotation()); unindent(); if (!_contract.baseContracts().empty()) error(*_contract.baseContracts().front(), "Inheritance not supported."); if (!_contract.definedStructs().empty()) error(*_contract.definedStructs().front(), "User-defined types not supported."); if (!_contract.definedEnums().empty()) error(*_contract.definedEnums().front(), "User-defined types not supported."); if (!_contract.events().empty()) error(*_contract.events().front(), "Events not supported."); if (!_contract.functionModifiers().empty()) error(*_contract.functionModifiers().front(), "Modifiers not supported."); ASTNode::listAccept(_contract.definedFunctions(), *this); return false; }
void Compiler::initializeStateVariables(ContractDefinition const& _contract) { for (ASTPointer<VariableDeclaration> const& variable: _contract.getStateVariables()) if (variable->getValue() && !variable->isConstant()) ExpressionCompiler(m_context, m_optimize).appendStateVariableInitialization(*variable); }