mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge branch 'develop' into jsoncpp_path
This commit is contained in:
commit
7035ae638a
37
AST.cpp
37
AST.cpp
@ -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()
|
||||
|
24
AST.h
24
AST.h
@ -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,
|
||||
|
@ -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))},
|
||||
|
@ -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();
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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))})
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
236
Parser.cpp
236
Parser.cpp
@ -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();
|
||||
}
|
||||
|
134
Scanner.cpp
134
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
|
||||
|
474
Token.h
474
Token.h
@ -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
|
||||
|
163
Types.cpp
163
Types.cpp
@ -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."));
|
||||
|
68
Types.h
68
Types.h
@ -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 };
|
||||
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; }
|
||||
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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user