diff options
author | debris <marek.kotewicz@gmail.com> | 2015-02-11 23:24:37 +0800 |
---|---|---|
committer | debris <marek.kotewicz@gmail.com> | 2015-02-11 23:24:37 +0800 |
commit | 05624c15b16ed2693cc9fb4c88fe5a40f813877e (patch) | |
tree | b8966e610ba83368a0137164098b3f76602cf2b8 | |
parent | d5499d1caf52af93468237b64bfe75d568939aa1 (diff) | |
parent | 11b4e7f7d8cf45be2717bb249cf966788f486ede (diff) | |
download | dexon-solidity-05624c15b16ed2693cc9fb4c88fe5a40f813877e.tar dexon-solidity-05624c15b16ed2693cc9fb4c88fe5a40f813877e.tar.gz dexon-solidity-05624c15b16ed2693cc9fb4c88fe5a40f813877e.tar.bz2 dexon-solidity-05624c15b16ed2693cc9fb4c88fe5a40f813877e.tar.lz dexon-solidity-05624c15b16ed2693cc9fb4c88fe5a40f813877e.tar.xz dexon-solidity-05624c15b16ed2693cc9fb4c88fe5a40f813877e.tar.zst dexon-solidity-05624c15b16ed2693cc9fb4c88fe5a40f813877e.zip |
Merge branch 'develop' into jsoncpp_path
-rw-r--r-- | AST.cpp | 37 | ||||
-rw-r--r-- | AST.h | 24 | ||||
-rw-r--r-- | ASTJsonConverter.cpp | 2 | ||||
-rw-r--r-- | Compiler.cpp | 4 | ||||
-rw-r--r-- | CompilerStack.cpp | 12 | ||||
-rw-r--r-- | CompilerStack.h | 8 | ||||
-rw-r--r-- | ExpressionCompiler.cpp | 225 | ||||
-rw-r--r-- | ExpressionCompiler.h | 19 | ||||
-rw-r--r-- | GlobalContext.cpp | 26 | ||||
-rw-r--r-- | InterfaceHandler.cpp | 72 | ||||
-rw-r--r-- | InterfaceHandler.h | 18 | ||||
-rw-r--r-- | Parser.cpp | 236 | ||||
-rw-r--r-- | Scanner.cpp | 134 | ||||
-rw-r--r-- | Token.cpp | 3 | ||||
-rw-r--r-- | Token.h | 474 | ||||
-rw-r--r-- | Types.cpp | 163 | ||||
-rw-r--r-- | Types.h | 70 |
17 files changed, 785 insertions, 742 deletions
@@ -247,7 +247,7 @@ void StructDefinition::checkRecursion() const << errinfo_comment("Recursive struct definition.")); definitionsSeen.insert(def); for (ASTPointer<VariableDeclaration> const& member: def->getMembers()) - if (member->getType()->getCategory() == Type::Category::STRUCT) + if (member->getType()->getCategory() == Type::Category::Struct) { UserDefinedTypeName const& typeName = dynamic_cast<UserDefinedTypeName const&>(*member->getTypeName()); queue.push_back(&dynamic_cast<StructDefinition const&>(*typeName.getReferencedDeclaration())); @@ -279,9 +279,9 @@ string FunctionDefinition::getCanonicalSignature() const Declaration::LValueType VariableDeclaration::getLValueType() const { if (dynamic_cast<FunctionDefinition const*>(getScope()) || dynamic_cast<ModifierDefinition const*>(getScope())) - return Declaration::LValueType::LOCAL; + return Declaration::LValueType::Local; else - return Declaration::LValueType::STORAGE; + return Declaration::LValueType::Storage; } TypePointer ModifierDefinition::getType(ContractDefinition const*) const @@ -384,14 +384,14 @@ void VariableDefinition::checkTypeRequirements() // no type declared and no previous assignment, infer the type m_value->checkTypeRequirements(); TypePointer type = m_value->getType(); - if (type->getCategory() == Type::Category::INTEGER_CONSTANT) + if (type->getCategory() == Type::Category::IntegerConstant) { auto intType = dynamic_pointer_cast<IntegerConstantType const>(type)->getIntegerType(); if (!intType) BOOST_THROW_EXCEPTION(m_value->createTypeError("Invalid integer constant " + type->toString())); type = intType; } - else if (type->getCategory() == Type::Category::VOID) + else if (type->getCategory() == Type::Category::Void) BOOST_THROW_EXCEPTION(m_variable->createTypeError("var cannot be void type")); m_variable->setType(type); } @@ -406,7 +406,7 @@ void Assignment::checkTypeRequirements() if (!m_leftHandSide->getType()->isValueType() && !m_leftHandSide->isLocalLValue()) BOOST_THROW_EXCEPTION(createTypeError("Assignment to non-local non-value lvalue.")); m_type = m_leftHandSide->getType(); - if (m_assigmentOperator == Token::ASSIGN) + if (m_assigmentOperator == Token::Assign) m_rightHandSide->expectType(*m_type); else { @@ -425,7 +425,7 @@ void Assignment::checkTypeRequirements() void ExpressionStatement::checkTypeRequirements() { m_expression->checkTypeRequirements(); - if (m_expression->getType()->getCategory() == Type::Category::INTEGER_CONSTANT) + if (m_expression->getType()->getCategory() == Type::Category::IntegerConstant) if (!dynamic_pointer_cast<IntegerConstantType const>(m_expression->getType())->getIntegerType()) BOOST_THROW_EXCEPTION(m_expression->createTypeError("Invalid integer constant.")); } @@ -449,9 +449,9 @@ void Expression::requireLValue() void UnaryOperation::checkTypeRequirements() { - // INC, DEC, ADD, SUB, NOT, BIT_NOT, DELETE + // Inc, Dec, Add, Sub, Not, BitNot, Delete m_subExpression->checkTypeRequirements(); - if (m_operator == Token::Value::INC || m_operator == Token::Value::DEC || m_operator == Token::Value::DELETE) + if (m_operator == Token::Value::Inc || m_operator == Token::Value::Dec || m_operator == Token::Value::Delete) m_subExpression->requireLValue(); m_type = m_subExpression->getType()->unaryOperatorResult(m_operator); if (!m_type) @@ -497,20 +497,21 @@ void FunctionCall::checkTypeRequirements() // and then ask if that is implicitly convertible to the struct represented by the // function parameters TypePointers const& parameterTypes = functionType->getParameterTypes(); - if (functionType->getLocation() != FunctionType::Location::SHA3 && parameterTypes.size() != m_arguments.size()) + if (!functionType->takesArbitraryParameters() && parameterTypes.size() != m_arguments.size()) BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call.")); if (m_names.empty()) { for (size_t i = 0; i < m_arguments.size(); ++i) - if (functionType->getLocation() != FunctionType::Location::SHA3 && + if (!functionType->takesArbitraryParameters() && !m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i])) BOOST_THROW_EXCEPTION(m_arguments[i]->createTypeError("Invalid type for argument in function call.")); } else { - if (functionType->getLocation() == FunctionType::Location::SHA3) - BOOST_THROW_EXCEPTION(createTypeError("Named arguments cannnot be used for SHA3.")); + if (functionType->takesArbitraryParameters()) + BOOST_THROW_EXCEPTION(createTypeError("Named arguments cannnot be used for functions " + "that take arbitrary parameters.")); auto const& parameterNames = functionType->getParameterNames(); if (parameterNames.size() != m_names.size()) BOOST_THROW_EXCEPTION(createTypeError("Some argument names are missing.")); @@ -551,7 +552,7 @@ void FunctionCall::checkTypeRequirements() bool FunctionCall::isTypeConversion() const { - return m_expression->getType()->getCategory() == Type::Category::TYPE; + return m_expression->getType()->getCategory() == Type::Category::TypeType; } void NewExpression::checkTypeRequirements() @@ -563,7 +564,7 @@ void NewExpression::checkTypeRequirements() shared_ptr<ContractType const> contractType = make_shared<ContractType>(*m_contract); TypePointers const& parameterTypes = contractType->getConstructorType()->getParameterTypes(); m_type = make_shared<FunctionType>(parameterTypes, TypePointers{contractType}, - FunctionType::Location::CREATION); + FunctionType::Location::Creation); } void MemberAccess::checkTypeRequirements() @@ -575,19 +576,19 @@ void MemberAccess::checkTypeRequirements() BOOST_THROW_EXCEPTION(createTypeError("Member \"" + *m_memberName + "\" not found or not " "visible in " + type.toString())); //@todo later, this will not always be STORAGE - m_lvalue = type.getCategory() == Type::Category::STRUCT ? Declaration::LValueType::STORAGE : Declaration::LValueType::NONE; + m_lvalue = type.getCategory() == Type::Category::Struct ? Declaration::LValueType::Storage : Declaration::LValueType::None; } void IndexAccess::checkTypeRequirements() { m_base->checkTypeRequirements(); - if (m_base->getType()->getCategory() != Type::Category::MAPPING) + if (m_base->getType()->getCategory() != Type::Category::Mapping) BOOST_THROW_EXCEPTION(m_base->createTypeError("Indexed expression has to be a mapping (is " + m_base->getType()->toString() + ")")); MappingType const& type = dynamic_cast<MappingType const&>(*m_base->getType()); m_index->expectType(*type.getKeyType()); m_type = type.getValueType(); - m_lvalue = Declaration::LValueType::STORAGE; + m_lvalue = Declaration::LValueType::Storage; } void Identifier::checkTypeRequirements() @@ -132,17 +132,17 @@ private: class Declaration: public ASTNode { public: - enum class LValueType { NONE, LOCAL, STORAGE }; - enum class Visibility { DEFAULT, PUBLIC, PROTECTED, PRIVATE }; + enum class LValueType { None, Local, Storage }; + enum class Visibility { Default, Public, Protected, Private }; Declaration(Location const& _location, ASTPointer<ASTString> const& _name, - Visibility _visibility = Visibility::DEFAULT): + Visibility _visibility = Visibility::Default): ASTNode(_location), m_name(_name), m_visibility(_visibility), m_scope(nullptr) {} /// @returns the declared name. ASTString const& getName() const { return *m_name; } - Visibility getVisibility() const { return m_visibility == Visibility::DEFAULT ? getDefaultVisibility() : m_visibility; } - bool isPublic() const { return getVisibility() == Visibility::PUBLIC; } + Visibility getVisibility() const { return m_visibility == Visibility::Default ? getDefaultVisibility() : m_visibility; } + bool isPublic() const { return getVisibility() == Visibility::Public; } /// @returns the scope this declaration resides in. Can be nullptr if it is the global scope. /// Available only after name and type resolution step. @@ -154,10 +154,10 @@ public: /// contract types. virtual TypePointer getType(ContractDefinition const* m_currentContract = nullptr) const = 0; /// @returns the lvalue type of expressions referencing this declaration - virtual LValueType getLValueType() const { return LValueType::NONE; } + virtual LValueType getLValueType() const { return LValueType::None; } protected: - virtual Visibility getDefaultVisibility() const { return Visibility::PUBLIC; } + virtual Visibility getDefaultVisibility() const { return Visibility::Public; } private: ASTPointer<ASTString> m_name; @@ -414,7 +414,7 @@ public: bool isIndexed() const { return m_isIndexed; } protected: - Visibility getDefaultVisibility() const override { return Visibility::PROTECTED; } + Visibility getDefaultVisibility() const override { return Visibility::Protected; } private: ASTPointer<TypeName> m_typeName; ///< can be empty ("var") @@ -847,8 +847,8 @@ public: virtual void checkTypeRequirements() = 0; std::shared_ptr<Type const> const& getType() const { return m_type; } - bool isLValue() const { return m_lvalue != Declaration::LValueType::NONE; } - bool isLocalLValue() const { return m_lvalue == Declaration::LValueType::LOCAL; } + bool isLValue() const { return m_lvalue != Declaration::LValueType::None; } + bool isLocalLValue() const { return m_lvalue == Declaration::LValueType::Local; } /// Helper function, infer the type via @ref checkTypeRequirements and then check that it /// is implicitly convertible to @a _expectedType. If not, throw exception. @@ -865,7 +865,7 @@ protected: std::shared_ptr<Type const> m_type; //! If this expression is an lvalue (i.e. something that can be assigned to) and is stored //! locally or in storage. This is set during calls to @a checkTypeRequirements() - Declaration::LValueType m_lvalue = Declaration::LValueType::NONE; + Declaration::LValueType m_lvalue = Declaration::LValueType::None; //! Whether the outer expression requested the address (true) or the value (false) of this expression. bool m_lvalueRequested = false; }; @@ -1119,7 +1119,7 @@ class Literal: public PrimaryExpression public: enum class SubDenomination { - None = Token::ILLEGAL, + None = Token::Illegal, Wei = Token::SubWei, Szabo = Token::SubSzabo, Finney = Token::SubFinney, diff --git a/ASTJsonConverter.cpp b/ASTJsonConverter.cpp index d9332990..a216a59a 100644 --- a/ASTJsonConverter.cpp +++ b/ASTJsonConverter.cpp @@ -118,7 +118,7 @@ bool ASTJsonConverter::visit(FunctionDefinition const& _node) bool ASTJsonConverter::visit(VariableDeclaration const& _node) { - bool isLocalVariable = (_node.getLValueType() == VariableDeclaration::LValueType::LOCAL); + bool isLocalVariable = (_node.getLValueType() == VariableDeclaration::LValueType::Local); addJsonNode("VariableDeclaration", { make_pair("name", _node.getName()), make_pair("local", boost::lexical_cast<std::string>(isLocalVariable))}, diff --git a/Compiler.cpp b/Compiler.cpp index 389f826b..b3615367 100644 --- a/Compiler.cpp +++ b/Compiler.cpp @@ -189,7 +189,7 @@ unsigned Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, b if (c_numBytes > 32) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Type " + type->toString() + " not yet supported.")); - bool const c_leftAligned = type->getCategory() == Type::Category::STRING; + bool const c_leftAligned = type->getCategory() == Type::Category::String; bool const c_padToWords = true; dataOffset += CompilerUtils(m_context).loadFromMemory(dataOffset, c_numBytes, c_leftAligned, !_fromMemory, c_padToWords); @@ -213,7 +213,7 @@ void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters) << errinfo_comment("Type " + type->toString() + " not yet supported.")); CompilerUtils(m_context).copyToStackTop(stackDepth, *type); ExpressionCompiler::appendTypeConversion(m_context, *type, *type, true); - bool const c_leftAligned = type->getCategory() == Type::Category::STRING; + bool const c_leftAligned = type->getCategory() == Type::Category::String; bool const c_padToWords = true; dataOffset += CompilerUtils(m_context).storeInMemory(dataOffset, numBytes, c_leftAligned, c_padToWords); stackDepth -= type->getSizeOnStack(); diff --git a/CompilerStack.cpp b/CompilerStack.cpp index 2d77bc0a..762edb52 100644 --- a/CompilerStack.cpp +++ b/CompilerStack.cpp @@ -227,12 +227,12 @@ void CompilerStack::streamAssembly(ostream& _outStream, string const& _contractN string const& CompilerStack::getInterface(string const& _contractName) const { - return getMetadata(_contractName, DocumentationType::ABI_INTERFACE); + return getMetadata(_contractName, DocumentationType::ABIInterface); } string const& CompilerStack::getSolidityInterface(string const& _contractName) const { - return getMetadata(_contractName, DocumentationType::ABI_SOLIDITY_INTERFACE); + return getMetadata(_contractName, DocumentationType::ABISolidityInterface); } string const& CompilerStack::getMetadata(string const& _contractName, DocumentationType _type) const @@ -245,16 +245,16 @@ string const& CompilerStack::getMetadata(string const& _contractName, Documentat std::unique_ptr<string const>* doc; switch (_type) { - case DocumentationType::NATSPEC_USER: + case DocumentationType::NatspecUser: doc = &contract.userDocumentation; break; - case DocumentationType::NATSPEC_DEV: + case DocumentationType::NatspecDev: doc = &contract.devDocumentation; break; - case DocumentationType::ABI_INTERFACE: + case DocumentationType::ABIInterface: doc = &contract.interface; break; - case DocumentationType::ABI_SOLIDITY_INTERFACE: + case DocumentationType::ABISolidityInterface: doc = &contract.solidityInterface; break; default: diff --git a/CompilerStack.h b/CompilerStack.h index a6c3df8e..439077f3 100644 --- a/CompilerStack.h +++ b/CompilerStack.h @@ -43,10 +43,10 @@ class InterfaceHandler; enum class DocumentationType: uint8_t { - NATSPEC_USER = 1, - NATSPEC_DEV, - ABI_INTERFACE, - ABI_SOLIDITY_INTERFACE + NatspecUser = 1, + NatspecDev, + ABIInterface, + ABISolidityInterface }; extern const std::map<std::string, std::string> StandardSources; diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index 5561af9b..beda0132 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -64,7 +64,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) solAssert(m_currentLValue.isValid(), "LValue not retrieved."); Token::Value op = _assignment.getAssignmentOperator(); - if (op != Token::ASSIGN) // compound assignment + if (op != Token::Assign) // compound assignment { if (m_currentLValue.storesReferenceOnStack()) m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2; @@ -85,7 +85,7 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation) // the operator should know how to convert itself and to which types it applies, so // put this code together with "Type::acceptsBinary/UnaryOperator" into a class that // represents the operator - if (_unaryOperation.getType()->getCategory() == Type::Category::INTEGER_CONSTANT) + if (_unaryOperation.getType()->getCategory() == Type::Category::IntegerConstant) { m_context << _unaryOperation.getType()->literalValue(nullptr); return false; @@ -95,19 +95,19 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation) switch (_unaryOperation.getOperator()) { - case Token::NOT: // ! + case Token::Not: // ! m_context << eth::Instruction::ISZERO; break; - case Token::BIT_NOT: // ~ + case Token::BitNot: // ~ m_context << eth::Instruction::NOT; break; - case Token::DELETE: // delete + case Token::Delete: // delete solAssert(m_currentLValue.isValid(), "LValue not retrieved."); m_currentLValue.setToZero(_unaryOperation); m_currentLValue.reset(); break; - case Token::INC: // ++ (pre- or postfix) - case Token::DEC: // -- (pre- or postfix) + case Token::Inc: // ++ (pre- or postfix) + case Token::Dec: // -- (pre- or postfix) solAssert(m_currentLValue.isValid(), "LValue not retrieved."); m_currentLValue.retrieveValue(_unaryOperation.getType(), _unaryOperation.getLocation()); if (!_unaryOperation.isPrefixOperation()) @@ -118,7 +118,7 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation) m_context << eth::Instruction::DUP1; } m_context << u256(1); - if (_unaryOperation.getOperator() == Token::INC) + if (_unaryOperation.getOperator() == Token::Inc) m_context << eth::Instruction::ADD; else m_context << eth::Instruction::SWAP1 << eth::Instruction::SUB; // @todo avoid the swap @@ -129,10 +129,10 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation) m_currentLValue.storeValue(_unaryOperation, !_unaryOperation.isPrefixOperation()); m_currentLValue.reset(); break; - case Token::ADD: // + + case Token::Add: // + // unary add, so basically no-op break; - case Token::SUB: // - + case Token::Sub: // - m_context << u256(0) << eth::Instruction::SUB; break; default: @@ -149,19 +149,19 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation) Type const& commonType = _binaryOperation.getCommonType(); Token::Value const c_op = _binaryOperation.getOperator(); - if (c_op == Token::AND || c_op == Token::OR) // special case: short-circuiting + if (c_op == Token::And || c_op == Token::Or) // special case: short-circuiting appendAndOrOperatorCode(_binaryOperation); - else if (commonType.getCategory() == Type::Category::INTEGER_CONSTANT) + else if (commonType.getCategory() == Type::Category::IntegerConstant) m_context << commonType.literalValue(nullptr); else { - bool cleanupNeeded = commonType.getCategory() == Type::Category::INTEGER && - (Token::isCompareOp(c_op) || c_op == Token::DIV || c_op == Token::MOD); + bool cleanupNeeded = commonType.getCategory() == Type::Category::Integer && + (Token::isCompareOp(c_op) || c_op == Token::Div || c_op == Token::Mod); // for commutative operators, push the literal as late as possible to allow improved optimization auto isLiteral = [](Expression const& _e) { - return dynamic_cast<Literal const*>(&_e) || _e.getType()->getCategory() == Type::Category::INTEGER_CONSTANT; + return dynamic_cast<Literal const*>(&_e) || _e.getType()->getCategory() == Type::Category::IntegerConstant; }; bool swap = m_optimize && Token::isCommutativeOp(c_op) && isLiteral(rightExpression) && !isLiteral(leftExpression); if (swap) @@ -206,7 +206,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) TypePointers const& parameterTypes = function.getParameterTypes(); vector<ASTPointer<Expression const>> const& callArguments = _functionCall.getArguments(); vector<ASTPointer<ASTString>> const& callArgumentNames = _functionCall.getNames(); - if (function.getLocation() != Location::SHA3) + if (!function.takesArbitraryParameters()) solAssert(callArguments.size() == parameterTypes.size(), ""); vector<ASTPointer<Expression const>> arguments; @@ -227,7 +227,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) switch (function.getLocation()) { - case Location::INTERNAL: + case Location::Internal: { // Calling convention: Caller pushes return address and arguments // Callee removes them and pushes return values @@ -253,12 +253,12 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) CompilerUtils(m_context).popStackElement(*function.getReturnParameterTypes()[i]); break; } - case Location::EXTERNAL: - case Location::BARE: + case Location::External: + case Location::Bare: _functionCall.getExpression().accept(*this); - appendExternalFunctionCall(function, arguments, function.getLocation() == Location::BARE); + appendExternalFunctionCall(function, arguments, function.getLocation() == Location::Bare); break; - case Location::CREATION: + case Location::Creation: { _functionCall.getExpression().accept(*this); solAssert(!function.gasSet(), "Gas limit set for contract creation."); @@ -287,7 +287,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) m_context << eth::swapInstruction(1) << eth::Instruction::POP; break; } - case Location::SET_GAS: + case Location::SetGas: { // stack layout: contract_address function_id [gas] [value] _functionCall.getExpression().accept(*this); @@ -302,7 +302,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) m_context << eth::Instruction::POP; break; } - case Location::SET_VALUE: + case Location::SetValue: // stack layout: contract_address function_id [gas] [value] _functionCall.getExpression().accept(*this); // Note that function is not the original function, but the ".value" function. @@ -311,33 +311,33 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) m_context << eth::Instruction::POP; arguments.front()->accept(*this); break; - case Location::SEND: + case Location::Send: _functionCall.getExpression().accept(*this); m_context << u256(0); // 0 gas, we do not want to execute code arguments.front()->accept(*this); appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front(), true); appendExternalFunctionCall(FunctionType(TypePointers{}, TypePointers{}, - Location::EXTERNAL, true, true), {}, true); + Location::External, false, true, true), {}, true); break; - case Location::SUICIDE: + case Location::Suicide: arguments.front()->accept(*this); appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front(), true); m_context << eth::Instruction::SUICIDE; break; case Location::SHA3: { - unsigned length = appendArgumentsCopyToMemory(arguments, TypePointers(), 0, false); + unsigned length = appendArgumentsCopyToMemory(arguments, TypePointers(), 0, function.padArguments()); m_context << u256(length) << u256(0) << eth::Instruction::SHA3; break; } - case Location::LOG0: - case Location::LOG1: - case Location::LOG2: - case Location::LOG3: - case Location::LOG4: + case Location::Log0: + case Location::Log1: + case Location::Log2: + case Location::Log3: + case Location::Log4: { - unsigned logNumber = int(function.getLocation()) - int(Location::LOG0); + unsigned logNumber = int(function.getLocation()) - int(Location::Log0); for (unsigned arg = logNumber; arg > 0; --arg) { arguments[arg]->accept(*this); @@ -349,7 +349,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) m_context << u256(length) << u256(0) << eth::logInstruction(logNumber); break; } - case Location::EVENT: + case Location::Event: { _functionCall.getExpression().accept(*this); auto const& event = dynamic_cast<EventDefinition const&>(function.getDeclaration()); @@ -375,18 +375,18 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) m_context << u256(memLength) << u256(0) << eth::logInstruction(numIndexed); break; } - case Location::BLOCKHASH: + case Location::BlockHash: { arguments[0]->accept(*this); appendTypeConversion(*arguments[0]->getType(), *function.getParameterTypes()[0], true); m_context << eth::Instruction::BLOCKHASH; break; } - case Location::ECRECOVER: + case Location::ECRecover: case Location::SHA256: case Location::RIPEMD160: { - static const map<Location, u256> contractAddresses{{Location::ECRECOVER, 1}, + static const map<Location, u256> contractAddresses{{Location::ECRecover, 1}, {Location::SHA256, 2}, {Location::RIPEMD160, 3}}; m_context << contractAddresses.find(function.getLocation())->second; @@ -411,7 +411,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) ASTString const& member = _memberAccess.getMemberName(); switch (_memberAccess.getExpression().getType()->getCategory()) { - case Type::Category::CONTRACT: + case Type::Category::Contract: { bool alsoSearchInteger = false; ContractType const& type = dynamic_cast<ContractType const&>(*_memberAccess.getExpression().getType()); @@ -423,7 +423,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) u256 identifier = type.getFunctionIdentifier(member); if (identifier != Invalid256) { - appendTypeConversion(type, IntegerType(0, IntegerType::Modifier::ADDRESS), true); + appendTypeConversion(type, IntegerType(0, IntegerType::Modifier::Address), true); m_context << identifier; } else @@ -433,24 +433,24 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) if (!alsoSearchInteger) break; } - case Type::Category::INTEGER: + case Type::Category::Integer: if (member == "balance") { appendTypeConversion(*_memberAccess.getExpression().getType(), - IntegerType(0, IntegerType::Modifier::ADDRESS), true); + IntegerType(0, IntegerType::Modifier::Address), true); m_context << eth::Instruction::BALANCE; } else if (member == "send" || member.substr(0, min<size_t>(member.size(), 4)) == "call") appendTypeConversion(*_memberAccess.getExpression().getType(), - IntegerType(0, IntegerType::Modifier::ADDRESS), true); + IntegerType(0, IntegerType::Modifier::Address), true); else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to integer.")); break; - case Type::Category::FUNCTION: + case Type::Category::Function: solAssert(!!_memberAccess.getExpression().getType()->getMemberType(member), "Invalid member access to function."); break; - case Type::Category::MAGIC: + case Type::Category::Magic: // we can ignore the kind of magic and only look at the name of the member if (member == "coinbase") m_context << eth::Instruction::COINBASE; @@ -475,15 +475,15 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown magic member.")); break; - case Type::Category::STRUCT: + case Type::Category::Struct: { StructType const& type = dynamic_cast<StructType const&>(*_memberAccess.getExpression().getType()); m_context << type.getStorageOffsetOfMember(member) << eth::Instruction::ADD; - m_currentLValue = LValue(m_context, LValue::STORAGE, *_memberAccess.getType()); + m_currentLValue = LValue(m_context, LValue::LValueType::Storage, *_memberAccess.getType()); m_currentLValue.retrieveValueIfLValueNotRequested(_memberAccess); break; } - case Type::Category::TYPE: + case Type::Category::TypeType: { TypeType const& type = dynamic_cast<TypeType const&>(*_memberAccess.getExpression().getType()); if (type.getMembers().getMemberType(member)) @@ -515,7 +515,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) length += CompilerUtils(m_context).storeInMemory(length); m_context << u256(length) << u256(0) << eth::Instruction::SHA3; - m_currentLValue = LValue(m_context, LValue::STORAGE, *_indexAccess.getType()); + m_currentLValue = LValue(m_context, LValue::LValueType::Storage, *_indexAccess.getType()); m_currentLValue.retrieveValueIfLValueNotRequested(_indexAccess); return false; @@ -526,7 +526,7 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier) Declaration const* declaration = _identifier.getReferencedDeclaration(); if (MagicVariableDeclaration const* magicVar = dynamic_cast<MagicVariableDeclaration const*>(declaration)) { - if (magicVar->getType()->getCategory() == Type::Category::CONTRACT) + if (magicVar->getType()->getCategory() == Type::Category::Contract) // "this" or "super" if (!dynamic_cast<ContractType const&>(*magicVar->getType()).isSuper()) m_context << eth::Instruction::ADDRESS; @@ -556,9 +556,9 @@ void ExpressionCompiler::endVisit(Literal const& _literal) { switch (_literal.getType()->getCategory()) { - case Type::Category::INTEGER_CONSTANT: - case Type::Category::BOOL: - case Type::Category::STRING: + case Type::Category::IntegerConstant: + case Type::Category::Bool: + case Type::Category::String: m_context << _literal.getType()->literalValue(&_literal); break; default: @@ -569,11 +569,11 @@ void ExpressionCompiler::endVisit(Literal const& _literal) void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation const& _binaryOperation) { Token::Value const c_op = _binaryOperation.getOperator(); - solAssert(c_op == Token::OR || c_op == Token::AND, ""); + solAssert(c_op == Token::Or || c_op == Token::And, ""); _binaryOperation.getLeftExpression().accept(*this); m_context << eth::Instruction::DUP1; - if (c_op == Token::AND) + if (c_op == Token::And) m_context << eth::Instruction::ISZERO; eth::AssemblyItem endLabel = m_context.appendConditionalJump(); m_context << eth::Instruction::POP; @@ -583,10 +583,10 @@ void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation const& _binaryO void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type const& _type) { - if (_operator == Token::EQ || _operator == Token::NE) + if (_operator == Token::Equal || _operator == Token::NotEqual) { m_context << eth::Instruction::EQ; - if (_operator == Token::NE) + if (_operator == Token::NotEqual) m_context << eth::Instruction::ISZERO; } else @@ -596,18 +596,18 @@ void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type switch (_operator) { - case Token::GTE: + case Token::GreaterThanOrEqual: m_context << (c_isSigned ? eth::Instruction::SLT : eth::Instruction::LT) << eth::Instruction::ISZERO; break; - case Token::LTE: + case Token::LessThanOrEqual: m_context << (c_isSigned ? eth::Instruction::SGT : eth::Instruction::GT) << eth::Instruction::ISZERO; break; - case Token::GT: + case Token::GreaterThan: m_context << (c_isSigned ? eth::Instruction::SGT : eth::Instruction::GT); break; - case Token::LT: + case Token::LessThan: m_context << (c_isSigned ? eth::Instruction::SLT : eth::Instruction::LT); break; default: @@ -635,21 +635,24 @@ void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Ty switch (_operator) { - case Token::ADD: + case Token::Add: m_context << eth::Instruction::ADD; break; - case Token::SUB: + case Token::Sub: m_context << eth::Instruction::SUB; break; - case Token::MUL: + case Token::Mul: m_context << eth::Instruction::MUL; break; - case Token::DIV: + case Token::Div: m_context << (c_isSigned ? eth::Instruction::SDIV : eth::Instruction::DIV); break; - case Token::MOD: + case Token::Mod: m_context << (c_isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD); break; + case Token::Exp: + m_context << eth::Instruction::EXP; + break; default: BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown arithmetic operator.")); } @@ -659,13 +662,13 @@ void ExpressionCompiler::appendBitOperatorCode(Token::Value _operator) { switch (_operator) { - case Token::BIT_OR: + case Token::BitOr: m_context << eth::Instruction::OR; break; - case Token::BIT_AND: + case Token::BitAnd: m_context << eth::Instruction::AND; break; - case Token::BIT_XOR: + case Token::BitXor: m_context << eth::Instruction::XOR; break; default: @@ -698,29 +701,38 @@ void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type con Type::Category stackTypeCategory = _typeOnStack.getCategory(); Type::Category targetTypeCategory = _targetType.getCategory(); - if (stackTypeCategory == Type::Category::STRING) + if (stackTypeCategory == Type::Category::String) { - if (targetTypeCategory == Type::Category::INTEGER) + StaticStringType const& typeOnStack = dynamic_cast<StaticStringType const&>(_typeOnStack); + if (targetTypeCategory == Type::Category::Integer) { // conversion from string to hash. no need to clean the high bit // only to shift right because of opposite alignment IntegerType const& targetIntegerType = dynamic_cast<IntegerType const&>(_targetType); - StaticStringType const& typeOnStack = dynamic_cast<StaticStringType const&>(_typeOnStack); solAssert(targetIntegerType.isHash(), "Only conversion between String and Hash is allowed."); solAssert(targetIntegerType.getNumBits() == typeOnStack.getNumBytes() * 8, "The size should be the same."); m_context << (u256(1) << (256 - typeOnStack.getNumBytes() * 8)) << eth::Instruction::SWAP1 << eth::Instruction::DIV; } else { - solAssert(targetTypeCategory == Type::Category::STRING, "Invalid type conversion requested."); - // nothing to do, strings are high-order-bit-aligned - //@todo clear lower-order bytes if we allow explicit conversion to shorter strings + // clear lower-order bytes for conversion to shorter strings - we always clean + solAssert(targetTypeCategory == Type::Category::String, "Invalid type conversion requested."); + StaticStringType const& targetType = dynamic_cast<StaticStringType const&>(_targetType); + if (targetType.getNumBytes() < typeOnStack.getNumBytes()) + { + if (targetType.getNumBytes() == 0) + m_context << eth::Instruction::DUP1 << eth::Instruction::XOR; + else + m_context << (u256(1) << (256 - targetType.getNumBytes() * 8)) + << eth::Instruction::DUP1 << eth::Instruction::SWAP2 + << eth::Instruction::DIV << eth::Instruction::MUL; + } } } - else if (stackTypeCategory == Type::Category::INTEGER || stackTypeCategory == Type::Category::CONTRACT || - stackTypeCategory == Type::Category::INTEGER_CONSTANT) + else if (stackTypeCategory == Type::Category::Integer || stackTypeCategory == Type::Category::Contract || + stackTypeCategory == Type::Category::IntegerConstant) { - if (targetTypeCategory == Type::Category::STRING && stackTypeCategory == Type::Category::INTEGER) + if (targetTypeCategory == Type::Category::String && stackTypeCategory == Type::Category::Integer) { // conversion from hash to string. no need to clean the high bit // only to shift left because of opposite alignment @@ -732,11 +744,11 @@ void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type con } else { - solAssert(targetTypeCategory == Type::Category::INTEGER || targetTypeCategory == Type::Category::CONTRACT, ""); - IntegerType addressType(0, IntegerType::Modifier::ADDRESS); - IntegerType const& targetType = targetTypeCategory == Type::Category::INTEGER + solAssert(targetTypeCategory == Type::Category::Integer || targetTypeCategory == Type::Category::Contract, ""); + IntegerType addressType(0, IntegerType::Modifier::Address); + IntegerType const& targetType = targetTypeCategory == Type::Category::Integer ? dynamic_cast<IntegerType const&>(_targetType) : addressType; - if (stackTypeCategory == Type::Category::INTEGER_CONSTANT) + if (stackTypeCategory == Type::Category::IntegerConstant) { IntegerConstantType const& constType = dynamic_cast<IntegerConstantType const&>(_typeOnStack); // We know that the stack is clean, we only have to clean for a narrowing conversion @@ -746,7 +758,7 @@ void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type con } else { - IntegerType const& typeOnStack = stackTypeCategory == Type::Category::INTEGER + IntegerType const& typeOnStack = stackTypeCategory == Type::Category::Integer ? dynamic_cast<IntegerType const&>(_typeOnStack) : addressType; // Widening: clean up according to source type width // Non-widening and force: clean up according to target type bits @@ -776,7 +788,8 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio vector<ASTPointer<Expression const>> const& _arguments, bool bare) { - solAssert(_arguments.size() == _functionType.getParameterTypes().size(), ""); + solAssert(_functionType.takesArbitraryParameters() || + _arguments.size() == _functionType.getParameterTypes().size(), ""); // Assumed stack content here: // <stack top> @@ -800,7 +813,10 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio // reserve space for the function identifier unsigned dataOffset = bare ? 0 : CompilerUtils::dataStartOffset; - dataOffset += appendArgumentsCopyToMemory(_arguments, _functionType.getParameterTypes(), dataOffset); + // For bare call, activate "4 byte pad exception": If the first argument has exactly 4 bytes, + // do not pad it to 32 bytes. + dataOffset += appendArgumentsCopyToMemory(_arguments, _functionType.getParameterTypes(), dataOffset, + _functionType.padArguments(), bare); //@todo only return the first return value for now Type const* firstType = _functionType.getReturnParameterTypes().empty() ? nullptr : @@ -831,7 +847,7 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio if (retSize > 0) { - bool const c_leftAligned = firstType->getCategory() == Type::Category::STRING; + bool const c_leftAligned = firstType->getCategory() == Type::Category::String; CompilerUtils(m_context).loadFromMemory(0, retSize, c_leftAligned, false, true); } } @@ -839,7 +855,8 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio unsigned ExpressionCompiler::appendArgumentsCopyToMemory(vector<ASTPointer<Expression const>> const& _arguments, TypePointers const& _types, unsigned _memoryOffset, - bool _padToWordBoundaries) + bool _padToWordBoundaries, + bool _padExceptionIfFourBytes) { solAssert(_types.empty() || _types.size() == _arguments.size(), ""); unsigned length = 0; @@ -848,8 +865,12 @@ unsigned ExpressionCompiler::appendArgumentsCopyToMemory(vector<ASTPointer<Expre _arguments[i]->accept(*this); TypePointer const& expectedType = _types.empty() ? _arguments[i]->getType()->getRealType() : _types[i]; appendTypeConversion(*_arguments[i]->getType(), *expectedType, true); + bool pad = _padToWordBoundaries; + // Do not pad if the first argument has exactly four bytes + if (i == 0 && pad && _padExceptionIfFourBytes && expectedType->getCalldataEncodedSize() == 4) + pad = false; length += appendTypeMoveToMemory(*expectedType, _arguments[i]->getLocation(), - _memoryOffset + length, _padToWordBoundaries); + _memoryOffset + length, pad); } return length; } @@ -862,7 +883,7 @@ unsigned ExpressionCompiler::appendTypeMoveToMemory(Type const& _type, Location BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location) << errinfo_comment("Type " + _type.toString() + " not yet supported.")); - bool const c_leftAligned = _type.getCategory() == Type::Category::STRING; + bool const c_leftAligned = _type.getCategory() == Type::Category::String; return CompilerUtils(m_context).storeInMemory(_memoryOffset, c_numBytes, c_leftAligned, _padToWordBoundaries); } @@ -912,7 +933,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& m_context << eth::Instruction::DUP1 << structType->getStorageOffsetOfMember(names[i]) << eth::Instruction::ADD; - m_currentLValue = LValue(m_context, LValue::STORAGE, *types[i]); + m_currentLValue = LValue(m_context, LValue::LValueType::Storage, *types[i]); m_currentLValue.retrieveValue(types[i], Location(), true); solAssert(types[i]->getSizeOnStack() == 1, "Returning struct elements with stack size != 1 not yet implemented."); m_context << eth::Instruction::SWAP1; @@ -924,7 +945,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& { // simple value solAssert(accessorType.getReturnParameterTypes().size() == 1, ""); - m_currentLValue = LValue(m_context, LValue::STORAGE, *returnType); + m_currentLValue = LValue(m_context, LValue::LValueType::Storage, *returnType); m_currentLValue.retrieveValue(returnType, Location(), true); retSizeOnStack = returnType->getSizeOnStack(); } @@ -938,7 +959,7 @@ ExpressionCompiler::LValue::LValue(CompilerContext& _compilerContext, LValueType { //@todo change the type cast for arrays solAssert(_dataType.getStorageSize() <= numeric_limits<unsigned>::max(), "The storage size of " +_dataType.toString() + " should fit in unsigned"); - if (m_type == STORAGE) + if (m_type == LValueType::Storage) m_size = unsigned(_dataType.getStorageSize()); else m_size = unsigned(_dataType.getSizeOnStack()); @@ -948,7 +969,7 @@ void ExpressionCompiler::LValue::retrieveValue(TypePointer const& _type, Locatio { switch (m_type) { - case STACK: + case LValueType::Stack: { unsigned stackPos = m_context->baseToCurrentStackOffset(unsigned(m_baseStackOffset)); if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory @@ -958,10 +979,10 @@ void ExpressionCompiler::LValue::retrieveValue(TypePointer const& _type, Locatio *m_context << eth::dupInstruction(stackPos + 1); break; } - case STORAGE: + case LValueType::Storage: retrieveValueFromStorage(_type, _remove); break; - case MEMORY: + case LValueType::Memory: if (!_type->isValueType()) break; // no distinction between value and reference for non-value types BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_location) @@ -997,7 +1018,7 @@ void ExpressionCompiler::LValue::storeValue(Expression const& _expression, bool { switch (m_type) { - case STACK: + case LValueType::Stack: { unsigned stackDiff = m_context->baseToCurrentStackOffset(unsigned(m_baseStackOffset)) - m_size + 1; if (stackDiff > 16) @@ -1010,7 +1031,7 @@ void ExpressionCompiler::LValue::storeValue(Expression const& _expression, bool retrieveValue(_expression.getType(), _expression.getLocation()); break; } - case LValue::STORAGE: + case LValueType::Storage: if (!_expression.getType()->isValueType()) break; // no distinction between value and reference for non-value types // stack layout: value value ... value ref @@ -1035,7 +1056,7 @@ void ExpressionCompiler::LValue::storeValue(Expression const& _expression, bool << u256(1) << eth::Instruction::SWAP1 << eth::Instruction::SUB; } break; - case LValue::MEMORY: + case LValueType::Memory: if (!_expression.getType()->isValueType()) break; // no distinction between value and reference for non-value types BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_expression.getLocation()) @@ -1052,7 +1073,7 @@ void ExpressionCompiler::LValue::setToZero(Expression const& _expression) const { switch (m_type) { - case STACK: + case LValueType::Stack: { unsigned stackDiff = m_context->baseToCurrentStackOffset(unsigned(m_baseStackOffset)); if (stackDiff > 16) @@ -1064,7 +1085,7 @@ void ExpressionCompiler::LValue::setToZero(Expression const& _expression) const << eth::Instruction::POP; break; } - case LValue::STORAGE: + case LValueType::Storage: if (m_size == 0) *m_context << eth::Instruction::POP; for (unsigned i = 0; i < m_size; ++i) @@ -1076,7 +1097,7 @@ void ExpressionCompiler::LValue::setToZero(Expression const& _expression) const << u256(1) << eth::Instruction::ADD; } break; - case LValue::MEMORY: + case LValueType::Memory: if (!_expression.getType()->isValueType()) break; // no distinction between value and reference for non-value types BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_expression.getLocation()) @@ -1101,7 +1122,7 @@ void ExpressionCompiler::LValue::retrieveValueIfLValueNotRequested(Expression co void ExpressionCompiler::LValue::fromStateVariable(Declaration const& _varDecl, TypePointer const& _type) { - m_type = STORAGE; + m_type = LValueType::Storage; solAssert(_type->getStorageSize() <= numeric_limits<unsigned>::max(), "The storage size of " + _type->toString() + " should fit in an unsigned"); *m_context << m_context->getStorageLocationOfVariable(_varDecl); m_size = unsigned(_type->getStorageSize()); @@ -1111,7 +1132,7 @@ void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, D { if (m_context->isLocalVariable(&_declaration)) { - m_type = STACK; + m_type = LValueType::Stack; m_size = _identifier.getType()->getSizeOnStack(); m_baseStackOffset = m_context->getBaseStackOffsetOfVariable(_declaration); } diff --git a/ExpressionCompiler.h b/ExpressionCompiler.h index adfe8e52..3c94d74c 100644 --- a/ExpressionCompiler.h +++ b/ExpressionCompiler.h @@ -97,7 +97,8 @@ private: unsigned appendArgumentsCopyToMemory(std::vector<ASTPointer<Expression const>> const& _arguments, TypePointers const& _types = {}, unsigned _memoryOffset = 0, - bool _padToWordBoundaries = true); + bool _padToWordBoundaries = true, + bool _padExceptionIfFourBytes = false); /// Appends code that moves a stack element of the given type to memory /// @returns the number of bytes moved to memory unsigned appendTypeMoveToMemory(Type const& _type, Location const& _location, unsigned _memoryOffset, @@ -118,7 +119,7 @@ private: class LValue { public: - enum LValueType { NONE, STACK, MEMORY, STORAGE }; + enum class LValueType { None, Stack, Memory, Storage }; explicit LValue(CompilerContext& _compilerContext): m_context(&_compilerContext) { reset(); } LValue(CompilerContext& _compilerContext, LValueType _type, Type const& _dataType, unsigned _baseStackOffset = 0); @@ -128,15 +129,15 @@ private: void fromIdentifier(Identifier const& _identifier, Declaration const& _declaration); /// Convenience function to set type for a state variable and retrieve the reference void fromStateVariable(Declaration const& _varDecl, TypePointer const& _type); - void reset() { m_type = NONE; m_baseStackOffset = 0; m_size = 0; } + void reset() { m_type = LValueType::None; m_baseStackOffset = 0; m_size = 0; } - bool isValid() const { return m_type != NONE; } - bool isInOnStack() const { return m_type == STACK; } - bool isInMemory() const { return m_type == MEMORY; } - bool isInStorage() const { return m_type == STORAGE; } + bool isValid() const { return m_type != LValueType::None; } + bool isInOnStack() const { return m_type == LValueType::Stack; } + bool isInMemory() const { return m_type == LValueType::Memory; } + bool isInStorage() const { return m_type == LValueType::Storage; } /// @returns true if this lvalue reference type occupies a slot on the stack. - bool storesReferenceOnStack() const { return m_type == STORAGE || m_type == MEMORY; } + bool storesReferenceOnStack() const { return m_type == LValueType::Storage || m_type == LValueType::Memory; } /// Copies the value of the current lvalue to the top of the stack and, if @a _remove is true, /// also removes the reference from the stack (note that is does not reset the type to @a NONE). @@ -160,7 +161,7 @@ private: void retrieveValueFromStorage(TypePointer const& _type, bool _remove = false) const; CompilerContext* m_context; - LValueType m_type = NONE; + LValueType m_type = LValueType::None; /// If m_type is STACK, this is base stack offset (@see /// CompilerContext::getBaseStackOffsetOfVariable) of a local variable. unsigned m_baseStackOffset = 0; diff --git a/GlobalContext.cpp b/GlobalContext.cpp index 687c9c9d..60de5105 100644 --- a/GlobalContext.cpp +++ b/GlobalContext.cpp @@ -34,29 +34,29 @@ namespace solidity { GlobalContext::GlobalContext(): -m_magicVariables(vector<shared_ptr<MagicVariableDeclaration const>>{make_shared<MagicVariableDeclaration>("block", make_shared<MagicType>(MagicType::Kind::BLOCK)), - make_shared<MagicVariableDeclaration>("msg", make_shared<MagicType>(MagicType::Kind::MSG)), - make_shared<MagicVariableDeclaration>("tx", make_shared<MagicType>(MagicType::Kind::TX)), +m_magicVariables(vector<shared_ptr<MagicVariableDeclaration const>>{make_shared<MagicVariableDeclaration>("block", make_shared<MagicType>(MagicType::Kind::Block)), + make_shared<MagicVariableDeclaration>("msg", make_shared<MagicType>(MagicType::Kind::Message)), + make_shared<MagicVariableDeclaration>("tx", make_shared<MagicType>(MagicType::Kind::Transaction)), make_shared<MagicVariableDeclaration>("suicide", - make_shared<FunctionType>(strings{"address"}, strings{}, FunctionType::Location::SUICIDE)), + make_shared<FunctionType>(strings{"address"}, strings{}, FunctionType::Location::Suicide)), make_shared<MagicVariableDeclaration>("sha3", - make_shared<FunctionType>(strings{"hash"}, strings{"hash"}, FunctionType::Location::SHA3)), + make_shared<FunctionType>(strings(), strings{"hash"}, FunctionType::Location::SHA3, true)), make_shared<MagicVariableDeclaration>("log0", - make_shared<FunctionType>(strings{"hash"},strings{}, FunctionType::Location::LOG0)), + make_shared<FunctionType>(strings{"hash"},strings{}, FunctionType::Location::Log0)), make_shared<MagicVariableDeclaration>("log1", - make_shared<FunctionType>(strings{"hash", "hash"},strings{}, FunctionType::Location::LOG1)), + make_shared<FunctionType>(strings{"hash", "hash"},strings{}, FunctionType::Location::Log1)), make_shared<MagicVariableDeclaration>("log2", - make_shared<FunctionType>(strings{"hash", "hash", "hash"},strings{}, FunctionType::Location::LOG2)), + make_shared<FunctionType>(strings{"hash", "hash", "hash"},strings{}, FunctionType::Location::Log2)), make_shared<MagicVariableDeclaration>("log3", - make_shared<FunctionType>(strings{"hash", "hash", "hash", "hash"},strings{}, FunctionType::Location::LOG3)), + make_shared<FunctionType>(strings{"hash", "hash", "hash", "hash"},strings{}, FunctionType::Location::Log3)), make_shared<MagicVariableDeclaration>("log4", - make_shared<FunctionType>(strings{"hash", "hash", "hash", "hash", "hash"},strings{}, FunctionType::Location::LOG4)), + make_shared<FunctionType>(strings{"hash", "hash", "hash", "hash", "hash"},strings{}, FunctionType::Location::Log4)), make_shared<MagicVariableDeclaration>("sha256", - make_shared<FunctionType>(strings{"hash"}, strings{"hash"}, FunctionType::Location::SHA256)), + make_shared<FunctionType>(strings(), strings{"hash"}, FunctionType::Location::SHA256, true)), make_shared<MagicVariableDeclaration>("ecrecover", - make_shared<FunctionType>(strings{"hash", "hash8", "hash", "hash"}, strings{"address"}, FunctionType::Location::ECRECOVER)), + make_shared<FunctionType>(strings{"hash", "hash8", "hash", "hash"}, strings{"address"}, FunctionType::Location::ECRecover)), make_shared<MagicVariableDeclaration>("ripemd160", - make_shared<FunctionType>(strings{"hash"}, strings{"hash160"}, FunctionType::Location::RIPEMD160))}) + make_shared<FunctionType>(strings(), strings{"hash160"}, FunctionType::Location::RIPEMD160, true))}) { } diff --git a/InterfaceHandler.cpp b/InterfaceHandler.cpp index 82486c5d..7ecde802 100644 --- a/InterfaceHandler.cpp +++ b/InterfaceHandler.cpp @@ -13,7 +13,7 @@ namespace solidity InterfaceHandler::InterfaceHandler() { - m_lastTag = DocTagType::NONE; + m_lastTag = DocTagType::None; } std::unique_ptr<std::string> InterfaceHandler::getDocumentation(ContractDefinition const& _contractDef, @@ -21,13 +21,13 @@ std::unique_ptr<std::string> InterfaceHandler::getDocumentation(ContractDefiniti { switch(_type) { - case DocumentationType::NATSPEC_USER: + case DocumentationType::NatspecUser: return getUserDocumentation(_contractDef); - case DocumentationType::NATSPEC_DEV: + case DocumentationType::NatspecDev: return getDevDocumentation(_contractDef); - case DocumentationType::ABI_INTERFACE: + case DocumentationType::ABIInterface: return getABIInterface(_contractDef); - case DocumentationType::ABI_SOLIDITY_INTERFACE: + case DocumentationType::ABISolidityInterface: return getABISolidityInterface(_contractDef); } @@ -133,7 +133,7 @@ std::unique_ptr<std::string> InterfaceHandler::getUserDocumentation(ContractDefi if (strPtr) { resetUser(); - parseDocString(*strPtr, CommentOwner::FUNCTION); + parseDocString(*strPtr, CommentOwner::Function); if (!m_notice.empty()) {// since @notice is the only user tag if missing function should not appear user["notice"] = Json::Value(m_notice); @@ -158,7 +158,7 @@ std::unique_ptr<std::string> InterfaceHandler::getDevDocumentation(ContractDefin { m_contractAuthor.clear(); m_title.clear(); - parseDocString(*contractDoc, CommentOwner::CONTRACT); + parseDocString(*contractDoc, CommentOwner::Contract); if (!m_contractAuthor.empty()) doc["author"] = m_contractAuthor; @@ -174,7 +174,7 @@ std::unique_ptr<std::string> InterfaceHandler::getDevDocumentation(ContractDefin if (strPtr) { resetDev(); - parseDocString(*strPtr, CommentOwner::FUNCTION); + parseDocString(*strPtr, CommentOwner::Function); if (!m_dev.empty()) method["details"] = Json::Value(m_dev); @@ -251,7 +251,7 @@ std::string::const_iterator InterfaceHandler::parseDocTagParam(std::string::cons auto paramDesc = std::string(currPos, nlPos); m_params.push_back(std::make_pair(paramName, paramDesc)); - m_lastTag = DocTagType::PARAM; + m_lastTag = DocTagType::Param; return skipLineOrEOS(nlPos, _end); } @@ -280,28 +280,28 @@ std::string::const_iterator InterfaceHandler::parseDocTag(std::string::const_ite // LTODO: need to check for @(start of a tag) between here and the end of line // for all cases. Also somehow automate list of acceptable tags for each // language construct since current way does not scale well. - if (m_lastTag == DocTagType::NONE || _tag != "") + if (m_lastTag == DocTagType::None || _tag != "") { if (_tag == "dev") - return parseDocTagLine(_pos, _end, m_dev, DocTagType::DEV, false); + return parseDocTagLine(_pos, _end, m_dev, DocTagType::Dev, false); else if (_tag == "notice") - return parseDocTagLine(_pos, _end, m_notice, DocTagType::NOTICE, false); + return parseDocTagLine(_pos, _end, m_notice, DocTagType::Notice, false); else if (_tag == "return") - return parseDocTagLine(_pos, _end, m_return, DocTagType::RETURN, false); + return parseDocTagLine(_pos, _end, m_return, DocTagType::Return, false); else if (_tag == "author") { - if (_owner == CommentOwner::CONTRACT) - return parseDocTagLine(_pos, _end, m_contractAuthor, DocTagType::AUTHOR, false); - else if (_owner == CommentOwner::FUNCTION) - return parseDocTagLine(_pos, _end, m_author, DocTagType::AUTHOR, false); + if (_owner == CommentOwner::Contract) + return parseDocTagLine(_pos, _end, m_contractAuthor, DocTagType::Author, false); + else if (_owner == CommentOwner::Function) + return parseDocTagLine(_pos, _end, m_author, DocTagType::Author, false); else // LTODO: for now this else makes no sense but later comments will go to more language constructs BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("@author tag is legal only for contracts")); } else if (_tag == "title") { - if (_owner == CommentOwner::CONTRACT) - return parseDocTagLine(_pos, _end, m_title, DocTagType::TITLE, false); + if (_owner == CommentOwner::Contract) + return parseDocTagLine(_pos, _end, m_title, DocTagType::Title, false); else // LTODO: Unknown tag, throw some form of warning and not just an exception BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("@title tag is legal only for contracts")); @@ -322,27 +322,27 @@ std::string::const_iterator InterfaceHandler::appendDocTag(std::string::const_it { switch (m_lastTag) { - case DocTagType::DEV: - return parseDocTagLine(_pos, _end, m_dev, DocTagType::DEV, true); - case DocTagType::NOTICE: - return parseDocTagLine(_pos, _end, m_notice, DocTagType::NOTICE, true); - case DocTagType::RETURN: - return parseDocTagLine(_pos, _end, m_return, DocTagType::RETURN, true); - case DocTagType::AUTHOR: - if (_owner == CommentOwner::CONTRACT) - return parseDocTagLine(_pos, _end, m_contractAuthor, DocTagType::AUTHOR, true); - else if (_owner == CommentOwner::FUNCTION) - return parseDocTagLine(_pos, _end, m_author, DocTagType::AUTHOR, true); + case DocTagType::Dev: + return parseDocTagLine(_pos, _end, m_dev, DocTagType::Dev, true); + case DocTagType::Notice: + return parseDocTagLine(_pos, _end, m_notice, DocTagType::Notice, true); + case DocTagType::Return: + return parseDocTagLine(_pos, _end, m_return, DocTagType::Return, true); + case DocTagType::Author: + if (_owner == CommentOwner::Contract) + return parseDocTagLine(_pos, _end, m_contractAuthor, DocTagType::Author, true); + else if (_owner == CommentOwner::Function) + return parseDocTagLine(_pos, _end, m_author, DocTagType::Author, true); else // LTODO: Unknown tag, throw some form of warning and not just an exception BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("@author tag in illegal comment")); - case DocTagType::TITLE: - if (_owner == CommentOwner::CONTRACT) - return parseDocTagLine(_pos, _end, m_title, DocTagType::TITLE, true); + case DocTagType::Title: + if (_owner == CommentOwner::Contract) + return parseDocTagLine(_pos, _end, m_title, DocTagType::Title, true); else // LTODO: Unknown tag, throw some form of warning and not just an exception BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("@title tag in illegal comment")); - case DocTagType::PARAM: + case DocTagType::Param: return appendDocTagParam(_pos, _end); default: BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Internal: Illegal documentation tag type")); @@ -378,14 +378,14 @@ void InterfaceHandler::parseDocString(std::string const& _string, CommentOwner _ currPos = parseDocTag(tagNameEndPos + 1, end, std::string(tagPos + 1, tagNameEndPos), _owner); } - else if (m_lastTag != DocTagType::NONE) // continuation of the previous tag + else if (m_lastTag != DocTagType::None) // continuation of the previous tag currPos = appendDocTag(currPos, end, _owner); else if (currPos != end) { // if it begins without a tag then consider it as @notice if (currPos == _string.begin()) { - currPos = parseDocTag(currPos, end, "notice", CommentOwner::FUNCTION); + currPos = parseDocTag(currPos, end, "notice", CommentOwner::Function); continue; } else if (nlPos == end) //end of text diff --git a/InterfaceHandler.h b/InterfaceHandler.h index 08232e4d..6aa3f72d 100644 --- a/InterfaceHandler.h +++ b/InterfaceHandler.h @@ -41,19 +41,19 @@ enum class DocumentationType: uint8_t; enum class DocTagType: uint8_t { - NONE = 0, - DEV, - NOTICE, - PARAM, - RETURN, - AUTHOR, - TITLE + None = 0, + Dev, + Notice, + Param, + Return, + Author, + Title }; enum class CommentOwner { - CONTRACT, - FUNCTION + Contract, + Function }; class InterfaceHandler @@ -69,10 +69,10 @@ ASTPointer<SourceUnit> Parser::parse(shared_ptr<Scanner> const& _scanner) { switch (m_scanner->getCurrentToken()) { - case Token::IMPORT: + case Token::Import: nodes.push_back(parseImportDirective()); break; - case Token::CONTRACT: + case Token::Contract: nodes.push_back(parseContractDefinition()); break; default: @@ -100,12 +100,12 @@ int Parser::getEndPosition() const ASTPointer<ImportDirective> Parser::parseImportDirective() { ASTNodeFactory nodeFactory(*this); - expectToken(Token::IMPORT); - if (m_scanner->getCurrentToken() != Token::STRING_LITERAL) + expectToken(Token::Import); + if (m_scanner->getCurrentToken() != Token::StringLiteral) BOOST_THROW_EXCEPTION(createParserError("Expected string literal (URL).")); ASTPointer<ASTString> url = getLiteralAndAdvance(); nodeFactory.markEndPosition(); - expectToken(Token::SEMICOLON); + expectToken(Token::Semicolon); return nodeFactory.createNode<ImportDirective>(url); } @@ -115,7 +115,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition() ASTPointer<ASTString> docString; if (m_scanner->getCurrentCommentLiteral() != "") docString = make_shared<ASTString>(m_scanner->getCurrentCommentLiteral()); - expectToken(Token::CONTRACT); + expectToken(Token::Contract); ASTPointer<ASTString> name = expectIdentifierToken(); vector<ASTPointer<InheritanceSpecifier>> baseContracts; vector<ASTPointer<StructDefinition>> structs; @@ -123,40 +123,40 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition() vector<ASTPointer<FunctionDefinition>> functions; vector<ASTPointer<ModifierDefinition>> modifiers; vector<ASTPointer<EventDefinition>> events; - if (m_scanner->getCurrentToken() == Token::IS) + if (m_scanner->getCurrentToken() == Token::Is) do { m_scanner->next(); baseContracts.push_back(parseInheritanceSpecifier()); } - while (m_scanner->getCurrentToken() == Token::COMMA); - expectToken(Token::LBRACE); + while (m_scanner->getCurrentToken() == Token::Comma); + expectToken(Token::LBrace); while (true) { Token::Value currentToken = m_scanner->getCurrentToken(); - if (currentToken == Token::RBRACE) + if (currentToken == Token::RBrace) break; - else if (currentToken == Token::FUNCTION) + else if (currentToken == Token::Function) functions.push_back(parseFunctionDefinition(name.get())); - else if (currentToken == Token::STRUCT) + else if (currentToken == Token::Struct) structs.push_back(parseStructDefinition()); - else if (currentToken == Token::IDENTIFIER || currentToken == Token::MAPPING || + else if (currentToken == Token::Identifier || currentToken == Token::Mapping || Token::isElementaryTypeName(currentToken)) { VarDeclParserOptions options; options.isStateVariable = true; stateVariables.push_back(parseVariableDeclaration(options)); - expectToken(Token::SEMICOLON); + expectToken(Token::Semicolon); } - else if (currentToken == Token::MODIFIER) + else if (currentToken == Token::Modifier) modifiers.push_back(parseModifierDefinition()); - else if (currentToken == Token::EVENT) + else if (currentToken == Token::Event) events.push_back(parseEventDefinition()); else BOOST_THROW_EXCEPTION(createParserError("Function, variable, struct or modifier declaration expected.")); } nodeFactory.markEndPosition(); - expectToken(Token::RBRACE); + expectToken(Token::RBrace); return nodeFactory.createNode<ContractDefinition>(name, docString, baseContracts, structs, stateVariables, functions, modifiers, events); } @@ -166,12 +166,12 @@ ASTPointer<InheritanceSpecifier> Parser::parseInheritanceSpecifier() ASTNodeFactory nodeFactory(*this); ASTPointer<Identifier> name(parseIdentifier()); vector<ASTPointer<Expression>> arguments; - if (m_scanner->getCurrentToken() == Token::LPAREN) + if (m_scanner->getCurrentToken() == Token::LParen) { m_scanner->next(); arguments = parseFunctionCallListArguments(); nodeFactory.markEndPosition(); - expectToken(Token::RPAREN); + expectToken(Token::RParen); } else nodeFactory.setEndPositionFromNode(name); @@ -180,13 +180,13 @@ ASTPointer<InheritanceSpecifier> Parser::parseInheritanceSpecifier() Declaration::Visibility Parser::parseVisibilitySpecifier(Token::Value _token) { - Declaration::Visibility visibility(Declaration::Visibility::DEFAULT); - if (_token == Token::PUBLIC) - visibility = Declaration::Visibility::PUBLIC; - else if (_token == Token::PROTECTED) - visibility = Declaration::Visibility::PROTECTED; - else if (_token == Token::PRIVATE) - visibility = Declaration::Visibility::PRIVATE; + Declaration::Visibility visibility(Declaration::Visibility::Default); + if (_token == Token::Public) + visibility = Declaration::Visibility::Public; + else if (_token == Token::Protected) + visibility = Declaration::Visibility::Protected; + else if (_token == Token::Private) + visibility = Declaration::Visibility::Private; else solAssert(false, "Invalid visibility specifier."); m_scanner->next(); @@ -200,29 +200,29 @@ ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(ASTString const* if (m_scanner->getCurrentCommentLiteral() != "") docstring = make_shared<ASTString>(m_scanner->getCurrentCommentLiteral()); - expectToken(Token::FUNCTION); + expectToken(Token::Function); ASTPointer<ASTString> name; - if (m_scanner->getCurrentToken() == Token::LPAREN) + if (m_scanner->getCurrentToken() == Token::LParen) name = make_shared<ASTString>(); // anonymous function else name = expectIdentifierToken(); ASTPointer<ParameterList> parameters(parseParameterList()); bool isDeclaredConst = false; - Declaration::Visibility visibility(Declaration::Visibility::DEFAULT); + Declaration::Visibility visibility(Declaration::Visibility::Default); vector<ASTPointer<ModifierInvocation>> modifiers; while (true) { Token::Value token = m_scanner->getCurrentToken(); - if (token == Token::CONST) + if (token == Token::Const) { isDeclaredConst = true; m_scanner->next(); } - else if (token == Token::IDENTIFIER) + else if (token == Token::Identifier) modifiers.push_back(parseModifierInvocation()); else if (Token::isVisibilitySpecifier(token)) { - if (visibility != Declaration::Visibility::DEFAULT) + if (visibility != Declaration::Visibility::Default) BOOST_THROW_EXCEPTION(createParserError("Multiple visibility specifiers.")); visibility = parseVisibilitySpecifier(token); } @@ -230,7 +230,7 @@ ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(ASTString const* break; } ASTPointer<ParameterList> returnParameters; - if (m_scanner->getCurrentToken() == Token::RETURNS) + if (m_scanner->getCurrentToken() == Token::Returns) { bool const permitEmptyParameterList = false; m_scanner->next(); @@ -249,17 +249,17 @@ ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(ASTString const* ASTPointer<StructDefinition> Parser::parseStructDefinition() { ASTNodeFactory nodeFactory(*this); - expectToken(Token::STRUCT); + expectToken(Token::Struct); ASTPointer<ASTString> name = expectIdentifierToken(); vector<ASTPointer<VariableDeclaration>> members; - expectToken(Token::LBRACE); - while (m_scanner->getCurrentToken() != Token::RBRACE) + expectToken(Token::LBrace); + while (m_scanner->getCurrentToken() != Token::RBrace) { members.push_back(parseVariableDeclaration()); - expectToken(Token::SEMICOLON); + expectToken(Token::Semicolon); } nodeFactory.markEndPosition(); - expectToken(Token::RBRACE); + expectToken(Token::RBrace); return nodeFactory.createNode<StructDefinition>(name, members); } @@ -272,16 +272,16 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(VarDeclParserOp bool isIndexed = false; ASTPointer<ASTString> identifier; Token::Value token = m_scanner->getCurrentToken(); - Declaration::Visibility visibility(Declaration::Visibility::DEFAULT); + Declaration::Visibility visibility(Declaration::Visibility::Default); if (_options.isStateVariable && Token::isVisibilitySpecifier(token)) visibility = parseVisibilitySpecifier(token); - if (_options.allowIndexed && token == Token::INDEXED) + if (_options.allowIndexed && token == Token::Indexed) { isIndexed = true; m_scanner->next(); } nodeFactory.markEndPosition(); - if (_options.allowEmptyName && m_scanner->getCurrentToken() != Token::IDENTIFIER) + if (_options.allowEmptyName && m_scanner->getCurrentToken() != Token::Identifier) { identifier = make_shared<ASTString>(""); solAssert(type != nullptr, ""); @@ -304,10 +304,10 @@ ASTPointer<ModifierDefinition> Parser::parseModifierDefinition() if (m_scanner->getCurrentCommentLiteral() != "") docstring = make_shared<ASTString>(m_scanner->getCurrentCommentLiteral()); - expectToken(Token::MODIFIER); + expectToken(Token::Modifier); ASTPointer<ASTString> name(expectIdentifierToken()); ASTPointer<ParameterList> parameters; - if (m_scanner->getCurrentToken() == Token::LPAREN) + if (m_scanner->getCurrentToken() == Token::LParen) parameters = parseParameterList(); else parameters = createEmptyParameterList(); @@ -323,15 +323,15 @@ ASTPointer<EventDefinition> Parser::parseEventDefinition() if (m_scanner->getCurrentCommentLiteral() != "") docstring = make_shared<ASTString>(m_scanner->getCurrentCommentLiteral()); - expectToken(Token::EVENT); + expectToken(Token::Event); ASTPointer<ASTString> name(expectIdentifierToken()); ASTPointer<ParameterList> parameters; - if (m_scanner->getCurrentToken() == Token::LPAREN) + if (m_scanner->getCurrentToken() == Token::LParen) parameters = parseParameterList(true, true); else parameters = createEmptyParameterList(); nodeFactory.markEndPosition(); - expectToken(Token::SEMICOLON); + expectToken(Token::Semicolon); return nodeFactory.createNode<EventDefinition>(name, docstring, parameters); } @@ -340,12 +340,12 @@ ASTPointer<ModifierInvocation> Parser::parseModifierInvocation() ASTNodeFactory nodeFactory(*this); ASTPointer<Identifier> name(parseIdentifier()); vector<ASTPointer<Expression>> arguments; - if (m_scanner->getCurrentToken() == Token::LPAREN) + if (m_scanner->getCurrentToken() == Token::LParen) { m_scanner->next(); arguments = parseFunctionCallListArguments(); nodeFactory.markEndPosition(); - expectToken(Token::RPAREN); + expectToken(Token::RParen); } else nodeFactory.setEndPositionFromNode(name); @@ -368,17 +368,17 @@ ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar) type = ASTNodeFactory(*this).createNode<ElementaryTypeName>(token); m_scanner->next(); } - else if (token == Token::VAR) + else if (token == Token::Var) { if (!_allowVar) BOOST_THROW_EXCEPTION(createParserError("Expected explicit type name.")); m_scanner->next(); } - else if (token == Token::MAPPING) + else if (token == Token::Mapping) { type = parseMapping(); } - else if (token == Token::IDENTIFIER) + else if (token == Token::Identifier) { ASTNodeFactory nodeFactory(*this); nodeFactory.markEndPosition(); @@ -392,18 +392,18 @@ ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar) ASTPointer<Mapping> Parser::parseMapping() { ASTNodeFactory nodeFactory(*this); - expectToken(Token::MAPPING); - expectToken(Token::LPAREN); + expectToken(Token::Mapping); + expectToken(Token::LParen); if (!Token::isElementaryTypeName(m_scanner->getCurrentToken())) BOOST_THROW_EXCEPTION(createParserError("Expected elementary type name for mapping key type")); ASTPointer<ElementaryTypeName> keyType; keyType = ASTNodeFactory(*this).createNode<ElementaryTypeName>(m_scanner->getCurrentToken()); m_scanner->next(); - expectToken(Token::ARROW); + expectToken(Token::Arrow); bool const allowVar = false; ASTPointer<TypeName> valueType = parseTypeName(allowVar); nodeFactory.markEndPosition(); - expectToken(Token::RPAREN); + expectToken(Token::RParen); return nodeFactory.createNode<Mapping>(keyType, valueType); } @@ -414,13 +414,13 @@ ASTPointer<ParameterList> Parser::parseParameterList(bool _allowEmpty, bool _all VarDeclParserOptions options; options.allowIndexed = _allowIndexed; options.allowEmptyName = true; - expectToken(Token::LPAREN); - if (!_allowEmpty || m_scanner->getCurrentToken() != Token::RPAREN) + expectToken(Token::LParen); + if (!_allowEmpty || m_scanner->getCurrentToken() != Token::RParen) { parameters.push_back(parseVariableDeclaration(options)); - while (m_scanner->getCurrentToken() != Token::RPAREN) + while (m_scanner->getCurrentToken() != Token::RParen) { - expectToken(Token::COMMA); + expectToken(Token::Comma); parameters.push_back(parseVariableDeclaration(options)); } } @@ -432,12 +432,12 @@ ASTPointer<ParameterList> Parser::parseParameterList(bool _allowEmpty, bool _all ASTPointer<Block> Parser::parseBlock() { ASTNodeFactory nodeFactory(*this); - expectToken(Token::LBRACE); + expectToken(Token::LBrace); vector<ASTPointer<Statement>> statements; - while (m_scanner->getCurrentToken() != Token::RBRACE) + while (m_scanner->getCurrentToken() != Token::RBrace) statements.push_back(parseStatement()); nodeFactory.markEndPosition(); - expectToken(Token::RBRACE); + expectToken(Token::RBrace); return nodeFactory.createNode<Block>(statements); } @@ -446,28 +446,28 @@ ASTPointer<Statement> Parser::parseStatement() ASTPointer<Statement> statement; switch (m_scanner->getCurrentToken()) { - case Token::IF: + case Token::If: return parseIfStatement(); - case Token::WHILE: + case Token::While: return parseWhileStatement(); - case Token::FOR: + case Token::For: return parseForStatement(); - case Token::LBRACE: + case Token::LBrace: return parseBlock(); // starting from here, all statements must be terminated by a semicolon - case Token::CONTINUE: + case Token::Continue: statement = ASTNodeFactory(*this).createNode<Continue>(); m_scanner->next(); break; - case Token::BREAK: + case Token::Break: statement = ASTNodeFactory(*this).createNode<Break>(); m_scanner->next(); break; - case Token::RETURN: + case Token::Return: { ASTNodeFactory nodeFactory(*this); ASTPointer<Expression> expression; - if (m_scanner->next() != Token::SEMICOLON) + if (m_scanner->next() != Token::Semicolon) { expression = parseExpression(); nodeFactory.setEndPositionFromNode(expression); @@ -475,7 +475,7 @@ ASTPointer<Statement> Parser::parseStatement() statement = nodeFactory.createNode<Return>(expression); break; } - case Token::IDENTIFIER: + case Token::Identifier: if (m_insideModifier && m_scanner->getCurrentLiteral() == "_") { statement = ASTNodeFactory(*this).createNode<PlaceholderStatement>(); @@ -486,20 +486,20 @@ ASTPointer<Statement> Parser::parseStatement() default: statement = parseVarDefOrExprStmt(); } - expectToken(Token::SEMICOLON); + expectToken(Token::Semicolon); return statement; } ASTPointer<IfStatement> Parser::parseIfStatement() { ASTNodeFactory nodeFactory(*this); - expectToken(Token::IF); - expectToken(Token::LPAREN); + expectToken(Token::If); + expectToken(Token::LParen); ASTPointer<Expression> condition = parseExpression(); - expectToken(Token::RPAREN); + expectToken(Token::RParen); ASTPointer<Statement> trueBody = parseStatement(); ASTPointer<Statement> falseBody; - if (m_scanner->getCurrentToken() == Token::ELSE) + if (m_scanner->getCurrentToken() == Token::Else) { m_scanner->next(); falseBody = parseStatement(); @@ -513,10 +513,10 @@ ASTPointer<IfStatement> Parser::parseIfStatement() ASTPointer<WhileStatement> Parser::parseWhileStatement() { ASTNodeFactory nodeFactory(*this); - expectToken(Token::WHILE); - expectToken(Token::LPAREN); + expectToken(Token::While); + expectToken(Token::LParen); ASTPointer<Expression> condition = parseExpression(); - expectToken(Token::RPAREN); + expectToken(Token::RParen); ASTPointer<Statement> body = parseStatement(); nodeFactory.setEndPositionFromNode(body); return nodeFactory.createNode<WhileStatement>(condition, body); @@ -528,21 +528,21 @@ ASTPointer<ForStatement> Parser::parseForStatement() ASTPointer<Statement> initExpression; ASTPointer<Expression> conditionExpression; ASTPointer<ExpressionStatement> loopExpression; - expectToken(Token::FOR); - expectToken(Token::LPAREN); + expectToken(Token::For); + expectToken(Token::LParen); - // LTODO: Maybe here have some predicate like peekExpression() instead of checking for semicolon and RPAREN? - if (m_scanner->getCurrentToken() != Token::SEMICOLON) + // LTODO: Maybe here have some predicate like peekExpression() instead of checking for semicolon and RParen? + if (m_scanner->getCurrentToken() != Token::Semicolon) initExpression = parseVarDefOrExprStmt(); - expectToken(Token::SEMICOLON); + expectToken(Token::Semicolon); - if (m_scanner->getCurrentToken() != Token::SEMICOLON) + if (m_scanner->getCurrentToken() != Token::Semicolon) conditionExpression = parseExpression(); - expectToken(Token::SEMICOLON); + expectToken(Token::Semicolon); - if (m_scanner->getCurrentToken() != Token::RPAREN) + if (m_scanner->getCurrentToken() != Token::RParen) loopExpression = parseExpressionStatement(); - expectToken(Token::RPAREN); + expectToken(Token::RParen); ASTPointer<Statement> body = parseStatement(); nodeFactory.setEndPositionFromNode(body); @@ -567,7 +567,7 @@ ASTPointer<VariableDefinition> Parser::parseVariableDefinition() options.allowVar = true; ASTPointer<VariableDeclaration> variable = parseVariableDeclaration(options); ASTPointer<Expression> value; - if (m_scanner->getCurrentToken() == Token::ASSIGN) + if (m_scanner->getCurrentToken() == Token::Assign) { m_scanner->next(); value = parseExpression(); @@ -644,9 +644,9 @@ ASTPointer<Expression> Parser::parseLeftHandSideExpression() { ASTNodeFactory nodeFactory(*this); ASTPointer<Expression> expression; - if (m_scanner->getCurrentToken() == Token::NEW) + if (m_scanner->getCurrentToken() == Token::New) { - expectToken(Token::NEW); + expectToken(Token::New); ASTPointer<Identifier> contractName(parseIdentifier()); nodeFactory.setEndPositionFromNode(contractName); expression = nodeFactory.createNode<NewExpression>(contractName); @@ -658,30 +658,30 @@ ASTPointer<Expression> Parser::parseLeftHandSideExpression() { switch (m_scanner->getCurrentToken()) { - case Token::LBRACK: + case Token::LBrack: { m_scanner->next(); ASTPointer<Expression> index = parseExpression(); nodeFactory.markEndPosition(); - expectToken(Token::RBRACK); + expectToken(Token::RBrack); expression = nodeFactory.createNode<IndexAccess>(expression, index); } break; - case Token::PERIOD: + case Token::Period: { m_scanner->next(); nodeFactory.markEndPosition(); expression = nodeFactory.createNode<MemberAccess>(expression, expectIdentifierToken()); } break; - case Token::LPAREN: + case Token::LParen: { m_scanner->next(); vector<ASTPointer<Expression>> arguments; vector<ASTPointer<ASTString>> names; std::tie(arguments, names) = parseFunctionCallArguments(); nodeFactory.markEndPosition(); - expectToken(Token::RPAREN); + expectToken(Token::RParen); expression = nodeFactory.createNode<FunctionCall>(expression, arguments, names); } break; @@ -698,11 +698,11 @@ ASTPointer<Expression> Parser::parsePrimaryExpression() ASTPointer<Expression> expression; switch (token) { - case Token::TRUE_LITERAL: - case Token::FALSE_LITERAL: + case Token::TrueLiteral: + case Token::FalseLiteral: expression = nodeFactory.createNode<Literal>(token, getLiteralAndAdvance()); break; - case Token::NUMBER: + case Token::Number: if (Token::isEtherSubdenomination(m_scanner->peekNextToken())) { ASTPointer<ASTString> literal = getLiteralAndAdvance(); @@ -713,19 +713,19 @@ ASTPointer<Expression> Parser::parsePrimaryExpression() break; } // fall-through - case Token::STRING_LITERAL: + case Token::StringLiteral: nodeFactory.markEndPosition(); expression = nodeFactory.createNode<Literal>(token, getLiteralAndAdvance()); break; - case Token::IDENTIFIER: + case Token::Identifier: nodeFactory.markEndPosition(); expression = nodeFactory.createNode<Identifier>(getLiteralAndAdvance()); break; - case Token::LPAREN: + case Token::LParen: { m_scanner->next(); ASTPointer<Expression> expression = parseExpression(); - expectToken(Token::RPAREN); + expectToken(Token::RParen); return expression; } default: @@ -748,12 +748,12 @@ ASTPointer<Expression> Parser::parsePrimaryExpression() vector<ASTPointer<Expression>> Parser::parseFunctionCallListArguments() { vector<ASTPointer<Expression>> arguments; - if (m_scanner->getCurrentToken() != Token::RPAREN) + if (m_scanner->getCurrentToken() != Token::RParen) { arguments.push_back(parseExpression()); - while (m_scanner->getCurrentToken() != Token::RPAREN) + while (m_scanner->getCurrentToken() != Token::RParen) { - expectToken(Token::COMMA); + expectToken(Token::Comma); arguments.push_back(parseExpression()); } } @@ -764,22 +764,22 @@ pair<vector<ASTPointer<Expression>>, vector<ASTPointer<ASTString>>> Parser::pars { pair<vector<ASTPointer<Expression>>, vector<ASTPointer<ASTString>>> ret; Token::Value token = m_scanner->getCurrentToken(); - if (token == Token::LBRACE) + if (token == Token::LBrace) { // call({arg1 : 1, arg2 : 2 }) - expectToken(Token::LBRACE); - while (m_scanner->getCurrentToken() != Token::RBRACE) + expectToken(Token::LBrace); + while (m_scanner->getCurrentToken() != Token::RBrace) { ret.second.push_back(expectIdentifierToken()); - expectToken(Token::COLON); + expectToken(Token::Colon); ret.first.push_back(parseExpression()); - if (m_scanner->getCurrentToken() == Token::COMMA) - expectToken(Token::COMMA); + if (m_scanner->getCurrentToken() == Token::Comma) + expectToken(Token::Comma); else break; } - expectToken(Token::RBRACE); + expectToken(Token::RBrace); } else ret.first = parseFunctionCallListArguments(); @@ -793,11 +793,11 @@ bool Parser::peekVariableDefinition() // (which include assignments to other expressions and pre-declared variables) // We have a variable definition if we get a keyword that specifies a type name, or // in the case of a user-defined type, we have two identifiers following each other. - return (m_scanner->getCurrentToken() == Token::MAPPING || - m_scanner->getCurrentToken() == Token::VAR || + return (m_scanner->getCurrentToken() == Token::Mapping || + m_scanner->getCurrentToken() == Token::Var || ((Token::isElementaryTypeName(m_scanner->getCurrentToken()) || - m_scanner->getCurrentToken() == Token::IDENTIFIER) && - m_scanner->peekNextToken() == Token::IDENTIFIER)); + m_scanner->getCurrentToken() == Token::Identifier) && + m_scanner->peekNextToken() == Token::Identifier)); } void Parser::expectToken(Token::Value _value) @@ -818,7 +818,7 @@ Token::Value Parser::expectAssignmentOperator() ASTPointer<ASTString> Parser::expectIdentifierToken() { - if (m_scanner->getCurrentToken() != Token::IDENTIFIER) + if (m_scanner->getCurrentToken() != Token::Identifier) BOOST_THROW_EXCEPTION(createParserError("Expected identifier")); return getLiteralAndAdvance(); } diff --git a/Scanner.cpp b/Scanner.cpp index 6a8ecd9d..fbe3ea97 100644 --- a/Scanner.cpp +++ b/Scanner.cpp @@ -225,7 +225,7 @@ Token::Value Scanner::skipSingleLineComment() // separately by the lexical grammar and becomes part of the // stream of input elements for the syntactic grammar while (advance() && !isLineTerminator(m_char)) { }; - return Token::WHITESPACE; + return Token::Whitespace; } Token::Value Scanner::scanSingleLineDocComment() @@ -255,7 +255,7 @@ Token::Value Scanner::scanSingleLineDocComment() advance(); } literal.complete(); - return Token::COMMENT_LITERAL; + return Token::CommentLiteral; } Token::Value Scanner::skipMultiLineComment() @@ -272,11 +272,11 @@ Token::Value Scanner::skipMultiLineComment() if (ch == '*' && m_char == '/') { m_char = ' '; - return Token::WHITESPACE; + return Token::Whitespace; } } // Unterminated multi-line comment. - return Token::ILLEGAL; + return Token::Illegal; } Token::Value Scanner::scanMultiLineDocComment() @@ -319,9 +319,9 @@ Token::Value Scanner::scanMultiLineDocComment() } literal.complete(); if (!endFound) - return Token::ILLEGAL; + return Token::Illegal; else - return Token::COMMENT_LITERAL; + return Token::CommentLiteral; } Token::Value Scanner::scanSlash() @@ -331,7 +331,7 @@ Token::Value Scanner::scanSlash() if (m_char == '/') { if (!advance()) /* double slash comment directly before EOS */ - return Token::WHITESPACE; + return Token::Whitespace; else if (m_char == '/') { // doxygen style /// comment @@ -340,7 +340,7 @@ Token::Value Scanner::scanSlash() comment = scanSingleLineDocComment(); m_nextSkippedComment.location.end = getSourcePos(); m_nextSkippedComment.token = comment; - return Token::WHITESPACE; + return Token::Whitespace; } else return skipSingleLineComment(); @@ -349,7 +349,7 @@ Token::Value Scanner::scanSlash() { // doxygen style /** natspec comment if (!advance()) /* slash star comment before EOS */ - return Token::WHITESPACE; + return Token::Whitespace; else if (m_char == '*') { advance(); //consume the last '*' at /** @@ -366,15 +366,15 @@ Token::Value Scanner::scanSlash() m_nextSkippedComment.location.end = getSourcePos(); m_nextSkippedComment.token = comment; } - return Token::WHITESPACE; + return Token::Whitespace; } else return skipMultiLineComment(); } else if (m_char == '=') - return selectToken(Token::ASSIGN_DIV); + return selectToken(Token::AssignDiv); else - return Token::DIV; + return Token::Div; } void Scanner::scanToken() @@ -391,7 +391,7 @@ void Scanner::scanToken() case '\n': // fall-through case ' ': case '\t': - token = selectToken(Token::WHITESPACE); + token = selectToken(Token::Whitespace); break; case '"': case '\'': @@ -401,76 +401,82 @@ void Scanner::scanToken() // < <= << <<= advance(); if (m_char == '=') - token = selectToken(Token::LTE); + token = selectToken(Token::LessThanOrEqual); else if (m_char == '<') - token = selectToken('=', Token::ASSIGN_SHL, Token::SHL); + token = selectToken('=', Token::AssignShl, Token::SHL); else - token = Token::LT; + token = Token::LessThan; break; case '>': // > >= >> >>= >>> >>>= advance(); if (m_char == '=') - token = selectToken(Token::GTE); + token = selectToken(Token::GreaterThanOrEqual); else if (m_char == '>') { // >> >>= >>> >>>= advance(); if (m_char == '=') - token = selectToken(Token::ASSIGN_SAR); + token = selectToken(Token::AssignSar); else if (m_char == '>') - token = selectToken('=', Token::ASSIGN_SHR, Token::SHR); + token = selectToken('=', Token::AssignShr, Token::SHR); else token = Token::SAR; } else - token = Token::GT; + token = Token::GreaterThan; break; case '=': // = == => advance(); if (m_char == '=') - token = selectToken(Token::EQ); + token = selectToken(Token::Equal); else if (m_char == '>') - token = selectToken(Token::ARROW); + token = selectToken(Token::Arrow); else - token = Token::ASSIGN; + token = Token::Assign; break; case '!': // ! != advance(); if (m_char == '=') - token = selectToken(Token::NE); + token = selectToken(Token::NotEqual); else - token = Token::NOT; + token = Token::Not; break; case '+': // + ++ += advance(); if (m_char == '+') - token = selectToken(Token::INC); + token = selectToken(Token::Inc); else if (m_char == '=') - token = selectToken(Token::ASSIGN_ADD); + token = selectToken(Token::AssignAdd); else - token = Token::ADD; + token = Token::Add; break; case '-': // - -- -= advance(); if (m_char == '-') - token = selectToken(Token::DEC); + token = selectToken(Token::Dec); else if (m_char == '=') - token = selectToken(Token::ASSIGN_SUB); + token = selectToken(Token::AssignSub); else - token = Token::SUB; + token = Token::Sub; break; case '*': - // * *= - token = selectToken('=', Token::ASSIGN_MUL, Token::MUL); + // * ** *= + advance(); + if (m_char == '*') + token = selectToken(Token::Exp); + else if (m_char == '=') + token = selectToken(Token::AssignMul); + else + token = Token::Mul; break; case '%': // % %= - token = selectToken('=', Token::ASSIGN_MOD, Token::MOD); + token = selectToken('=', Token::AssignMod, Token::Mod); break; case '/': // / // /* /= @@ -480,25 +486,25 @@ void Scanner::scanToken() // & && &= advance(); if (m_char == '&') - token = selectToken(Token::AND); + token = selectToken(Token::And); else if (m_char == '=') - token = selectToken(Token::ASSIGN_BIT_AND); + token = selectToken(Token::AssignBitAnd); else - token = Token::BIT_AND; + token = Token::BitAnd; break; case '|': // | || |= advance(); if (m_char == '|') - token = selectToken(Token::OR); + token = selectToken(Token::Or); else if (m_char == '=') - token = selectToken(Token::ASSIGN_BIT_OR); + token = selectToken(Token::AssignBitOr); else - token = Token::BIT_OR; + token = Token::BitOr; break; case '^': // ^ ^= - token = selectToken('=', Token::ASSIGN_BIT_XOR, Token::BIT_XOR); + token = selectToken('=', Token::AssignBitXor, Token::BitXor); break; case '.': // . Number @@ -506,40 +512,40 @@ void Scanner::scanToken() if (isDecimalDigit(m_char)) token = scanNumber('.'); else - token = Token::PERIOD; + token = Token::Period; break; case ':': - token = selectToken(Token::COLON); + token = selectToken(Token::Colon); break; case ';': - token = selectToken(Token::SEMICOLON); + token = selectToken(Token::Semicolon); break; case ',': - token = selectToken(Token::COMMA); + token = selectToken(Token::Comma); break; case '(': - token = selectToken(Token::LPAREN); + token = selectToken(Token::LParen); break; case ')': - token = selectToken(Token::RPAREN); + token = selectToken(Token::RParen); break; case '[': - token = selectToken(Token::LBRACK); + token = selectToken(Token::LBrack); break; case ']': - token = selectToken(Token::RBRACK); + token = selectToken(Token::RBrack); break; case '{': - token = selectToken(Token::LBRACE); + token = selectToken(Token::LBrace); break; case '}': - token = selectToken(Token::RBRACE); + token = selectToken(Token::RBrace); break; case '?': - token = selectToken(Token::CONDITIONAL); + token = selectToken(Token::Conditional); break; case '~': - token = selectToken(Token::BIT_NOT); + token = selectToken(Token::BitNot); break; default: if (isIdentifierStart(m_char)) @@ -547,17 +553,17 @@ void Scanner::scanToken() else if (isDecimalDigit(m_char)) token = scanNumber(); else if (skipWhitespace()) - token = Token::WHITESPACE; + token = Token::Whitespace; else if (isSourcePastEndOfInput()) token = Token::EOS; else - token = selectToken(Token::ILLEGAL); + token = selectToken(Token::Illegal); break; } // Continue scanning for tokens as long as we're just skipping // whitespace. } - while (token == Token::WHITESPACE); + while (token == Token::Whitespace); m_nextToken.location.end = getSourcePos(); m_nextToken.token = token; } @@ -615,16 +621,16 @@ Token::Value Scanner::scanString() if (c == '\\') { if (isSourcePastEndOfInput() || !scanEscape()) - return Token::ILLEGAL; + return Token::Illegal; } else addLiteralChar(c); } if (m_char != quote) - return Token::ILLEGAL; + return Token::Illegal; literal.complete(); advance(); // consume quote - return Token::STRING_LITERAL; + return Token::StringLiteral; } void Scanner::scanDecimalDigits() @@ -657,7 +663,7 @@ Token::Value Scanner::scanNumber(char _charSeen) kind = HEX; addLiteralCharAndAdvance(); if (!isHexDigit(m_char)) - return Token::ILLEGAL; // we must have at least one hex digit after 'x'/'X' + return Token::Illegal; // we must have at least one hex digit after 'x'/'X' while (isHexDigit(m_char)) addLiteralCharAndAdvance(); } @@ -678,13 +684,13 @@ Token::Value Scanner::scanNumber(char _charSeen) { solAssert(kind != HEX, "'e'/'E' must be scanned as part of the hex number"); if (kind != DECIMAL) - return Token::ILLEGAL; + return Token::Illegal; // scan exponent addLiteralCharAndAdvance(); if (m_char == '+' || m_char == '-') addLiteralCharAndAdvance(); if (!isDecimalDigit(m_char)) - return Token::ILLEGAL; // we must have at least one decimal digit after 'e'/'E' + return Token::Illegal; // we must have at least one decimal digit after 'e'/'E' scanDecimalDigits(); } // The source character immediately following a numeric literal must @@ -692,9 +698,9 @@ Token::Value Scanner::scanNumber(char _charSeen) // section 7.8.3, page 17 (note that we read only one decimal digit // if the value is 0). if (isDecimalDigit(m_char) || isIdentifierStart(m_char)) - return Token::ILLEGAL; + return Token::Illegal; literal.complete(); - return Token::NUMBER; + return Token::Number; } Token::Value Scanner::scanIdentifierOrKeyword() @@ -80,7 +80,6 @@ char const Token::m_tokenType[] = { TOKEN_LIST(KT, KK) }; - Token::Value Token::fromIdentifierOrKeyword(const std::string& _name) { // The following macros are used inside TOKEN_LIST and cause non-keyword tokens to be ignored @@ -91,7 +90,7 @@ Token::Value Token::fromIdentifierOrKeyword(const std::string& _name) #undef KEYWORD #undef TOKEN auto it = keywords.find(_name); - return it == keywords.end() ? Token::IDENTIFIER : it->second; + return it == keywords.end() ? Token::Identifier : it->second; } #undef KT @@ -47,11 +47,6 @@ #include <libsolidity/Utils.h> #include <libsolidity/Exceptions.h> -#if defined(DELETE) -#undef DELETE -//#error The macro "DELETE" from windows.h conflicts with this file. Please change the order of includes. -#endif - namespace dev { namespace solidity @@ -77,101 +72,102 @@ namespace solidity T(EOS, "EOS", 0) \ \ /* Punctuators (ECMA-262, section 7.7, page 15). */ \ - T(LPAREN, "(", 0) \ - T(RPAREN, ")", 0) \ - T(LBRACK, "[", 0) \ - T(RBRACK, "]", 0) \ - T(LBRACE, "{", 0) \ - T(RBRACE, "}", 0) \ - T(COLON, ":", 0) \ - T(SEMICOLON, ";", 0) \ - T(PERIOD, ".", 0) \ - T(CONDITIONAL, "?", 3) \ - T(ARROW, "=>", 0) \ + T(LParen, "(", 0) \ + T(RParen, ")", 0) \ + T(LBrack, "[", 0) \ + T(RBrack, "]", 0) \ + T(LBrace, "{", 0) \ + T(RBrace, "}", 0) \ + T(Colon, ":", 0) \ + T(Semicolon, ";", 0) \ + T(Period, ".", 0) \ + T(Conditional, "?", 3) \ + T(Arrow, "=>", 0) \ \ /* Assignment operators. */ \ /* IsAssignmentOp() relies on this block of enum values being */ \ /* contiguous and sorted in the same order!*/ \ - T(ASSIGN, "=", 2) \ + T(Assign, "=", 2) \ /* The following have to be in exactly the same order as the simple binary operators*/ \ - T(ASSIGN_BIT_OR, "|=", 2) \ - T(ASSIGN_BIT_XOR, "^=", 2) \ - T(ASSIGN_BIT_AND, "&=", 2) \ - T(ASSIGN_SHL, "<<=", 2) \ - T(ASSIGN_SAR, ">>=", 2) \ - T(ASSIGN_SHR, ">>>=", 2) \ - T(ASSIGN_ADD, "+=", 2) \ - T(ASSIGN_SUB, "-=", 2) \ - T(ASSIGN_MUL, "*=", 2) \ - T(ASSIGN_DIV, "/=", 2) \ - T(ASSIGN_MOD, "%=", 2) \ + T(AssignBitOr, "|=", 2) \ + T(AssignBitXor, "^=", 2) \ + T(AssignBitAnd, "&=", 2) \ + T(AssignShl, "<<=", 2) \ + T(AssignSar, ">>=", 2) \ + T(AssignShr, ">>>=", 2) \ + T(AssignAdd, "+=", 2) \ + T(AssignSub, "-=", 2) \ + T(AssignMul, "*=", 2) \ + T(AssignDiv, "/=", 2) \ + T(AssignMod, "%=", 2) \ \ /* Binary operators sorted by precedence. */ \ /* IsBinaryOp() relies on this block of enum values */ \ /* being contiguous and sorted in the same order! */ \ - T(COMMA, ",", 1) \ - T(OR, "||", 4) \ - T(AND, "&&", 5) \ - T(BIT_OR, "|", 8) \ - T(BIT_XOR, "^", 9) \ - T(BIT_AND, "&", 10) \ + T(Comma, ",", 1) \ + T(Or, "||", 4) \ + T(And, "&&", 5) \ + T(BitOr, "|", 8) \ + T(BitXor, "^", 9) \ + T(BitAnd, "&", 10) \ T(SHL, "<<", 11) \ T(SAR, ">>", 11) \ T(SHR, ">>>", 11) \ - T(ADD, "+", 12) \ - T(SUB, "-", 12) \ - T(MUL, "*", 13) \ - T(DIV, "/", 13) \ - T(MOD, "%", 13) \ + T(Add, "+", 12) \ + T(Sub, "-", 12) \ + T(Mul, "*", 13) \ + T(Div, "/", 13) \ + T(Mod, "%", 13) \ + T(Exp, "**", 14) \ \ /* Compare operators sorted by precedence. */ \ /* IsCompareOp() relies on this block of enum values */ \ /* being contiguous and sorted in the same order! */ \ - T(EQ, "==", 6) \ - T(NE, "!=", 6) \ - T(LT, "<", 7) \ - T(GT, ">", 7) \ - T(LTE, "<=", 7) \ - T(GTE, ">=", 7) \ - K(IN, "in", 7) \ + T(Equal, "==", 6) \ + T(NotEqual, "!=", 6) \ + T(LessThan, "<", 7) \ + T(GreaterThan, ">", 7) \ + T(LessThanOrEqual, "<=", 7) \ + T(GreaterThanOrEqual, ">=", 7) \ + K(In, "in", 7) \ \ /* Unary operators. */ \ /* IsUnaryOp() relies on this block of enum values */ \ /* being contiguous and sorted in the same order! */ \ - T(NOT, "!", 0) \ - T(BIT_NOT, "~", 0) \ - T(INC, "++", 0) \ - T(DEC, "--", 0) \ - K(DELETE, "delete", 0) \ + T(Not, "!", 0) \ + T(BitNot, "~", 0) \ + T(Inc, "++", 0) \ + T(Dec, "--", 0) \ + K(Delete, "delete", 0) \ \ /* Keywords */ \ - K(BREAK, "break", 0) \ - K(CASE, "case", 0) \ - K(CONST, "constant", 0) \ - K(CONTINUE, "continue", 0) \ - K(CONTRACT, "contract", 0) \ - K(DEFAULT, "default", 0) \ - K(DO, "do", 0) \ - K(ELSE, "else", 0) \ - K(EVENT, "event", 0) \ - K(IS, "is", 0) \ - K(INDEXED, "indexed", 0) \ - K(FOR, "for", 0) \ - K(FUNCTION, "function", 0) \ - K(IF, "if", 0) \ - K(IMPORT, "import", 0) \ - K(MAPPING, "mapping", 0) \ - K(MODIFIER, "modifier", 0) \ - K(NEW, "new", 0) \ - K(PUBLIC, "public", 0) \ - K(PRIVATE, "private", 0) \ - K(PROTECTED, "protected", 0) \ - K(RETURN, "return", 0) \ - K(RETURNS, "returns", 0) \ - K(STRUCT, "struct", 0) \ - K(SWITCH, "switch", 0) \ - K(VAR, "var", 0) \ - K(WHILE, "while", 0) \ + K(Break, "break", 0) \ + K(Case, "case", 0) \ + K(Const, "constant", 0) \ + K(Continue, "continue", 0) \ + K(Contract, "contract", 0) \ + K(Default, "default", 0) \ + K(Do, "do", 0) \ + K(Else, "else", 0) \ + K(Event, "event", 0) \ + K(Is, "is", 0) \ + K(Indexed, "indexed", 0) \ + K(For, "for", 0) \ + K(Function, "function", 0) \ + K(If, "if", 0) \ + K(Import, "import", 0) \ + K(Mapping, "mapping", 0) \ + K(Modifier, "modifier", 0) \ + K(New, "new", 0) \ + K(Public, "public", 0) \ + K(Private, "private", 0) \ + K(Protected, "protected", 0) \ + K(Return, "return", 0) \ + K(Returns, "returns", 0) \ + K(Struct, "struct", 0) \ + K(Switch, "switch", 0) \ + K(Var, "var", 0) \ + K(While, "while", 0) \ \ \ /* Ether subdenominations */ \ @@ -182,162 +178,162 @@ namespace solidity /* type keywords, keep them in this order, keep int as first keyword * the implementation in Types.cpp has to be synced to this here * TODO more to be added */ \ - K(INT, "int", 0) \ - K(INT8, "int8", 0) \ - K(INT16, "int16", 0) \ - K(INT24, "int24", 0) \ - K(INT32, "int32", 0) \ - K(INT40, "int40", 0) \ - K(INT48, "int48", 0) \ - K(INT56, "int56", 0) \ - K(INT64, "int64", 0) \ - K(INT72, "int72", 0) \ - K(INT80, "int80", 0) \ - K(INT88, "int88", 0) \ - K(INT96, "int96", 0) \ - K(INT104, "int104", 0) \ - K(INT112, "int112", 0) \ - K(INT120, "int120", 0) \ - K(INT128, "int128", 0) \ - K(INT136, "int136", 0) \ - K(INT144, "int144", 0) \ - K(INT152, "int152", 0) \ - K(INT160, "int160", 0) \ - K(INT168, "int168", 0) \ - K(INT176, "int178", 0) \ - K(INT184, "int184", 0) \ - K(INT192, "int192", 0) \ - K(INT200, "int200", 0) \ - K(INT208, "int208", 0) \ - K(INT216, "int216", 0) \ - K(INT224, "int224", 0) \ - K(INT232, "int232", 0) \ - K(INT240, "int240", 0) \ - K(INT248, "int248", 0) \ - K(INT256, "int256", 0) \ - K(UINT, "uint", 0) \ - K(UINT8, "uint8", 0) \ - K(UINT16, "uint16", 0) \ - K(UINT24, "uint24", 0) \ - K(UINT32, "uint32", 0) \ - K(UINT40, "uint40", 0) \ - K(UINT48, "uint48", 0) \ - K(UINT56, "uint56", 0) \ - K(UINT64, "uint64", 0) \ - K(UINT72, "uint72", 0) \ - K(UINT80, "uint80", 0) \ - K(UINT88, "uint88", 0) \ - K(UINT96, "uint96", 0) \ - K(UINT104, "uint104", 0) \ - K(UINT112, "uint112", 0) \ - K(UINT120, "uint120", 0) \ - K(UINT128, "uint128", 0) \ - K(UINT136, "uint136", 0) \ - K(UINT144, "uint144", 0) \ - K(UINT152, "uint152", 0) \ - K(UINT160, "uint160", 0) \ - K(UINT168, "uint168", 0) \ - K(UINT176, "uint178", 0) \ - K(UINT184, "uint184", 0) \ - K(UINT192, "uint192", 0) \ - K(UINT200, "uint200", 0) \ - K(UINT208, "uint208", 0) \ - K(UINT216, "uint216", 0) \ - K(UINT224, "uint224", 0) \ - K(UINT232, "uint232", 0) \ - K(UINT240, "uint240", 0) \ - K(UINT248, "uint248", 0) \ - K(UINT256, "uint256", 0) \ - K(HASH, "hash", 0) \ - K(HASH8, "hash8", 0) \ - K(HASH16, "hash16", 0) \ - K(HASH24, "hash24", 0) \ - K(HASH32, "hash32", 0) \ - K(HASH40, "hash40", 0) \ - K(HASH48, "hash48", 0) \ - K(HASH56, "hash56", 0) \ - K(HASH64, "hash64", 0) \ - K(HASH72, "hash72", 0) \ - K(HASH80, "hash80", 0) \ - K(HASH88, "hash88", 0) \ - K(HASH96, "hash96", 0) \ - K(HASH104, "hash104", 0) \ - K(HASH112, "hash112", 0) \ - K(HASH120, "hash120", 0) \ - K(HASH128, "hash128", 0) \ - K(HASH136, "hash136", 0) \ - K(HASH144, "hash144", 0) \ - K(HASH152, "hash152", 0) \ - K(HASH160, "hash160", 0) \ - K(HASH168, "hash168", 0) \ - K(HASH176, "hash178", 0) \ - K(HASH184, "hash184", 0) \ - K(HASH192, "hash192", 0) \ - K(HASH200, "hash200", 0) \ - K(HASH208, "hash208", 0) \ - K(HASH216, "hash216", 0) \ - K(HASH224, "hash224", 0) \ - K(HASH232, "hash232", 0) \ - K(HASH240, "hash240", 0) \ - K(HASH248, "hash248", 0) \ - K(HASH256, "hash256", 0) \ - K(ADDRESS, "address", 0) \ - K(BOOL, "bool", 0) \ - K(STRING_TYPE, "string", 0) \ - K(STRING0, "string0", 0) \ - K(STRING1, "string1", 0) \ - K(STRING2, "string2", 0) \ - K(STRING3, "string3", 0) \ - K(STRING4, "string4", 0) \ - K(STRING5, "string5", 0) \ - K(STRING6, "string6", 0) \ - K(STRING7, "string7", 0) \ - K(STRING8, "string8", 0) \ - K(STRING9, "string9", 0) \ - K(STRING10, "string10", 0) \ - K(STRING11, "string11", 0) \ - K(STRING12, "string12", 0) \ - K(STRING13, "string13", 0) \ - K(STRING14, "string14", 0) \ - K(STRING15, "string15", 0) \ - K(STRING16, "string16", 0) \ - K(STRING17, "string17", 0) \ - K(STRING18, "string18", 0) \ - K(STRING19, "string19", 0) \ - K(STRING20, "string20", 0) \ - K(STRING21, "string21", 0) \ - K(STRING22, "string22", 0) \ - K(STRING23, "string23", 0) \ - K(STRING24, "string24", 0) \ - K(STRING25, "string25", 0) \ - K(STRING26, "string26", 0) \ - K(STRING27, "string27", 0) \ - K(STRING28, "string28", 0) \ - K(STRING29, "string29", 0) \ - K(STRING30, "string30", 0) \ - K(STRING31, "string31", 0) \ - K(STRING32, "string32", 0) \ - K(TEXT, "text", 0) \ - K(REAL, "real", 0) \ - K(UREAL, "ureal", 0) \ - T(TYPES_END, NULL, 0) /* used as type enum end marker */ \ + K(Int, "int", 0) \ + K(Int8, "int8", 0) \ + K(Int16, "int16", 0) \ + K(Int24, "int24", 0) \ + K(Int32, "int32", 0) \ + K(Int40, "int40", 0) \ + K(Int48, "int48", 0) \ + K(Int56, "int56", 0) \ + K(Int64, "int64", 0) \ + K(Int72, "int72", 0) \ + K(Int80, "int80", 0) \ + K(Int88, "int88", 0) \ + K(Int96, "int96", 0) \ + K(Int104, "int104", 0) \ + K(Int112, "int112", 0) \ + K(Int120, "int120", 0) \ + K(Int128, "int128", 0) \ + K(Int136, "int136", 0) \ + K(Int144, "int144", 0) \ + K(Int152, "int152", 0) \ + K(Int160, "int160", 0) \ + K(Int168, "int168", 0) \ + K(Int176, "int178", 0) \ + K(Int184, "int184", 0) \ + K(Int192, "int192", 0) \ + K(Int200, "int200", 0) \ + K(Int208, "int208", 0) \ + K(Int216, "int216", 0) \ + K(Int224, "int224", 0) \ + K(Int232, "int232", 0) \ + K(Int240, "int240", 0) \ + K(Int248, "int248", 0) \ + K(Int256, "int256", 0) \ + K(UInt, "uint", 0) \ + K(UInt8, "uint8", 0) \ + K(UInt16, "uint16", 0) \ + K(UInt24, "uint24", 0) \ + K(UInt32, "uint32", 0) \ + K(UInt40, "uint40", 0) \ + K(UInt48, "uint48", 0) \ + K(UInt56, "uint56", 0) \ + K(UInt64, "uint64", 0) \ + K(UInt72, "uint72", 0) \ + K(UInt80, "uint80", 0) \ + K(UInt88, "uint88", 0) \ + K(UInt96, "uint96", 0) \ + K(UInt104, "uint104", 0) \ + K(UInt112, "uint112", 0) \ + K(UInt120, "uint120", 0) \ + K(UInt128, "uint128", 0) \ + K(UInt136, "uint136", 0) \ + K(UInt144, "uint144", 0) \ + K(UInt152, "uint152", 0) \ + K(UInt160, "uint160", 0) \ + K(UInt168, "uint168", 0) \ + K(UInt176, "uint178", 0) \ + K(UInt184, "uint184", 0) \ + K(UInt192, "uint192", 0) \ + K(UInt200, "uint200", 0) \ + K(UInt208, "uint208", 0) \ + K(UInt216, "uint216", 0) \ + K(UInt224, "uint224", 0) \ + K(UInt232, "uint232", 0) \ + K(UInt240, "uint240", 0) \ + K(UInt248, "uint248", 0) \ + K(UInt256, "uint256", 0) \ + K(Hash, "hash", 0) \ + K(Hash8, "hash8", 0) \ + K(Hash16, "hash16", 0) \ + K(Hash24, "hash24", 0) \ + K(Hash32, "hash32", 0) \ + K(Hash40, "hash40", 0) \ + K(Hash48, "hash48", 0) \ + K(Hash56, "hash56", 0) \ + K(Hash64, "hash64", 0) \ + K(Hash72, "hash72", 0) \ + K(Hash80, "hash80", 0) \ + K(Hash88, "hash88", 0) \ + K(Hash96, "hash96", 0) \ + K(Hash104, "hash104", 0) \ + K(Hash112, "hash112", 0) \ + K(Hash120, "hash120", 0) \ + K(Hash128, "hash128", 0) \ + K(Hash136, "hash136", 0) \ + K(Hash144, "hash144", 0) \ + K(Hash152, "hash152", 0) \ + K(Hash160, "hash160", 0) \ + K(Hash168, "hash168", 0) \ + K(Hash176, "hash178", 0) \ + K(Hash184, "hash184", 0) \ + K(Hash192, "hash192", 0) \ + K(Hash200, "hash200", 0) \ + K(Hash208, "hash208", 0) \ + K(Hash216, "hash216", 0) \ + K(Hash224, "hash224", 0) \ + K(Hash232, "hash232", 0) \ + K(Hash240, "hash240", 0) \ + K(Hash248, "hash248", 0) \ + K(Hash256, "hash256", 0) \ + K(Address, "address", 0) \ + K(Bool, "bool", 0) \ + K(StringType, "string", 0) \ + K(String0, "string0", 0) \ + K(String1, "string1", 0) \ + K(String2, "string2", 0) \ + K(String3, "string3", 0) \ + K(String4, "string4", 0) \ + K(String5, "string5", 0) \ + K(String6, "string6", 0) \ + K(String7, "string7", 0) \ + K(String8, "string8", 0) \ + K(String9, "string9", 0) \ + K(String10, "string10", 0) \ + K(String11, "string11", 0) \ + K(String12, "string12", 0) \ + K(String13, "string13", 0) \ + K(String14, "string14", 0) \ + K(String15, "string15", 0) \ + K(String16, "string16", 0) \ + K(String17, "string17", 0) \ + K(String18, "string18", 0) \ + K(String19, "string19", 0) \ + K(String20, "string20", 0) \ + K(String21, "string21", 0) \ + K(String22, "string22", 0) \ + K(String23, "string23", 0) \ + K(String24, "string24", 0) \ + K(String25, "string25", 0) \ + K(String26, "string26", 0) \ + K(String27, "string27", 0) \ + K(String28, "string28", 0) \ + K(String29, "string29", 0) \ + K(String30, "string30", 0) \ + K(String31, "string31", 0) \ + K(String32, "string32", 0) \ + K(Text, "text", 0) \ + K(Real, "real", 0) \ + K(UReal, "ureal", 0) \ + T(TypesEnd, NULL, 0) /* used as type enum end marker */ \ \ /* Literals */ \ - K(NULL_LITERAL, "null", 0) \ - K(TRUE_LITERAL, "true", 0) \ - K(FALSE_LITERAL, "false", 0) \ - T(NUMBER, NULL, 0) \ - T(STRING_LITERAL, NULL, 0) \ - T(COMMENT_LITERAL, NULL, 0) \ + K(NullLiteral, "null", 0) \ + K(TrueLiteral, "true", 0) \ + K(FalseLiteral, "false", 0) \ + T(Number, NULL, 0) \ + T(StringLiteral, NULL, 0) \ + T(CommentLiteral, NULL, 0) \ \ /* Identifiers (not keywords or future reserved words). */ \ - T(IDENTIFIER, NULL, 0) \ + T(Identifier, NULL, 0) \ \ /* Illegal token - not able to scan. */ \ - T(ILLEGAL, "ILLEGAL", 0) \ + T(Illegal, "ILLEGAL", 0) \ \ /* Scanner-internal use only. */ \ - T(WHITESPACE, NULL, 0) + T(Whitespace, NULL, 0) class Token @@ -364,25 +360,25 @@ public: } // Predicates - static bool isElementaryTypeName(Value tok) { return INT <= tok && tok < TYPES_END; } - static bool isAssignmentOp(Value tok) { return ASSIGN <= tok && tok <= ASSIGN_MOD; } - static bool isBinaryOp(Value op) { return COMMA <= op && op <= MOD; } - static bool isCommutativeOp(Value op) { return op == BIT_OR || op == BIT_XOR || op == BIT_AND || - op == ADD || op == MUL || op == EQ || op == NE; } - static bool isArithmeticOp(Value op) { return ADD <= op && op <= MOD; } - static bool isCompareOp(Value op) { return EQ <= op && op <= IN; } + static bool isElementaryTypeName(Value tok) { return Int <= tok && tok < TypesEnd; } + static bool isAssignmentOp(Value tok) { return Assign <= tok && tok <= AssignMod; } + static bool isBinaryOp(Value op) { return Comma <= op && op <= Exp; } + static bool isCommutativeOp(Value op) { return op == BitOr || op == BitXor || op == BitAnd || + op == Add || op == Mul || op == Equal || op == NotEqual; } + static bool isArithmeticOp(Value op) { return Add <= op && op <= Exp; } + static bool isCompareOp(Value op) { return Equal <= op && op <= In; } static Value AssignmentToBinaryOp(Value op) { - solAssert(isAssignmentOp(op) && op != ASSIGN, ""); - return Token::Value(op + (BIT_OR - ASSIGN_BIT_OR)); + solAssert(isAssignmentOp(op) && op != Assign, ""); + return Token::Value(op + (BitOr - AssignBitOr)); } - static bool isBitOp(Value op) { return (BIT_OR <= op && op <= SHR) || op == BIT_NOT; } - static bool isUnaryOp(Value op) { return (NOT <= op && op <= DELETE) || op == ADD || op == SUB; } - static bool isCountOp(Value op) { return op == INC || op == DEC; } + static bool isBitOp(Value op) { return (BitOr <= op && op <= SHR) || op == BitNot; } + static bool isUnaryOp(Value op) { return (Not <= op && op <= Delete) || op == Add || op == Sub; } + static bool isCountOp(Value op) { return op == Inc || op == Dec; } static bool isShiftOp(Value op) { return (SHL <= op) && (op <= SHR); } - static bool isVisibilitySpecifier(Value op) { return op == PUBLIC || op == PRIVATE || op == PROTECTED; } + static bool isVisibilitySpecifier(Value op) { return op == Public || op == Private || op == Protected; } static bool isEtherSubdenomination(Value op) { return op == SubWei || op == SubSzabo || op == SubFinney || op == Token::SubEther; } // Returns a string corresponding to the JS token string @@ -26,6 +26,8 @@ #include <libsolidity/Types.h> #include <libsolidity/AST.h> +#include <limits> + using namespace std; namespace dev @@ -37,24 +39,24 @@ shared_ptr<Type const> Type::fromElementaryTypeName(Token::Value _typeToken) { solAssert(Token::isElementaryTypeName(_typeToken), "Elementary type name expected."); - if (Token::INT <= _typeToken && _typeToken <= Token::HASH256) + if (Token::Int <= _typeToken && _typeToken <= Token::Hash256) { - int offset = _typeToken - Token::INT; + int offset = _typeToken - Token::Int; int bytes = offset % 33; if (bytes == 0) bytes = 32; int modifier = offset / 33; return make_shared<IntegerType>(bytes * 8, - modifier == 0 ? IntegerType::Modifier::SIGNED : - modifier == 1 ? IntegerType::Modifier::UNSIGNED : - IntegerType::Modifier::HASH); + modifier == 0 ? IntegerType::Modifier::Signed : + modifier == 1 ? IntegerType::Modifier::Unsigned : + IntegerType::Modifier::Hash); } - else if (_typeToken == Token::ADDRESS) - return make_shared<IntegerType>(0, IntegerType::Modifier::ADDRESS); - else if (_typeToken == Token::BOOL) + else if (_typeToken == Token::Address) + return make_shared<IntegerType>(0, IntegerType::Modifier::Address); + else if (_typeToken == Token::Bool) return make_shared<BoolType>(); - else if (Token::STRING0 <= _typeToken && _typeToken <= Token::STRING32) - return make_shared<StaticStringType>(int(_typeToken) - int(Token::STRING0)); + else if (Token::String0 <= _typeToken && _typeToken <= Token::String32) + return make_shared<StaticStringType>(int(_typeToken) - int(Token::String0)); else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to convert elementary typename " + std::string(Token::toString(_typeToken)) + " to type.")); @@ -87,12 +89,12 @@ shared_ptr<Type const> Type::forLiteral(Literal const& _literal) { switch (_literal.getToken()) { - case Token::TRUE_LITERAL: - case Token::FALSE_LITERAL: + case Token::TrueLiteral: + case Token::FalseLiteral: return make_shared<BoolType>(); - case Token::NUMBER: + case Token::Number: return make_shared<IntegerConstantType>(_literal); - case Token::STRING_LITERAL: + case Token::StringLiteral: //@todo put larger strings into dynamic strings return StaticStringType::smallestTypeForLiteral(_literal.getValue()); default: @@ -140,31 +142,31 @@ bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const bool IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const { - if (_convertTo.getCategory() == Category::STRING) + if (_convertTo.getCategory() == Category::String) { StaticStringType const& convertTo = dynamic_cast<StaticStringType const&>(_convertTo); return isHash() && (m_bits == convertTo.getNumBytes() * 8); } - return _convertTo.getCategory() == getCategory() || _convertTo.getCategory() == Category::CONTRACT; + return _convertTo.getCategory() == getCategory() || _convertTo.getCategory() == Category::Contract; } TypePointer IntegerType::unaryOperatorResult(Token::Value _operator) const { // "delete" is ok for all integer types - if (_operator == Token::DELETE) + if (_operator == Token::Delete) return make_shared<VoidType>(); // no further unary operators for addresses else if (isAddress()) return TypePointer(); // "~" is ok for all other types - else if (_operator == Token::BIT_NOT) + else if (_operator == Token::BitNot) return shared_from_this(); // nothing else for hashes else if (isHash()) return TypePointer(); // for non-hash integers, we allow +, -, ++ and -- - else if (_operator == Token::ADD || _operator == Token::SUB || - _operator == Token::INC || _operator == Token::DEC) + else if (_operator == Token::Add || _operator == Token::Sub || + _operator == Token::Inc || _operator == Token::Dec) return shared_from_this(); else return TypePointer(); @@ -188,7 +190,7 @@ string IntegerType::toString() const TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const { - if (_other->getCategory() != Category::INTEGER_CONSTANT && _other->getCategory() != getCategory()) + if (_other->getCategory() != Category::IntegerConstant && _other->getCategory() != getCategory()) return TypePointer(); auto commonType = dynamic_pointer_cast<IntegerType const>(Type::commonType(shared_from_this(), _other)); @@ -210,11 +212,8 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe const MemberList IntegerType::AddressMemberList = MemberList({{"balance", make_shared<IntegerType >(256)}, - {"callstring32", make_shared<FunctionType>(strings{"string32"}, strings{}, - FunctionType::Location::BARE)}, - {"callstring32string32", make_shared<FunctionType>(strings{"string32", "string32"}, - strings{}, FunctionType::Location::BARE)}, - {"send", make_shared<FunctionType>(strings{"uint"}, strings{}, FunctionType::Location::SEND)}}); + {"call", make_shared<FunctionType>(strings(), strings(), FunctionType::Location::Bare, true)}, + {"send", make_shared<FunctionType>(strings{"uint"}, strings{}, FunctionType::Location::Send)}}); IntegerConstantType::IntegerConstantType(Literal const& _literal) { @@ -254,13 +253,13 @@ TypePointer IntegerConstantType::unaryOperatorResult(Token::Value _operator) con bigint value; switch (_operator) { - case Token::BIT_NOT: + case Token::BitNot: value = ~m_value; break; - case Token::ADD: + case Token::Add: value = m_value; break; - case Token::SUB: + case Token::Sub: value = -m_value; break; default: @@ -271,7 +270,7 @@ TypePointer IntegerConstantType::unaryOperatorResult(Token::Value _operator) con TypePointer IntegerConstantType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const { - if (_other->getCategory() == Category::INTEGER) + if (_other->getCategory() == Category::Integer) { shared_ptr<IntegerType const> integerType = getIntegerType(); if (!integerType) @@ -295,34 +294,42 @@ TypePointer IntegerConstantType::binaryOperatorResult(Token::Value _operator, Ty bigint value; switch (_operator) { - case Token::BIT_OR: + case Token::BitOr: value = m_value | other.m_value; break; - case Token::BIT_XOR: + case Token::BitXor: value = m_value ^ other.m_value; break; - case Token::BIT_AND: + case Token::BitAnd: value = m_value & other.m_value; break; - case Token::ADD: + case Token::Add: value = m_value + other.m_value; break; - case Token::SUB: + case Token::Sub: value = m_value - other.m_value; break; - case Token::MUL: + case Token::Mul: value = m_value * other.m_value; break; - case Token::DIV: + case Token::Div: if (other.m_value == 0) return TypePointer(); value = m_value / other.m_value; break; - case Token::MOD: + case Token::Mod: if (other.m_value == 0) return TypePointer(); value = m_value % other.m_value; break; + case Token::Exp: + if (other.m_value < 0) + return TypePointer(); + else if (other.m_value > std::numeric_limits<unsigned int>::max()) + return TypePointer(); + else + value = boost::multiprecision::pow(m_value, other.m_value.convert_to<unsigned int>()); + break; default: return TypePointer(); } @@ -374,8 +381,8 @@ shared_ptr<IntegerType const> IntegerConstantType::getIntegerType() const return shared_ptr<IntegerType const>(); else return make_shared<IntegerType>(max(bytesRequired(value), 1u) * 8, - negative ? IntegerType::Modifier::SIGNED - : IntegerType::Modifier::UNSIGNED); + negative ? IntegerType::Modifier::Signed + : IntegerType::Modifier::Unsigned); } shared_ptr<StaticStringType> StaticStringType::smallestTypeForLiteral(string const& _literal) @@ -401,13 +408,16 @@ bool StaticStringType::isImplicitlyConvertibleTo(Type const& _convertTo) const bool StaticStringType::isExplicitlyConvertibleTo(Type const& _convertTo) const { - if (_convertTo.getCategory() == Category::INTEGER) + if (_convertTo.getCategory() == getCategory()) + return true; + if (_convertTo.getCategory() == Category::Integer) { IntegerType const& convertTo = dynamic_cast<IntegerType const&>(_convertTo); if (convertTo.isHash() && (m_bytes * 8 == convertTo.getNumBits())) return true; } - return isImplicitlyConvertibleTo(_convertTo); + + return false; } bool StaticStringType::operator==(Type const& _other) const @@ -443,9 +453,9 @@ bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const u256 BoolType::literalValue(Literal const* _literal) const { solAssert(_literal, ""); - if (_literal->getToken() == Token::TRUE_LITERAL) + if (_literal->getToken() == Token::TrueLiteral) return u256(1); - else if (_literal->getToken() == Token::FALSE_LITERAL) + else if (_literal->getToken() == Token::FalseLiteral) return u256(0); else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Bool type constructed from non-boolean literal.")); @@ -453,16 +463,16 @@ u256 BoolType::literalValue(Literal const* _literal) const TypePointer BoolType::unaryOperatorResult(Token::Value _operator) const { - if (_operator == Token::DELETE) + if (_operator == Token::Delete) return make_shared<VoidType>(); - return (_operator == Token::NOT) ? shared_from_this() : TypePointer(); + return (_operator == Token::Not) ? shared_from_this() : TypePointer(); } TypePointer BoolType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const { if (getCategory() != _other->getCategory()) return TypePointer(); - if (Token::isCompareOp(_operator) || _operator == Token::AND || _operator == Token::OR) + if (Token::isCompareOp(_operator) || _operator == Token::And || _operator == Token::Or) return _other; else return TypePointer(); @@ -472,9 +482,9 @@ bool ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const { if (*this == _convertTo) return true; - if (_convertTo.getCategory() == Category::INTEGER) + if (_convertTo.getCategory() == Category::Integer) return dynamic_cast<IntegerType const&>(_convertTo).isAddress(); - if (_convertTo.getCategory() == Category::CONTRACT) + if (_convertTo.getCategory() == Category::Contract) { auto const& bases = getContractDefinition().getLinearizedBaseContracts(); if (m_super && bases.size() <= 1) @@ -487,13 +497,13 @@ bool ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const bool ContractType::isExplicitlyConvertibleTo(Type const& _convertTo) const { - return isImplicitlyConvertibleTo(_convertTo) || _convertTo.getCategory() == Category::INTEGER || - _convertTo.getCategory() == Category::CONTRACT; + return isImplicitlyConvertibleTo(_convertTo) || _convertTo.getCategory() == Category::Integer || + _convertTo.getCategory() == Category::Contract; } TypePointer ContractType::unaryOperatorResult(Token::Value _operator) const { - return _operator == Token::DELETE ? make_shared<VoidType>() : TypePointer(); + return _operator == Token::Delete ? make_shared<VoidType>() : TypePointer(); } bool ContractType::operator==(Type const& _other) const @@ -557,7 +567,7 @@ u256 ContractType::getFunctionIdentifier(string const& _functionName) const TypePointer StructType::unaryOperatorResult(Token::Value _operator) const { - return _operator == Token::DELETE ? make_shared<VoidType>() : TypePointer(); + return _operator == Token::Delete ? make_shared<VoidType>() : TypePointer(); } bool StructType::operator==(Type const& _other) const @@ -616,7 +626,7 @@ u256 StructType::getStorageOffsetOfMember(string const& _name) const } FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal): - m_location(_isInternal ? Location::INTERNAL : Location::EXTERNAL), + m_location(_isInternal ? Location::Internal : Location::External), m_isConstant(_function.isDeclaredConst()), m_declaration(&_function) { @@ -646,7 +656,7 @@ FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal } FunctionType::FunctionType(VariableDeclaration const& _varDecl): - m_location(Location::EXTERNAL), m_isConstant(true), m_declaration(&_varDecl) + m_location(Location::External), m_isConstant(true), m_declaration(&_varDecl) { TypePointers params; vector<string> paramNames; @@ -683,7 +693,7 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl): } FunctionType::FunctionType(const EventDefinition& _event): - m_location(Location::EVENT), m_declaration(&_event) + m_location(Location::Event), m_declaration(&_event) { TypePointers params; vector<string> paramNames; @@ -740,9 +750,9 @@ string FunctionType::toString() const unsigned FunctionType::getSizeOnStack() const { unsigned size = 0; - if (m_location == Location::EXTERNAL) + if (m_location == Location::External) size = 2; - else if (m_location == Location::INTERNAL || m_location == Location::BARE) + else if (m_location == Location::Internal || m_location == Location::Bare) size = 1; if (m_gasSet) size++; @@ -755,22 +765,22 @@ MemberList const& FunctionType::getMembers() const { switch (m_location) { - case Location::EXTERNAL: - case Location::CREATION: - case Location::ECRECOVER: + case Location::External: + case Location::Creation: + case Location::ECRecover: case Location::SHA256: case Location::RIPEMD160: - case Location::BARE: + case Location::Bare: if (!m_members) { map<string, TypePointer> members{ {"gas", make_shared<FunctionType>(parseElementaryTypeVector({"uint"}), TypePointers{copyAndSetGasOrValue(true, false)}, - Location::SET_GAS, m_gasSet, m_valueSet)}, + Location::SetGas, false, m_gasSet, m_valueSet)}, {"value", make_shared<FunctionType>(parseElementaryTypeVector({"uint"}), TypePointers{copyAndSetGasOrValue(false, true)}, - Location::SET_VALUE, m_gasSet, m_valueSet)}}; - if (m_location == Location::CREATION) + Location::SetValue, false, m_gasSet, m_valueSet)}}; + if (m_location == Location::Creation) members.erase("gas"); m_members.reset(new MemberList(members)); } @@ -808,6 +818,7 @@ TypePointers FunctionType::parseElementaryTypeVector(strings const& _types) TypePointer FunctionType::copyAndSetGasOrValue(bool _setGas, bool _setValue) const { return make_shared<FunctionType>(m_parameterTypes, m_returnParameterTypes, m_location, + m_arbitraryParameters, m_gasSet || _setGas, m_valueSet || _setValue); } @@ -865,7 +876,7 @@ MemberList const& TypeType::getMembers() const if (!m_members) { map<string, TypePointer> members; - if (m_actualType->getCategory() == Category::CONTRACT && m_currentContract != nullptr) + if (m_actualType->getCategory() == Category::Contract && m_currentContract != nullptr) { ContractDefinition const& contract = dynamic_cast<ContractType const&>(*m_actualType).getContractDefinition(); vector<ContractDefinition const*> currentBases = m_currentContract->getLinearizedBaseContracts(); @@ -919,21 +930,21 @@ MagicType::MagicType(MagicType::Kind _kind): { switch (m_kind) { - case Kind::BLOCK: - m_members = MemberList({{"coinbase", make_shared<IntegerType>(0, IntegerType::Modifier::ADDRESS)}, + case Kind::Block: + m_members = MemberList({{"coinbase", make_shared<IntegerType>(0, IntegerType::Modifier::Address)}, {"timestamp", make_shared<IntegerType>(256)}, - {"blockhash", make_shared<FunctionType>(strings{"uint"}, strings{"hash"}, FunctionType::Location::BLOCKHASH)}, + {"blockhash", make_shared<FunctionType>(strings{"uint"}, strings{"hash"}, FunctionType::Location::BlockHash)}, {"difficulty", make_shared<IntegerType>(256)}, {"number", make_shared<IntegerType>(256)}, {"gaslimit", make_shared<IntegerType>(256)}}); break; - case Kind::MSG: - m_members = MemberList({{"sender", make_shared<IntegerType>(0, IntegerType::Modifier::ADDRESS)}, + case Kind::Message: + m_members = MemberList({{"sender", make_shared<IntegerType>(0, IntegerType::Modifier::Address)}, {"gas", make_shared<IntegerType>(256)}, {"value", make_shared<IntegerType>(256)}}); break; - case Kind::TX: - m_members = MemberList({{"origin", make_shared<IntegerType>(0, IntegerType::Modifier::ADDRESS)}, + case Kind::Transaction: + m_members = MemberList({{"origin", make_shared<IntegerType>(0, IntegerType::Modifier::Address)}, {"gasprice", make_shared<IntegerType>(256)}}); break; default: @@ -953,11 +964,11 @@ string MagicType::toString() const { switch (m_kind) { - case Kind::BLOCK: + case Kind::Block: return "block"; - case Kind::MSG: + case Kind::Message: return "msg"; - case Kind::TX: + case Kind::Transaction: return "tx"; default: BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown kind of magic.")); @@ -76,7 +76,9 @@ class Type: private boost::noncopyable, public std::enable_shared_from_this<Type public: enum class Category { - INTEGER, INTEGER_CONSTANT, BOOL, REAL, STRING, CONTRACT, STRUCT, FUNCTION, MAPPING, VOID, TYPE, MODIFIER, MAGIC + Integer, IntegerConstant, Bool, Real, + String, Contract, Struct, Function, + Mapping, Void, TypeType, Modifier, Magic }; ///@{ @@ -158,11 +160,11 @@ class IntegerType: public Type public: enum class Modifier { - UNSIGNED, SIGNED, HASH, ADDRESS + Unsigned, Signed, Hash, Address }; - virtual Category getCategory() const override { return Category::INTEGER; } + virtual Category getCategory() const override { return Category::Integer; } - explicit IntegerType(int _bits, Modifier _modifier = Modifier::UNSIGNED); + explicit IntegerType(int _bits, Modifier _modifier = Modifier::Unsigned); virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; @@ -179,9 +181,9 @@ public: virtual std::string toString() const override; int getNumBits() const { return m_bits; } - bool isHash() const { return m_modifier == Modifier::HASH || m_modifier == Modifier::ADDRESS; } - bool isAddress() const { return m_modifier == Modifier::ADDRESS; } - bool isSigned() const { return m_modifier == Modifier::SIGNED; } + bool isHash() const { return m_modifier == Modifier::Hash || m_modifier == Modifier::Address; } + bool isAddress() const { return m_modifier == Modifier::Address; } + bool isSigned() const { return m_modifier == Modifier::Signed; } static const MemberList AddressMemberList; @@ -197,7 +199,7 @@ private: class IntegerConstantType: public Type { public: - virtual Category getCategory() const override { return Category::INTEGER_CONSTANT; } + virtual Category getCategory() const override { return Category::IntegerConstant; } explicit IntegerConstantType(Literal const& _literal); explicit IntegerConstantType(bigint _value): m_value(_value) {} @@ -230,7 +232,7 @@ private: class StaticStringType: public Type { public: - virtual Category getCategory() const override { return Category::STRING; } + virtual Category getCategory() const override { return Category::String; } /// @returns the smallest string type for the given literal or an empty pointer /// if no type fits. @@ -261,7 +263,7 @@ class BoolType: public Type { public: BoolType() {} - virtual Category getCategory() const { return Category::BOOL; } + virtual Category getCategory() const { return Category::Bool; } virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override; @@ -279,7 +281,7 @@ public: class ContractType: public Type { public: - virtual Category getCategory() const override { return Category::CONTRACT; } + virtual Category getCategory() const override { return Category::Contract; } explicit ContractType(ContractDefinition const& _contract, bool _super = false): m_contract(_contract), m_super(_super) {} /// Contracts can be implicitly converted to super classes and to addresses. @@ -321,7 +323,7 @@ private: class StructType: public Type { public: - virtual Category getCategory() const override { return Category::STRUCT; } + virtual Category getCategory() const override { return Category::Struct; } explicit StructType(StructDefinition const& _struct): m_struct(_struct) {} virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; virtual bool operator==(Type const& _other) const override; @@ -353,26 +355,27 @@ public: /// BARE: contract address (non-abi contract call) /// OTHERS: special virtual function, nothing on the stack /// @todo This documentation is outdated, and Location should rather be named "Type" - enum class Location { INTERNAL, EXTERNAL, CREATION, SEND, - SHA3, SUICIDE, - ECRECOVER, SHA256, RIPEMD160, - LOG0, LOG1, LOG2, LOG3, LOG4, EVENT, - SET_GAS, SET_VALUE, BLOCKHASH, - BARE }; - - virtual Category getCategory() const override { return Category::FUNCTION; } + enum class Location { Internal, External, Creation, Send, + SHA3, Suicide, + ECRecover, SHA256, RIPEMD160, + Log0, Log1, Log2, Log3, Log4, Event, + SetGas, SetValue, BlockHash, + Bare }; + + virtual Category getCategory() const override { return Category::Function; } explicit FunctionType(FunctionDefinition const& _function, bool _isInternal = true); explicit FunctionType(VariableDeclaration const& _varDecl); explicit FunctionType(EventDefinition const& _event); FunctionType(strings const& _parameterTypes, strings const& _returnParameterTypes, - Location _location = Location::INTERNAL): + Location _location = Location::Internal, bool _arbitraryParameters = false): FunctionType(parseElementaryTypeVector(_parameterTypes), parseElementaryTypeVector(_returnParameterTypes), - _location) {} + _location, _arbitraryParameters) {} FunctionType(TypePointers const& _parameterTypes, TypePointers const& _returnParameterTypes, - Location _location = Location::INTERNAL, - bool _gasSet = false, bool _valueSet = false): + Location _location = Location::Internal, + bool _arbitraryParameters = false, bool _gasSet = false, bool _valueSet = false): m_parameterTypes(_parameterTypes), m_returnParameterTypes(_returnParameterTypes), - m_location(_location), m_gasSet(_gasSet), m_valueSet(_valueSet) {} + m_location(_location), + m_arbitraryParameters(_arbitraryParameters), m_gasSet(_gasSet), m_valueSet(_valueSet) {} TypePointers const& getParameterTypes() const { return m_parameterTypes; } std::vector<std::string> const& getParameterNames() const { return m_parameterNames; } @@ -405,6 +408,9 @@ public: /// Can contain a nullptr in which case indicates absence of documentation ASTPointer<ASTString> getDocumentation() const; + /// true iff arguments are to be padded to multiples of 32 bytes for external calls + bool padArguments() const { return !(m_location == Location::SHA3 || m_location == Location::SHA256 || m_location == Location::RIPEMD160); } + bool takesArbitraryParameters() const { return m_arbitraryParameters; } bool gasSet() const { return m_gasSet; } bool valueSet() const { return m_valueSet; } @@ -420,6 +426,8 @@ private: std::vector<std::string> m_parameterNames; std::vector<std::string> m_returnParameterNames; Location const m_location; + /// true iff the function takes an arbitrary number of arguments of arbitrary types + bool const m_arbitraryParameters = false; bool const m_gasSet = false; ///< true iff the gas value to be used is on the stack bool const m_valueSet = false; ///< true iff the value to be sent is on the stack bool m_isConstant; @@ -433,7 +441,7 @@ private: class MappingType: public Type { public: - virtual Category getCategory() const override { return Category::MAPPING; } + virtual Category getCategory() const override { return Category::Mapping; } MappingType(TypePointer const& _keyType, TypePointer const& _valueType): m_keyType(_keyType), m_valueType(_valueType) {} @@ -456,7 +464,7 @@ private: class VoidType: public Type { public: - virtual Category getCategory() const override { return Category::VOID; } + virtual Category getCategory() const override { return Category::Void; } VoidType() {} virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); } @@ -474,7 +482,7 @@ public: class TypeType: public Type { public: - virtual Category getCategory() const override { return Category::TYPE; } + virtual Category getCategory() const override { return Category::TypeType; } explicit TypeType(TypePointer const& _actualType, ContractDefinition const* _currentContract = nullptr): m_actualType(_actualType), m_currentContract(_currentContract) {} TypePointer const& getActualType() const { return m_actualType; } @@ -503,7 +511,7 @@ private: class ModifierType: public Type { public: - virtual Category getCategory() const override { return Category::MODIFIER; } + virtual Category getCategory() const override { return Category::Modifier; } explicit ModifierType(ModifierDefinition const& _modifier); virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); } @@ -526,8 +534,8 @@ private: class MagicType: public Type { public: - enum class Kind { BLOCK, MSG, TX }; - virtual Category getCategory() const override { return Category::MAGIC; } + enum class Kind { Block, Message, Transaction }; + virtual Category getCategory() const override { return Category::Magic; } explicit MagicType(Kind _kind); |