mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Magic variables.
This commit is contained in:
parent
c50cd646ce
commit
583a315d3d
17
AST.cpp
17
AST.cpp
@ -372,8 +372,6 @@ void VariableDefinition::checkTypeRequirements()
|
||||
m_variable->setType(m_value->getType());
|
||||
}
|
||||
}
|
||||
if (m_variable->getType() && !m_variable->getType()->canLiveOutsideStorage())
|
||||
BOOST_THROW_EXCEPTION(m_variable->createTypeError("Type is required to live outside storage."));
|
||||
}
|
||||
|
||||
void Assignment::checkTypeRequirements()
|
||||
@ -466,8 +464,6 @@ void FunctionCall::checkTypeRequirements()
|
||||
}
|
||||
else
|
||||
{
|
||||
m_expression->requireLValue();
|
||||
|
||||
//@todo would be nice to create a struct type from the arguments
|
||||
// and then ask if that is implicitly convertible to the struct represented by the
|
||||
// function parameters
|
||||
@ -495,25 +491,23 @@ bool FunctionCall::isTypeConversion() const
|
||||
void MemberAccess::checkTypeRequirements()
|
||||
{
|
||||
m_expression->checkTypeRequirements();
|
||||
m_expression->requireLValue();
|
||||
Type const& type = *m_expression->getType();
|
||||
m_type = type.getMemberType(*m_memberName);
|
||||
if (!m_type)
|
||||
BOOST_THROW_EXCEPTION(createTypeError("Member \"" + *m_memberName + "\" not found in " + type.toString()));
|
||||
m_isLvalue = true;
|
||||
m_isLvalue = (type.getCategory() == Type::Category::STRUCT && m_type->getCategory() != Type::Category::MAPPING);
|
||||
}
|
||||
|
||||
void IndexAccess::checkTypeRequirements()
|
||||
{
|
||||
m_base->checkTypeRequirements();
|
||||
m_base->requireLValue();
|
||||
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_isLvalue = true;
|
||||
m_isLvalue = m_type->getCategory() != Type::Category::MAPPING;
|
||||
}
|
||||
|
||||
void Identifier::checkTypeRequirements()
|
||||
@ -545,7 +539,6 @@ void Identifier::checkTypeRequirements()
|
||||
// Calling a function (e.g. function(12), otherContract.function(34)) does not do a type
|
||||
// conversion.
|
||||
m_type = make_shared<FunctionType>(*functionDef);
|
||||
m_isLvalue = true;
|
||||
return;
|
||||
}
|
||||
ContractDefinition* contractDef = dynamic_cast<ContractDefinition*>(m_referencedDeclaration);
|
||||
@ -554,6 +547,12 @@ void Identifier::checkTypeRequirements()
|
||||
m_type = make_shared<TypeType>(make_shared<ContractType>(*contractDef));
|
||||
return;
|
||||
}
|
||||
MagicVariableDeclaration* magicVariable = dynamic_cast<MagicVariableDeclaration*>(m_referencedDeclaration);
|
||||
if (magicVariable)
|
||||
{
|
||||
m_type = magicVariable->getType();
|
||||
return;
|
||||
}
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Declaration reference of unknown/forbidden type."));
|
||||
}
|
||||
|
||||
|
22
AST.h
22
AST.h
@ -230,6 +230,28 @@ private:
|
||||
std::shared_ptr<Type const> m_type; ///< derived type, initially empty
|
||||
};
|
||||
|
||||
/**
|
||||
* Pseudo AST node that is used as declaration for "this", "msg", "tx" and "block" when the
|
||||
* identifier is encountered. Will never have a valid location in the source code.
|
||||
*/
|
||||
class MagicVariableDeclaration: public Declaration
|
||||
{
|
||||
public:
|
||||
enum class VariableKind { THIS, MSG, TX, BLOCK };
|
||||
MagicVariableDeclaration(VariableKind _kind, ASTString const& _name,
|
||||
std::shared_ptr<Type const> const& _type):
|
||||
Declaration(Location(), std::make_shared<ASTString>(_name)), m_kind(_kind), m_type(_type) {}
|
||||
virtual void accept(ASTVisitor&) override { BOOST_THROW_EXCEPTION(InternalCompilerError()
|
||||
<< errinfo_comment("MagicVariableDeclaration used inside real AST.")); }
|
||||
|
||||
std::shared_ptr<Type const> const& getType() const { return m_type; }
|
||||
VariableKind getKind() const { return m_kind; }
|
||||
|
||||
private:
|
||||
VariableKind m_kind;
|
||||
std::shared_ptr<Type const> m_type;
|
||||
};
|
||||
|
||||
/// Types
|
||||
/// @{
|
||||
|
||||
|
@ -40,6 +40,7 @@ class StructDefinition;
|
||||
class ParameterList;
|
||||
class FunctionDefinition;
|
||||
class VariableDeclaration;
|
||||
class MagicVariableDeclaration;
|
||||
class TypeName;
|
||||
class ElementaryTypeName;
|
||||
class UserDefinedTypeName;
|
||||
|
15
Compiler.cpp
15
Compiler.cpp
@ -32,17 +32,13 @@ using namespace std;
|
||||
namespace dev {
|
||||
namespace solidity {
|
||||
|
||||
bytes Compiler::compile(ContractDefinition& _contract, bool _optimize)
|
||||
{
|
||||
Compiler compiler;
|
||||
compiler.compileContract(_contract);
|
||||
return compiler.m_context.getAssembledBytecode(_optimize);
|
||||
}
|
||||
|
||||
void Compiler::compileContract(ContractDefinition& _contract)
|
||||
void Compiler::compileContract(ContractDefinition& _contract, vector<MagicVariableDeclaration const*> const& _magicGlobals)
|
||||
{
|
||||
m_context = CompilerContext(); // clear it just in case
|
||||
|
||||
for (MagicVariableDeclaration const* variable: _magicGlobals)
|
||||
m_context.addMagicGlobal(*variable);
|
||||
|
||||
for (ASTPointer<FunctionDefinition> const& function: _contract.getDefinedFunctions())
|
||||
if (function->getName() != _contract.getName()) // don't add the constructor here
|
||||
m_context.addFunction(*function);
|
||||
@ -328,7 +324,8 @@ bool Compiler::visit(ExpressionStatement& _expressionStatement)
|
||||
{
|
||||
Expression& expression = _expressionStatement.getExpression();
|
||||
ExpressionCompiler::compileExpression(m_context, expression);
|
||||
if (expression.getType()->getCategory() != Type::Category::VOID)
|
||||
Type::Category category = expression.getType()->getCategory();
|
||||
if (category != Type::Category::VOID && category != Type::Category::MAGIC)
|
||||
m_context << eth::Instruction::POP;
|
||||
return false;
|
||||
}
|
||||
|
@ -32,13 +32,10 @@ class Compiler: private ASTVisitor
|
||||
public:
|
||||
Compiler(): m_returnTag(m_context.newTag()) {}
|
||||
|
||||
void compileContract(ContractDefinition& _contract);
|
||||
void compileContract(ContractDefinition& _contract, std::vector<MagicVariableDeclaration const*> const& _magicGlobals);
|
||||
bytes getAssembledBytecode(bool _optimize = false) { return m_context.getAssembledBytecode(_optimize); }
|
||||
void streamAssembly(std::ostream& _stream) const { m_context.streamAssembly(_stream); }
|
||||
|
||||
/// Compile the given contract and return the EVM bytecode.
|
||||
static bytes compile(ContractDefinition& _contract, bool _optimize);
|
||||
|
||||
private:
|
||||
/// Creates a new compiler context / assembly, packs the current code into the data part and
|
||||
/// adds the constructor code.
|
||||
|
@ -30,6 +30,11 @@ using namespace std;
|
||||
namespace dev {
|
||||
namespace solidity {
|
||||
|
||||
void CompilerContext::addMagicGlobal(MagicVariableDeclaration const& _declaration)
|
||||
{
|
||||
m_magicGlobals.insert(&_declaration);
|
||||
}
|
||||
|
||||
void CompilerContext::addStateVariable(VariableDeclaration const& _declaration)
|
||||
{
|
||||
m_stateVariables[&_declaration] = m_stateVariablesSize;
|
||||
|
@ -40,6 +40,7 @@ class CompilerContext
|
||||
public:
|
||||
CompilerContext(): m_stateVariablesSize(0) {}
|
||||
|
||||
void addMagicGlobal(MagicVariableDeclaration const& _declaration);
|
||||
void addStateVariable(VariableDeclaration const& _declaration);
|
||||
void startNewFunction() { m_localVariables.clear(); m_asm.setDeposit(0); }
|
||||
void initializeLocalVariables(unsigned _numVariables);
|
||||
@ -48,6 +49,7 @@ public:
|
||||
|
||||
void adjustStackOffset(int _adjustment) { m_asm.adjustDeposit(_adjustment); }
|
||||
|
||||
bool isMagicGlobal(Declaration const* _declaration) const { return m_magicGlobals.count(_declaration); }
|
||||
bool isFunctionDefinition(Declaration const* _declaration) const { return m_functionEntryLabels.count(_declaration); }
|
||||
bool isLocalVariable(Declaration const* _declaration) const;
|
||||
bool isStateVariable(Declaration const* _declaration) const { return m_stateVariables.count(_declaration); }
|
||||
@ -90,6 +92,8 @@ public:
|
||||
private:
|
||||
eth::Assembly m_asm;
|
||||
|
||||
/// Magic global variables like msg, tx or this, distinguished by type.
|
||||
std::set<Declaration const*> m_magicGlobals;
|
||||
/// Size of the state variables, offset of next variable to be added.
|
||||
u256 m_stateVariablesSize;
|
||||
/// Storage offsets of state variables
|
||||
|
@ -64,7 +64,7 @@ bytes const& CompilerStack::compile(bool _optimize)
|
||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
|
||||
m_bytecode.clear();
|
||||
m_compiler = make_shared<Compiler>();
|
||||
m_compiler->compileContract(*m_contractASTNode);
|
||||
m_compiler->compileContract(*m_contractASTNode, m_globalContext->getMagicVariables());
|
||||
return m_bytecode = m_compiler->getAssembledBytecode(_optimize);
|
||||
}
|
||||
|
||||
|
@ -162,7 +162,7 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall)
|
||||
{
|
||||
if (_functionCall.isTypeConversion())
|
||||
{
|
||||
//@todo we only have integers and bools for now which cannot be explicitly converted
|
||||
//@todo struct construction
|
||||
if (asserts(_functionCall.getArguments().size() == 1))
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError());
|
||||
Expression& firstArgument = *_functionCall.getArguments().front();
|
||||
@ -179,6 +179,8 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall)
|
||||
}
|
||||
else
|
||||
{
|
||||
//@todo: check for "external call" (to be stored in type)
|
||||
|
||||
// Calling convention: Caller pushes return address and arguments
|
||||
// Callee removes them and pushes return values
|
||||
FunctionDefinition const& function = dynamic_cast<FunctionType const&>(*_functionCall.getExpression().getType()).getFunction();
|
||||
@ -193,9 +195,6 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall)
|
||||
appendTypeConversion(*arguments[i]->getType(), *function.getParameters()[i]->getType());
|
||||
}
|
||||
_functionCall.getExpression().accept(*this);
|
||||
if (asserts(m_currentLValue.isInCode()))
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Code reference expected."));
|
||||
m_currentLValue.reset();
|
||||
|
||||
m_context.appendJump();
|
||||
m_context << returnLabel;
|
||||
@ -213,19 +212,36 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall)
|
||||
|
||||
void ExpressionCompiler::endVisit(MemberAccess& _memberAccess)
|
||||
{
|
||||
if (asserts(m_currentLValue.isInStorage()))
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Member access to a non-storage value."));
|
||||
StructType const& type = dynamic_cast<StructType const&>(*_memberAccess.getExpression().getType());
|
||||
m_context << type.getStorageOffsetOfMember(_memberAccess.getMemberName()) << eth::Instruction::ADD;
|
||||
m_currentLValue.retrieveValueIfLValueNotRequested(_memberAccess);
|
||||
switch (_memberAccess.getExpression().getType()->getCategory())
|
||||
{
|
||||
case Type::Category::INTEGER:
|
||||
if (asserts(_memberAccess.getMemberName() == "balance"))
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to integer."));
|
||||
m_context << eth::Instruction::BALANCE;
|
||||
break;
|
||||
case Type::Category::CONTRACT:
|
||||
// call function
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Contract variables not yet implemented."));
|
||||
break;
|
||||
case Type::Category::MAGIC:
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Magic variables not yet implemented."));
|
||||
break;
|
||||
case Type::Category::STRUCT:
|
||||
{
|
||||
StructType const& type = dynamic_cast<StructType const&>(*_memberAccess.getExpression().getType());
|
||||
m_context << type.getStorageOffsetOfMember(_memberAccess.getMemberName()) << eth::Instruction::ADD;
|
||||
m_currentLValue = LValue(m_context, LValue::STORAGE);
|
||||
m_currentLValue.retrieveValueIfLValueNotRequested(_memberAccess);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Member access to unknown type."));
|
||||
}
|
||||
}
|
||||
|
||||
bool ExpressionCompiler::visit(IndexAccess& _indexAccess)
|
||||
{
|
||||
m_currentLValue.reset();
|
||||
_indexAccess.getBaseExpression().accept(*this);
|
||||
if (asserts(m_currentLValue.isInStorage()))
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Index access to a non-storage value."));
|
||||
_indexAccess.getIndexExpression().accept(*this);
|
||||
appendTypeConversion(*_indexAccess.getIndexExpression().getType(),
|
||||
*dynamic_cast<MappingType const&>(*_indexAccess.getBaseExpression().getType()).getKeyType(),
|
||||
@ -242,8 +258,25 @@ bool ExpressionCompiler::visit(IndexAccess& _indexAccess)
|
||||
|
||||
void ExpressionCompiler::endVisit(Identifier& _identifier)
|
||||
{
|
||||
m_currentLValue.fromDeclaration(_identifier, *_identifier.getReferencedDeclaration());
|
||||
m_currentLValue.retrieveValueIfLValueNotRequested(_identifier);
|
||||
Declaration* declaration = _identifier.getReferencedDeclaration();
|
||||
if (MagicVariableDeclaration* magicVar = dynamic_cast<MagicVariableDeclaration*>(declaration))
|
||||
{
|
||||
if (magicVar->getKind() == MagicVariableDeclaration::VariableKind::THIS)
|
||||
m_context << eth::Instruction::ADDRESS;
|
||||
return;
|
||||
}
|
||||
if (FunctionDefinition* functionDef = dynamic_cast<FunctionDefinition*>(declaration))
|
||||
{
|
||||
m_context << m_context.getFunctionEntryLabel(*functionDef).pushTag();
|
||||
return;
|
||||
}
|
||||
if (VariableDeclaration* varDef = dynamic_cast<VariableDeclaration*>(declaration))
|
||||
{
|
||||
m_currentLValue.fromIdentifier(_identifier, *_identifier.getReferencedDeclaration());
|
||||
m_currentLValue.retrieveValueIfLValueNotRequested(_identifier);
|
||||
return;
|
||||
}
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Identifier type not expected in expression context."));
|
||||
}
|
||||
|
||||
void ExpressionCompiler::endVisit(Literal& _literal)
|
||||
@ -410,9 +443,6 @@ void ExpressionCompiler::LValue::retrieveValue(Expression const& _expression, bo
|
||||
{
|
||||
switch (m_type)
|
||||
{
|
||||
case CODE:
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Tried to retrieve value of a function."));
|
||||
break;
|
||||
case STACK:
|
||||
{
|
||||
unsigned stackPos = m_context->baseToCurrentStackOffset(unsigned(m_baseStackOffset));
|
||||
@ -423,11 +453,15 @@ void ExpressionCompiler::LValue::retrieveValue(Expression const& _expression, bo
|
||||
break;
|
||||
}
|
||||
case STORAGE:
|
||||
if (!_expression.getType()->isValueType())
|
||||
break; // no distinction between value and reference for non-value types
|
||||
if (!_remove)
|
||||
*m_context << eth::Instruction::DUP1;
|
||||
*m_context << eth::Instruction::SLOAD;
|
||||
break;
|
||||
case MEMORY:
|
||||
if (!_expression.getType()->isValueType())
|
||||
break; // no distinction between value and reference for non-value types
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_expression.getLocation())
|
||||
<< errinfo_comment("Location type not yet implemented."));
|
||||
break;
|
||||
@ -455,15 +489,15 @@ void ExpressionCompiler::LValue::storeValue(Expression const& _expression, bool
|
||||
break;
|
||||
}
|
||||
case LValue::STORAGE:
|
||||
if (!_expression.getType()->isValueType())
|
||||
break; // no distinction between value and reference for non-value types
|
||||
if (!_move)
|
||||
*m_context << eth::Instruction::DUP2 << eth::Instruction::SWAP1;
|
||||
*m_context << eth::Instruction::SSTORE;
|
||||
break;
|
||||
case LValue::CODE:
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_expression.getLocation())
|
||||
<< errinfo_comment("Location type does not support assignment."));
|
||||
break;
|
||||
case LValue::MEMORY:
|
||||
if (!_expression.getType()->isValueType())
|
||||
break; // no distinction between value and reference for non-value types
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_expression.getLocation())
|
||||
<< errinfo_comment("Location type not yet implemented."));
|
||||
break;
|
||||
@ -483,7 +517,7 @@ void ExpressionCompiler::LValue::retrieveValueIfLValueNotRequested(Expression co
|
||||
}
|
||||
}
|
||||
|
||||
void ExpressionCompiler::LValue::fromDeclaration(Expression const& _expression, Declaration const& _declaration)
|
||||
void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, Declaration const& _declaration)
|
||||
{
|
||||
if (m_context->isLocalVariable(&_declaration))
|
||||
{
|
||||
@ -495,13 +529,8 @@ void ExpressionCompiler::LValue::fromDeclaration(Expression const& _expression,
|
||||
m_type = STORAGE;
|
||||
*m_context << m_context->getStorageLocationOfVariable(_declaration);
|
||||
}
|
||||
else if (m_context->isFunctionDefinition(&_declaration))
|
||||
{
|
||||
m_type = CODE;
|
||||
*m_context << m_context->getFunctionEntryLabel(dynamic_cast<FunctionDefinition const&>(_declaration)).pushTag();
|
||||
}
|
||||
else
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_expression.getLocation())
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_identifier.getLocation())
|
||||
<< errinfo_comment("Identifier type not supported or identifier not found."));
|
||||
}
|
||||
|
||||
|
@ -83,31 +83,30 @@ private:
|
||||
|
||||
/**
|
||||
* Helper class to store and retrieve lvalues to and from various locations.
|
||||
* All types except STACK store a reference in a slot on the stack, STACK just stores the
|
||||
* base stack offset of the variable in @a m_baseStackOffset.
|
||||
* All types except STACK store a reference in a slot on the stack, STACK just
|
||||
* stores the base stack offset of the variable in @a m_baseStackOffset.
|
||||
*/
|
||||
class LValue
|
||||
{
|
||||
public:
|
||||
enum LValueType { NONE, CODE, STACK, MEMORY, STORAGE };
|
||||
enum LValueType { NONE, STACK, MEMORY, STORAGE };
|
||||
|
||||
explicit LValue(CompilerContext& _compilerContext): m_context(&_compilerContext) { reset(); }
|
||||
LValue(CompilerContext& _compilerContext, LValueType _type, unsigned _baseStackOffset = 0):
|
||||
m_context(&_compilerContext), m_type(_type), m_baseStackOffset(_baseStackOffset) {}
|
||||
|
||||
/// Set type according to the declaration and retrieve the reference.
|
||||
/// @a _expression is the current expression, used for error reporting.
|
||||
void fromDeclaration(Expression const& _expression, Declaration const& _declaration);
|
||||
/// @a _expression is the current expression
|
||||
void fromIdentifier(Identifier const& _identifier, Declaration const& _declaration);
|
||||
void reset() { m_type = NONE; m_baseStackOffset = 0; }
|
||||
|
||||
bool isValid() const { return m_type != NONE; }
|
||||
bool isInCode() const { return m_type == CODE; }
|
||||
bool isInOnStack() const { return m_type == STACK; }
|
||||
bool isInMemory() const { return m_type == MEMORY; }
|
||||
bool isInStorage() const { return m_type == STORAGE; }
|
||||
|
||||
/// @returns true if this lvalue reference type occupies a slot on the stack.
|
||||
bool storesReferenceOnStack() const { return m_type == STORAGE || m_type == MEMORY || m_type == CODE; }
|
||||
bool storesReferenceOnStack() const { return m_type == STORAGE || m_type == 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).
|
||||
|
@ -45,25 +45,37 @@ GlobalContext::GlobalContext()
|
||||
|
||||
void GlobalContext::setCurrentContract(ContractDefinition const& _contract)
|
||||
{
|
||||
m_this = createVariable("this", make_shared<ContractType>(_contract));
|
||||
m_currentContract = &_contract;
|
||||
}
|
||||
|
||||
vector<Declaration*> GlobalContext::getDeclarations() const
|
||||
{
|
||||
vector<Declaration*> declarations;
|
||||
declarations.reserve(m_objects.size() + 1);
|
||||
for (ASTPointer<Declaration> const& declaration: m_objects)
|
||||
declarations.push_back(declaration.get());
|
||||
declarations.push_back(m_this.get());
|
||||
declarations.reserve(m_magicVariables.size() + 1);
|
||||
for (ASTPointer<Declaration> const& variable: m_magicVariables)
|
||||
declarations.push_back(variable.get());
|
||||
declarations.push_back(getCurrentThis());
|
||||
return declarations;
|
||||
}
|
||||
|
||||
ASTPointer<VariableDeclaration> GlobalContext::createVariable(const string& _name, shared_ptr<const Type> const& _type)
|
||||
MagicVariableDeclaration*GlobalContext::getCurrentThis() const
|
||||
{
|
||||
ASTPointer<VariableDeclaration> variable = make_shared<VariableDeclaration>(Location(), ASTPointer<TypeName>(),
|
||||
make_shared<ASTString>(_name));
|
||||
variable->setType(_type);
|
||||
return variable;
|
||||
if (!m_thisPointer[m_currentContract])
|
||||
m_thisPointer[m_currentContract] = make_shared<MagicVariableDeclaration>(
|
||||
MagicVariableDeclaration::VariableKind::THIS,
|
||||
"this", make_shared<ContractType>(*m_currentContract));
|
||||
return m_thisPointer[m_currentContract].get();
|
||||
|
||||
}
|
||||
|
||||
vector<MagicVariableDeclaration const*> GlobalContext::getMagicVariables() const
|
||||
{
|
||||
vector<MagicVariableDeclaration const*> declarations;
|
||||
declarations.reserve(m_magicVariables.size() + 1);
|
||||
for (ASTPointer<MagicVariableDeclaration const> const& variable: m_magicVariables)
|
||||
declarations.push_back(variable.get());
|
||||
declarations.push_back(getCurrentThis());
|
||||
return declarations;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <libsolidity/ASTForward.h>
|
||||
@ -47,14 +48,14 @@ public:
|
||||
GlobalContext();
|
||||
void setCurrentContract(ContractDefinition const& _contract);
|
||||
|
||||
std::vector<MagicVariableDeclaration const*> getMagicVariables() const;
|
||||
std::vector<Declaration*> getDeclarations() const;
|
||||
|
||||
private:
|
||||
/// Creates a virtual variable declaration with the given name and type.
|
||||
static ASTPointer<VariableDeclaration> createVariable(std::string const& _name, std::shared_ptr<Type const> const& _type);
|
||||
|
||||
std::vector<ASTPointer<Declaration>> m_objects;
|
||||
ASTPointer<Declaration> m_this;
|
||||
MagicVariableDeclaration* getCurrentThis() const;
|
||||
std::vector<std::shared_ptr<MagicVariableDeclaration>> m_magicVariables;
|
||||
ContractDefinition const* m_currentContract;
|
||||
std::map<ContractDefinition const*, std::shared_ptr<MagicVariableDeclaration>> mutable m_thisPointer;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -189,6 +189,8 @@ u256 IntegerType::literalValue(Literal const& _literal) const
|
||||
return u256(value);
|
||||
}
|
||||
|
||||
const MemberList IntegerType::AddressMemberList = MemberList({{"balance", std::make_shared<IntegerType const>(256)}});
|
||||
|
||||
bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const
|
||||
{
|
||||
// conversion to integer is fine, but not to address
|
||||
|
10
Types.h
10
Types.h
@ -73,7 +73,7 @@ class Type: private boost::noncopyable
|
||||
public:
|
||||
enum class Category
|
||||
{
|
||||
INTEGER, BOOL, REAL, STRING, CONTRACT, STRUCT, FUNCTION, MAPPING, VOID, TYPE
|
||||
INTEGER, BOOL, REAL, STRING, CONTRACT, STRUCT, FUNCTION, MAPPING, VOID, TYPE, MAGIC
|
||||
};
|
||||
|
||||
///@{
|
||||
@ -110,6 +110,9 @@ public:
|
||||
virtual bool canBeStored() const { return true; }
|
||||
/// Returns false if the type cannot live outside the storage, i.e. if it includes some mapping.
|
||||
virtual bool canLiveOutsideStorage() const { return true; }
|
||||
/// Returns true if the type can be stored as a value (as opposed to a reference) on the stack,
|
||||
/// i.e. it behaves differently in lvalue context and in value context.
|
||||
virtual bool isValueType() const { return false; }
|
||||
|
||||
/// Returns the list of all members of this type. Default implementation: no members.
|
||||
virtual MemberList const& getMembers() const { return EmptyMemberList; }
|
||||
@ -154,6 +157,9 @@ public:
|
||||
virtual bool operator==(Type const& _other) const override;
|
||||
|
||||
virtual unsigned getCalldataEncodedSize() const override { return m_bits / 8; }
|
||||
virtual bool isValueType() const override { return true; }
|
||||
|
||||
virtual MemberList const& getMembers() const { return isAddress() ? AddressMemberList : EmptyMemberList; }
|
||||
|
||||
virtual std::string toString() const override;
|
||||
virtual u256 literalValue(Literal const& _literal) const override;
|
||||
@ -166,6 +172,7 @@ public:
|
||||
private:
|
||||
int m_bits;
|
||||
Modifier m_modifier;
|
||||
static const MemberList AddressMemberList;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -186,6 +193,7 @@ public:
|
||||
}
|
||||
|
||||
virtual unsigned getCalldataEncodedSize() const { return 1; }
|
||||
virtual bool isValueType() const override { return true; }
|
||||
|
||||
virtual std::string toString() const override { return "bool"; }
|
||||
virtual u256 literalValue(Literal const& _literal) const override;
|
||||
|
Loading…
Reference in New Issue
Block a user