Type system, not yet complete.

This commit is contained in:
Christian 2014-10-13 18:22:15 +02:00
parent bdac5c7b4b
commit 89b794f1dc
13 changed files with 817 additions and 124 deletions

244
AST.cpp
View File

@ -20,6 +20,8 @@
* Solidity abstract syntax tree.
*/
#include <algorithm>
#include <libsolidity/AST.h>
#include <libsolidity/ASTVisitor.h>
@ -66,8 +68,8 @@ void FunctionDefinition::accept(ASTVisitor& _visitor)
void VariableDeclaration::accept(ASTVisitor& _visitor)
{
if (_visitor.visit(*this)) {
if (m_type)
m_type->accept(_visitor);
if (m_typeName)
m_typeName->accept(_visitor);
}
_visitor.endVisit(*this);
}
@ -170,12 +172,6 @@ void VariableDefinition::accept(ASTVisitor& _visitor)
_visitor.endVisit(*this);
}
void Expression::accept(ASTVisitor& _visitor)
{
_visitor.visit(*this);
_visitor.endVisit(*this);
}
void Assignment::accept(ASTVisitor& _visitor)
{
if (_visitor.visit(*this)) {
@ -228,12 +224,6 @@ void IndexAccess::accept(ASTVisitor& _visitor)
_visitor.endVisit(*this);
}
void PrimaryExpression::accept(ASTVisitor& _visitor)
{
_visitor.visit(*this);
_visitor.endVisit(*this);
}
void Identifier::accept(ASTVisitor& _visitor)
{
_visitor.visit(*this);
@ -252,4 +242,230 @@ void Literal::accept(ASTVisitor& _visitor)
_visitor.endVisit(*this);
}
void Statement::expectType(Expression& _expression, const Type& _expectedType)
{
if (!_expression.checkTypeRequirements()->isImplicitlyConvertibleTo(_expectedType))
throw std::exception(); // @todo
}
ptr<Type> Block::checkTypeRequirements()
{
for (ptr<Statement> const& statement : m_statements)
statement->checkTypeRequirements();
return ptr<Type>();
}
ptr<Type> IfStatement::checkTypeRequirements()
{
expectType(*m_condition, BoolType());
m_trueBody->checkTypeRequirements();
if (m_falseBody) m_falseBody->checkTypeRequirements();
return ptr<Type>();
}
ptr<Type> WhileStatement::checkTypeRequirements()
{
expectType(*m_condition, BoolType());
m_body->checkTypeRequirements();
return ptr<Type>();
}
ptr<Type> Continue::checkTypeRequirements()
{
return ptr<Type>();
}
ptr<Type> Break::checkTypeRequirements()
{
return ptr<Type>();
}
ptr<Type> Return::checkTypeRequirements()
{
BOOST_ASSERT(m_returnParameters != nullptr);
if (m_returnParameters->getParameters().size() != 1)
throw std::exception(); // @todo
// this could later be changed such that the paramaters type is an anonymous struct type,
// but for now, we only allow one return parameter
expectType(*m_expression, *m_returnParameters->getParameters().front()->getType());
return ptr<Type>();
}
ptr<Type> VariableDefinition::checkTypeRequirements()
{
// Variables can be declared without type (with "var"), in which case the first assignment
// setsthe type.
// Note that assignments before the first declaration are legal because of the special scoping
// rules inherited from JavaScript.
if (m_value) {
if (m_variable->getType()) {
expectType(*m_value, *m_variable->getType());
} else {
// no type declared and no previous assignment, infer the type
m_variable->setType(m_value->checkTypeRequirements());
}
}
return ptr<Type>();
}
ptr<Type> Assignment::checkTypeRequirements()
{
//@todo lefthandside actually has to be assignable
// add a feature to the type system to check that
expectType(*m_rightHandSide, *m_leftHandSide->checkTypeRequirements());
m_type = m_leftHandSide->getType();
if (m_assigmentOperator != Token::ASSIGN) {
// complex assignment
if (!m_type->acceptsBinaryOperator(Token::AssignmentToBinaryOp(m_assigmentOperator)))
throw std::exception();
}
return m_type;
}
ptr<Type> UnaryOperation::checkTypeRequirements()
{
// INC, DEC, NOT, BIT_NOT, DELETE
m_type = m_subExpression->checkTypeRequirements();
if (m_type->acceptsUnaryOperator(m_operator))
throw std::exception();
return m_type;
}
ptr<Type> BinaryOperation::checkTypeRequirements()
{
m_right->checkTypeRequirements();
m_left->checkTypeRequirements();
if (m_right->getType()->isImplicitlyConvertibleTo(*m_left->getType()))
m_commonType = m_left->getType();
else if (m_left->getType()->isImplicitlyConvertibleTo(*m_right->getType()))
m_commonType = m_right->getType();
else
throw std::exception();
if (Token::IsCompareOp(m_operator)) {
m_type = std::make_shared<BoolType>();
} else {
BOOST_ASSERT(Token::IsBinaryOp(m_operator));
m_type = m_commonType;
if (!m_commonType->acceptsBinaryOperator(Token::AssignmentToBinaryOp(m_operator)))
throw std::exception();
}
return m_type;
}
ptr<Type> FunctionCall::checkTypeRequirements()
{
m_expression->checkTypeRequirements();
for (ptr<Expression> const& argument : m_arguments)
argument->checkTypeRequirements();
ptr<Type> expressionType = m_expression->getType();
Type::Category const category = expressionType->getCategory();
if (category == Type::Category::TYPE) {
TypeType* type = dynamic_cast<TypeType*>(expressionType.get());
BOOST_ASSERT(type != nullptr);
//@todo for structs, we have to check the number of arguments to be equal to the
// number of non-mapping members
if (m_arguments.size() != 1)
throw std::exception();
if (!m_arguments.front()->getType()->isExplicitlyConvertibleTo(*type->getActualType()))
throw std::exception();
m_type = type->getActualType();
} else if (category == Type::Category::FUNCTION) {
//@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
FunctionType* function = dynamic_cast<FunctionType*>(expressionType.get());
BOOST_ASSERT(function != nullptr);
FunctionDefinition const& fun = function->getFunction();
vecptr<VariableDeclaration> const& parameters = fun.getParameters();
if (parameters.size() != m_arguments.size())
throw std::exception();
for (size_t i = 0; i < m_arguments.size(); ++i) {
if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameters[i]->getType()))
throw std::exception();
}
// @todo actually the return type should be an anonymous struct,
// but we change it to the type of the first return value until we have structs
if (fun.getReturnParameterList()->getParameters().empty())
m_type = std::make_shared<VoidType>();
else
m_type = fun.getReturnParameterList()->getParameters().front()->getType();
} else {
throw std::exception(); // type does not support invocation
}
return m_type;
}
ptr<Type> MemberAccess::checkTypeRequirements()
{
BOOST_ASSERT(false); // not yet implemented
// m_type = ;
return m_type;
}
ptr<Type> IndexAccess::checkTypeRequirements()
{
BOOST_ASSERT(false); // not yet implemented
// m_type = ;
return m_type;
}
ptr<Type> Identifier::checkTypeRequirements()
{
BOOST_ASSERT(m_referencedDeclaration != nullptr);
//@todo these dynamic casts here are not really nice...
// is i useful to have an AST visitor here?
// or can this already be done in NameAndTypeResolver?
// the only problem we get there is that in
// var x;
// x = 2;
// var y = x;
// the type of x is not yet determined.
VariableDeclaration* variable = dynamic_cast<VariableDeclaration*>(m_referencedDeclaration);
if (variable != nullptr) {
if (variable->getType().get() == nullptr)
throw std::exception(); // variable used before type could be determined
m_type = variable->getType();
return m_type;
}
//@todo can we unify these with TypeName::toType()?
StructDefinition* structDef = dynamic_cast<StructDefinition*>(m_referencedDeclaration);
if (structDef != nullptr) {
// note that we do not have a struct type here
m_type = std::make_shared<TypeType>(std::make_shared<StructType>(*structDef));
return m_type;
}
FunctionDefinition* functionDef = dynamic_cast<FunctionDefinition*>(m_referencedDeclaration);
if (functionDef != nullptr) {
// a function reference is not a TypeType, because calling a TypeType converts to the type.
// Calling a function (e.g. function(12), otherContract.function(34)) does not do a type
// conversion.
m_type = std::make_shared<FunctionType>(*functionDef);
return m_type;
}
ContractDefinition* contractDef = dynamic_cast<ContractDefinition*>(m_referencedDeclaration);
if (contractDef != nullptr) {
m_type = std::make_shared<TypeType>(std::make_shared<ContractType>(*contractDef));
return m_type;
}
throw std::exception(); // declaration reference of unknown/forbidden type
return m_type;
}
ptr<Type> ElementaryTypeNameExpression::checkTypeRequirements()
{
m_type = std::make_shared<TypeType>(Type::fromElementaryTypeName(m_typeToken));
return m_type;
}
ptr<Type> Literal::checkTypeRequirements()
{
m_type = Type::forLiteral(*this);
return m_type;
}
} }

123
AST.h
View File

@ -22,6 +22,8 @@
#pragma once
#include <boost/noncopyable.hpp>
#include <string>
#include <vector>
#include <memory>
@ -29,13 +31,14 @@
#include <libsolidity/ASTForward.h>
#include <libsolidity/BaseTypes.h>
#include <libsolidity/Token.h>
#include <libsolidity/Types.h>
namespace dev {
namespace solidity {
class ASTVisitor;
class ASTNode
class ASTNode : private boost::noncopyable
{
public:
explicit ASTNode(Location const& _location)
@ -55,7 +58,18 @@ private:
Location m_location;
};
class ContractDefinition : public ASTNode
class Declaration : public ASTNode
{
public:
Declaration(Location const& _location, ptr<ASTString> const& _name)
: ASTNode(_location), m_name(_name) {}
const ASTString& getName() const { return *m_name; }
private:
ptr<ASTString> m_name;
};
class ContractDefinition : public Declaration
{
public:
ContractDefinition(Location const& _location,
@ -63,7 +77,7 @@ public:
vecptr<StructDefinition> const& _definedStructs,
vecptr<VariableDeclaration> const& _stateVariables,
vecptr<FunctionDefinition> const& _definedFunctions)
: ASTNode(_location), m_name(_name),
: Declaration(_location, _name),
m_definedStructs(_definedStructs),
m_stateVariables(_stateVariables),
m_definedFunctions(_definedFunctions)
@ -71,30 +85,26 @@ public:
virtual void accept(ASTVisitor& _visitor) override;
const ASTString& getName() const { return *m_name; }
vecptr<StructDefinition> const& getDefinedStructs() { return m_definedStructs; }
vecptr<VariableDeclaration> const& getStateVariables() { return m_stateVariables; }
vecptr<FunctionDefinition> const& getDefinedFunctions() { return m_definedFunctions; }
private:
ptr<ASTString> m_name;
vecptr<StructDefinition> m_definedStructs;
vecptr<VariableDeclaration> m_stateVariables;
vecptr<FunctionDefinition> m_definedFunctions;
};
class StructDefinition : public ASTNode
class StructDefinition : public Declaration
{
public:
StructDefinition(Location const& _location,
ptr<ASTString> const& _name,
vecptr<VariableDeclaration> const& _members)
: ASTNode(_location), m_name(_name), m_members(_members)
: Declaration(_location, _name), m_members(_members)
{}
virtual void accept(ASTVisitor& _visitor) override;
const ASTString& getName() const { return *m_name; }
private:
ptr<ASTString> m_name;
vecptr<VariableDeclaration> m_members;
};
@ -114,7 +124,7 @@ private:
vecptr<VariableDeclaration> m_parameters;
};
class FunctionDefinition : public ASTNode
class FunctionDefinition : public Declaration
{
public:
FunctionDefinition(Location const& _location, ptr<ASTString> const& _name, bool _isPublic,
@ -122,43 +132,47 @@ public:
bool _isDeclaredConst,
ptr<ParameterList> const& _returnParameters,
ptr<Block> const& _body)
: ASTNode(_location), m_name(_name), m_isPublic(_isPublic), m_parameters(_parameters),
: Declaration(_location, _name), m_isPublic(_isPublic), m_parameters(_parameters),
m_isDeclaredConst(_isDeclaredConst), m_returnParameters(_returnParameters),
m_body(_body)
{}
virtual void accept(ASTVisitor& _visitor) override;
const ASTString& getName() const { return *m_name; }
bool isPublic() const { return m_isPublic; }
bool isDeclaredConst() const { return m_isDeclaredConst; }
vecptr<VariableDeclaration> const& getParameters() { return m_parameters->getParameters(); }
bool hasReturnParameters() const { return m_returnParameters.get() != nullptr; }
vecptr<VariableDeclaration> const& getReturnParameters() { return m_returnParameters->getParameters(); }
vecptr<VariableDeclaration> const& getParameters() const { return m_parameters->getParameters(); }
ParameterList& getParameterList() { return *m_parameters; }
ptr<ParameterList> const& getReturnParameterList() const { return m_returnParameters; }
Block& getBody() { return *m_body; }
private:
ptr<ASTString> m_name;
bool m_isPublic;
ptr<ParameterList> m_parameters;
bool m_isDeclaredConst;
ptr<ParameterList> m_returnParameters; //< either "null"pointer or pointer to non-empty parameter list
ptr<ParameterList> m_returnParameters;
ptr<Block> m_body;
};
class VariableDeclaration : public ASTNode
class VariableDeclaration : public Declaration
{
public:
VariableDeclaration(Location const& _location,
ptr<TypeName> const& _type,
ptr<ASTString> const& _name)
: ASTNode(_location), m_type(_type), m_name(_name)
: Declaration(_location, _name), m_typeName(_type)
{}
virtual void accept(ASTVisitor& _visitor) override;
TypeName* getTypeName() const { return m_type.get(); }
const ASTString& getName() const { return *m_name; }
bool isTypeGivenExplicitly() const { return m_typeName.get() != nullptr; }
TypeName* getTypeName() const { return m_typeName.get(); }
//! Returns the declared or inferred type. Can be an empty pointer if no type was explicitly
//! declared and there is no assignment to the variable that fixes the type.
ptr<Type> const& getType() const { return m_type; }
void setType(ptr<Type> const& _type) { m_type = _type; }
private:
ptr<TypeName> m_type; ///< can be empty ("var")
ptr<ASTString> m_name;
ptr<TypeName> m_typeName; ///< can be empty ("var")
ptr<Type> m_type;
};
/// types
@ -169,6 +183,8 @@ class TypeName : public ASTNode
public:
explicit TypeName(Location const& _location) : ASTNode(_location) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual ptr<Type> toType() = 0;
};
/// any pre-defined type that is not a mapping
@ -179,6 +195,7 @@ public:
: TypeName(_location), m_type(_type)
{}
virtual void accept(ASTVisitor& _visitor) override;
virtual ptr<Type> toType() override { return Type::fromElementaryTypeName(m_type); }
Token::Value getType() const { return m_type; }
private:
@ -192,10 +209,15 @@ public:
: TypeName(_location), m_name(_name)
{}
virtual void accept(ASTVisitor& _visitor) override;
virtual ptr<Type> toType() override { return Type::fromUserDefinedTypeName(*this); }
const ASTString& getName() const { return *m_name; }
void setReferencedStruct(StructDefinition& _referencedStruct) { m_referencedStruct = &_referencedStruct; }
StructDefinition const* getReferencedStruct() const { return m_referencedStruct; }
private:
ptr<ASTString> m_name;
StructDefinition* m_referencedStruct;
};
class Mapping : public TypeName
@ -206,6 +228,7 @@ public:
: TypeName(_location), m_keyType(_keyType), m_valueType(_valueType)
{}
virtual void accept(ASTVisitor& _visitor) override;
virtual ptr<Type> toType() override { return Type::fromMapping(*this); }
private:
ptr<ElementaryTypeName> m_keyType;
ptr<TypeName> m_valueType;
@ -221,6 +244,15 @@ class Statement : public ASTNode
public:
explicit Statement(Location const& _location) : ASTNode(_location) {}
virtual void accept(ASTVisitor& _visitor) override;
//! Check all type requirements, throws exception if some requirement is not met.
//! For expressions, this also returns the inferred type of the expression. For other
//! statements, returns the empty pointer.
virtual ptr<Type> checkTypeRequirements() = 0;
protected:
//! Check that the inferred type for _expression is _expectedType or at least implicitly
//! convertible to _expectedType. If not, throw exception.
void expectType(Expression& _expression, Type const& _expectedType);
};
class Block : public Statement
@ -230,6 +262,8 @@ public:
: Statement(_location), m_statements(_statements)
{}
virtual void accept(ASTVisitor& _visitor) override;
virtual ptr<Type> checkTypeRequirements() override;
private:
vecptr<Statement> m_statements;
};
@ -243,6 +277,7 @@ public:
m_trueBody(_trueBody), m_falseBody(_falseBody)
{}
virtual void accept(ASTVisitor& _visitor) override;
virtual ptr<Type> checkTypeRequirements() override;
private:
ptr<Expression> m_condition;
ptr<Statement> m_trueBody;
@ -264,6 +299,7 @@ public:
: BreakableStatement(_location), m_condition(_condition), m_body(_body)
{}
virtual void accept(ASTVisitor& _visitor) override;
virtual ptr<Type> checkTypeRequirements() override;
private:
ptr<Expression> m_condition;
ptr<Statement> m_body;
@ -274,6 +310,7 @@ class Continue : public Statement
public:
Continue(Location const& _location) : Statement(_location) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual ptr<Type> checkTypeRequirements() override;
};
class Break : public Statement
@ -281,6 +318,7 @@ class Break : public Statement
public:
Break(Location const& _location) : Statement(_location) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual ptr<Type> checkTypeRequirements() override;
};
class Return : public Statement
@ -290,8 +328,13 @@ public:
: Statement(_location), m_expression(_expression)
{}
virtual void accept(ASTVisitor& _visitor) override;
virtual ptr<Type> checkTypeRequirements() override;
void setFunctionReturnParameters(ParameterList& _parameters) { m_returnParameters = &_parameters; }
private:
ptr<Expression> m_expression; //< value to return, optional
ParameterList* m_returnParameters; //< extracted from the function declaration
};
class VariableDefinition : public Statement
@ -302,6 +345,8 @@ public:
: Statement(_location), m_variable(_variable), m_value(_value)
{}
virtual void accept(ASTVisitor& _visitor) override;
virtual ptr<Type> checkTypeRequirements() override;
private:
ptr<VariableDeclaration> m_variable;
ptr<Expression> m_value; ///< can be missing
@ -311,7 +356,9 @@ class Expression : public Statement
{
public:
Expression(Location const& _location) : Statement(_location) {}
virtual void accept(ASTVisitor& _visitor) override;
ptr<Type> const& getType() { return m_type; }
protected:
ptr<Type> m_type;
};
/// @}
@ -328,6 +375,7 @@ public:
m_assigmentOperator(_assignmentOperator), m_rightHandSide(_rightHandSide)
{}
virtual void accept(ASTVisitor& _visitor) override;
virtual ptr<Type> checkTypeRequirements() override;
Token::Value getAssignmentOperator() const { return m_assigmentOperator; }
private:
@ -345,6 +393,7 @@ public:
m_subExpression(_subExpression), m_isPrefix(_isPrefix)
{}
virtual void accept(ASTVisitor& _visitor) override;
virtual ptr<Type> checkTypeRequirements() override;
Token::Value getOperator() const { return m_operator; }
bool isPrefixOperation() const { return m_isPrefix; }
@ -362,12 +411,15 @@ public:
: Expression(_location), m_left(_left), m_operator(_operator), m_right(_right)
{}
virtual void accept(ASTVisitor& _visitor) override;
virtual ptr<Type> checkTypeRequirements() override;
Token::Value getOperator() const { return m_operator; }
private:
ptr<Expression> m_left;
Token::Value m_operator;
ptr<Expression> m_right;
ptr<Type> m_commonType;
};
/// Can be ordinary function call, type cast or struct construction.
@ -379,6 +431,7 @@ public:
: Expression(_location), m_expression(_expression), m_arguments(_arguments)
{}
virtual void accept(ASTVisitor& _visitor) override;
virtual ptr<Type> checkTypeRequirements() override;
private:
ptr<Expression> m_expression;
vecptr<Expression> m_arguments;
@ -393,6 +446,7 @@ public:
{}
virtual void accept(ASTVisitor& _visitor) override;
const ASTString& getMemberName() const { return *m_memberName; }
virtual ptr<Type> checkTypeRequirements() override;
private:
ptr<Expression> m_expression;
ptr<ASTString> m_memberName;
@ -406,6 +460,7 @@ public:
: Expression(_location), m_base(_base), m_index(_index)
{}
virtual void accept(ASTVisitor& _visitor) override;
virtual ptr<Type> checkTypeRequirements() override;
private:
ptr<Expression> m_base;
ptr<Expression> m_index;
@ -415,7 +470,6 @@ class PrimaryExpression : public Expression
{
public:
PrimaryExpression(Location const& _location) : Expression(_location) {}
virtual void accept(ASTVisitor& _visitor) override;
};
class Identifier : public PrimaryExpression
@ -424,27 +478,29 @@ public:
Identifier(Location const& _location, ptr<ASTString> const& _name)
: PrimaryExpression(_location), m_name(_name) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual ptr<Type> checkTypeRequirements() override;
ASTString const& getName() const { return *m_name; }
void setReferencedObject(ASTNode& _referencedObject) { m_referencedObject = &_referencedObject; }
ASTNode* getReferencedVariable() { return m_referencedObject; }
void setReferencedDeclaration(Declaration& _referencedDeclaration) { m_referencedDeclaration = &_referencedDeclaration; }
Declaration* getReferencedDeclaration() { return m_referencedDeclaration; }
private:
ptr<ASTString> m_name;
//! Node the name refers to. Has to be a declaration of some sort.
ASTNode* m_referencedObject;
//! Declaration the name refers to.
Declaration* m_referencedDeclaration;
};
class ElementaryTypeNameExpression : public PrimaryExpression
{
public:
ElementaryTypeNameExpression(Location const& _location, Token::Value _type)
: PrimaryExpression(_location), m_type(_type) {}
ElementaryTypeNameExpression(Location const& _location, Token::Value _typeToken)
: PrimaryExpression(_location), m_typeToken(_typeToken) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual ptr<Type> checkTypeRequirements() override;
Token::Value getType() const { return m_type; }
Token::Value getTypeToken() const { return m_typeToken; }
private:
Token::Value m_type;
Token::Value m_typeToken;
};
class Literal : public PrimaryExpression
@ -454,6 +510,7 @@ public:
: PrimaryExpression(_location), m_token(_token), m_value(_value)
{}
virtual void accept(ASTVisitor& _visitor) override;
virtual ptr<Type> checkTypeRequirements() override;
Token::Value getToken() const { return m_token; }
ASTString const& getValue() const { return *m_value; }

View File

@ -32,6 +32,7 @@ namespace dev {
namespace solidity {
class ASTNode;
class Declaration;
class ContractDefinition;
class StructDefinition;
class ParameterList;

View File

@ -233,7 +233,7 @@ bool ASTPrinter::visit(Identifier& _node)
bool ASTPrinter::visit(ElementaryTypeNameExpression& _node)
{
writeLine(std::string("ElementaryTypeNameExpression ") + Token::String(_node.getType()));
writeLine(std::string("ElementaryTypeNameExpression ") + Token::String(_node.getTypeToken()));
printSourcePart(_node);
return goDeeper();
}

View File

@ -31,10 +31,10 @@ namespace solidity {
class NameAndTypeResolver::ScopeHelper {
public:
ScopeHelper(NameAndTypeResolver& _resolver, ASTString const& _name, ASTNode& _declaration)
ScopeHelper(NameAndTypeResolver& _resolver, Declaration& _declaration)
: m_resolver(_resolver)
{
m_resolver.registerName(_name, _declaration);
m_resolver.registerDeclaration(_declaration);
m_resolver.enterNewSubScope(_declaration);
}
~ScopeHelper()
@ -60,16 +60,15 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
void NameAndTypeResolver::handleContract(ContractDefinition& _contract)
{
ScopeHelper scopeHelper(*this, _contract.getName(), _contract);
ScopeHelper scopeHelper(*this, _contract);
// @todo structs (definition and usage)
for (ptr<VariableDeclaration> const& variable : _contract.getStateVariables())
registerName(variable->getName(), *variable);
// @todo structs
registerVariableDeclarationAndResolveType(*variable);
for (ptr<FunctionDefinition> const& function : _contract.getDefinedFunctions())
handleFunction(*function);
// @todo resolve names used in mappings
}
void NameAndTypeResolver::reset()
@ -81,30 +80,20 @@ void NameAndTypeResolver::reset()
void NameAndTypeResolver::handleFunction(FunctionDefinition& _function)
{
ScopeHelper scopeHelper(*this, _function.getName(), _function);
ScopeHelper scopeHelper(*this, _function);
// @todo resolve names used in mappings
for (ptr<VariableDeclaration> const& variable : _function.getParameters())
registerName(variable->getName(), *variable);
if (_function.hasReturnParameters())
for (ptr<VariableDeclaration> const& variable : _function.getReturnParameters())
registerName(variable->getName(), *variable);
handleFunctionBody(_function.getBody());
registerVariablesInFunction(_function);
resolveReferencesInFunction(*_function.getReturnParameterList(), _function.getBody());
_function.getBody().checkTypeRequirements();
}
void NameAndTypeResolver::handleFunctionBody(Block& _functionBody)
{
registerVariablesInFunction(_functionBody);
resolveReferencesInFunction(_functionBody);
}
void NameAndTypeResolver::registerVariablesInFunction(Block& _functionBody)
void NameAndTypeResolver::registerVariablesInFunction(FunctionDefinition& _function)
{
class VariableDeclarationFinder : public ASTVisitor {
public:
VariableDeclarationFinder(NameAndTypeResolver& _resolver) : m_resolver(_resolver) {}
virtual bool visit(VariableDeclaration& _variable) override {
m_resolver.registerName(_variable.getName(), _variable);
m_resolver.registerVariableDeclarationAndResolveType(_variable);
return false;
}
private:
@ -112,37 +101,85 @@ void NameAndTypeResolver::registerVariablesInFunction(Block& _functionBody)
};
VariableDeclarationFinder declarationFinder(*this);
_functionBody.accept(declarationFinder);
_function.accept(declarationFinder);
}
void NameAndTypeResolver::resolveReferencesInFunction(Block& _functionBody)
void NameAndTypeResolver::resolveReferencesInFunction(ParameterList& _returnParameters,
Block& _functionBody)
{
class ReferencesResolver : public ASTVisitor {
public:
ReferencesResolver(NameAndTypeResolver& _resolver) : m_resolver(_resolver) {}
ReferencesResolver(NameAndTypeResolver& _resolver,
ParameterList& _returnParameters)
: m_resolver(_resolver), m_returnParameters(_returnParameters) {}
virtual bool visit(Identifier& _identifier) override {
ASTNode* node = m_resolver.getNameFromCurrentScope(_identifier.getName());
if (node == nullptr)
Declaration* declaration = m_resolver.getNameFromCurrentScope(_identifier.getName());
if (declaration == nullptr)
throw std::exception(); // @todo
_identifier.setReferencedObject(*node);
_identifier.setReferencedDeclaration(*declaration);
return false;
}
virtual bool visit(Return& _return) override {
_return.setFunctionReturnParameters(m_returnParameters);
return true;
}
private:
NameAndTypeResolver& m_resolver;
ParameterList& m_returnParameters;
};
ReferencesResolver referencesResolver(*this, _returnParameters);
_functionBody.accept(referencesResolver);
}
void NameAndTypeResolver::registerVariableDeclarationAndResolveType(VariableDeclaration& _variable)
{
registerDeclaration(_variable);
TypeName* typeName = _variable.getTypeName();
if (typeName == nullptr) // unknown type, to be resolved by first assignment
return;
// walk the AST to resolve user defined type references
// (walking is necessory because of mappings)
// @todo this could probably also be done at an earlier stage where we anyway
// walk the AST
class UserDefinedTypeNameResolver : public ASTVisitor {
public:
UserDefinedTypeNameResolver(NameAndTypeResolver& _resolver)
: m_resolver(_resolver) {}
virtual bool visit(UserDefinedTypeName& _typeName) override {
Declaration* declaration = m_resolver.getNameFromCurrentScope(_typeName.getName());
if (declaration == nullptr)
throw std::exception(); // @todo
StructDefinition* referencedStruct = dynamic_cast<StructDefinition*>(declaration);
if (referencedStruct == nullptr)
throw std::exception(); // @todo we only allow structs as user defined types (later also contracts)
_typeName.setReferencedStruct(*referencedStruct);
return false;
}
virtual bool visit(Mapping&) override {
// @todo
return true;
}
private:
NameAndTypeResolver& m_resolver;
};
ReferencesResolver referencesResolver(*this);
_functionBody.accept(referencesResolver);
UserDefinedTypeNameResolver resolver(*this);
_variable.accept(resolver);
_variable.setType(typeName->toType());
}
void NameAndTypeResolver::registerName(ASTString const& _name, ASTNode& _declaration)
void NameAndTypeResolver::registerDeclaration(Declaration& _declaration)
{
if (!m_currentScope->registerName(_name, _declaration))
if (!m_currentScope->registerDeclaration(_declaration))
throw std::exception(); // @todo
}
ASTNode* NameAndTypeResolver::getNameFromCurrentScope(ASTString const& _name, bool _recursive)
Declaration* NameAndTypeResolver::getNameFromCurrentScope(ASTString const& _name, bool _recursive)
{
return m_currentScope->resolveName(_name, _recursive);
}

View File

@ -24,13 +24,15 @@
#include <map>
#include <boost/noncopyable.hpp>
#include <libsolidity/Scope.h>
#include <libsolidity/ASTVisitor.h>
namespace dev {
namespace solidity {
class NameAndTypeResolver
class NameAndTypeResolver : private boost::noncopyable
{
public:
NameAndTypeResolver();
@ -43,12 +45,13 @@ private:
void handleContract(ContractDefinition& _contract);
void handleFunction(FunctionDefinition& _function);
void handleFunctionBody(Block& _functionBody);
void registerVariablesInFunction(Block& _functionBody);
void resolveReferencesInFunction(Block& _functionBody);
void registerVariablesInFunction(FunctionDefinition& _function);
void resolveReferencesInFunction(ParameterList& _returnParameters,
Block& _functionBody);
void registerName(ASTString const& _name, ASTNode& _declaration);
ASTNode* getNameFromCurrentScope(ASTString const& _name, bool _recursive = true);
void registerVariableDeclarationAndResolveType(VariableDeclaration& _variable);
void registerDeclaration(Declaration& _declaration);
Declaration* getNameFromCurrentScope(ASTString const& _name, bool _recursive = true);
void enterNewSubScope(ASTNode& _node);
void closeCurrentScope();

View File

@ -47,6 +47,8 @@ public:
void markEndPosition() { m_location.end = m_parser.getEndPosition(); }
void setLocationEmpty() { m_location.end = m_location.start; }
/// Set the end position to the one of the given node.
void setEndPositionFromNode(const ptr<ASTNode>& _node)
{
@ -104,7 +106,8 @@ ptr<ContractDefinition> Parser::parseContractDefinition()
structs.push_back(parseStructDefinition());
} else if (currentToken == Token::IDENTIFIER || currentToken == Token::MAPPING ||
Token::IsElementaryTypeName(currentToken)) {
stateVariables.push_back(parseVariableDeclaration());
bool const allowVar = false;
stateVariables.push_back(parseVariableDeclaration(allowVar));
expectToken(Token::SEMICOLON);
} else {
throwExpectationError("Function, variable or struct declaration expected.");
@ -135,6 +138,11 @@ ptr<FunctionDefinition> Parser::parseFunctionDefinition(bool _isPublic)
const bool permitEmptyParameterList = false;
m_scanner->next();
returnParameters = parseParameterList(permitEmptyParameterList);
} else {
// create an empty parameter list at a zero-length location
ASTNodeFactory nodeFactory(*this);
nodeFactory.setLocationEmpty();
returnParameters = nodeFactory.createNode<ParameterList>(vecptr<VariableDeclaration>());
}
ptr<Block> block = parseBlock();
nodeFactory.setEndPositionFromNode(block);
@ -151,7 +159,8 @@ ptr<StructDefinition> Parser::parseStructDefinition()
vecptr<VariableDeclaration> members;
expectToken(Token::LBRACE);
while (m_scanner->getCurrentToken() != Token::RBRACE) {
members.push_back(parseVariableDeclaration());
bool const allowVar = false;
members.push_back(parseVariableDeclaration(allowVar));
expectToken(Token::SEMICOLON);
}
nodeFactory.markEndPosition();
@ -160,16 +169,16 @@ ptr<StructDefinition> Parser::parseStructDefinition()
return nodeFactory.createNode<StructDefinition>(name, members);
}
ptr<VariableDeclaration> Parser::parseVariableDeclaration()
ptr<VariableDeclaration> Parser::parseVariableDeclaration(bool _allowVar)
{
ASTNodeFactory nodeFactory(*this);
ptr<TypeName> type = parseTypeName();
ptr<TypeName> type = parseTypeName(_allowVar);
nodeFactory.markEndPosition();
return nodeFactory.createNode<VariableDeclaration>(type, expectIdentifierToken());
}
ptr<TypeName> Parser::parseTypeName()
ptr<TypeName> Parser::parseTypeName(bool _allowVar)
{
ptr<TypeName> type;
Token::Value token = m_scanner->getCurrentToken();
@ -177,7 +186,8 @@ ptr<TypeName> Parser::parseTypeName()
type = ASTNodeFactory(*this).createNode<ElementaryTypeName>(token);
m_scanner->next();
} else if (token == Token::VAR) {
type = ASTNodeFactory(*this).createNode<TypeName>();
if (!_allowVar)
throwExpectationError("Expected explicit type name.");
m_scanner->next();
} else if (token == Token::MAPPING) {
type = parseMapping();
@ -206,24 +216,26 @@ ptr<Mapping> Parser::parseMapping()
m_scanner->next();
expectToken(Token::ARROW);
ptr<TypeName> valueType = parseTypeName();
bool const allowVar = false;
ptr<TypeName> valueType = parseTypeName(allowVar);
nodeFactory.markEndPosition();
expectToken(Token::RPAREN);
return nodeFactory.createNode<Mapping>(keyType, valueType);
}
ptr<ParameterList> Parser::parseParameterList(bool _permitEmpty)
ptr<ParameterList> Parser::parseParameterList(bool _allowEmpty)
{
ASTNodeFactory nodeFactory(*this);
vecptr<VariableDeclaration> parameters;
expectToken(Token::LPAREN);
if (!_permitEmpty || m_scanner->getCurrentToken() != Token::RPAREN) {
parameters.push_back(parseVariableDeclaration());
if (!_allowEmpty || m_scanner->getCurrentToken() != Token::RPAREN) {
bool const allowVar = false;
parameters.push_back(parseVariableDeclaration(allowVar));
while (m_scanner->getCurrentToken() != Token::RPAREN) {
expectToken(Token::COMMA);
parameters.push_back(parseVariableDeclaration());
parameters.push_back(parseVariableDeclaration(allowVar));
}
}
nodeFactory.markEndPosition();
@ -328,7 +340,8 @@ ptr<WhileStatement> Parser::parseWhileStatement()
ptr<VariableDefinition> Parser::parseVariableDefinition()
{
ASTNodeFactory nodeFactory(*this);
ptr<VariableDeclaration> variable = parseVariableDeclaration();
bool const allowVar = true;
ptr<VariableDeclaration> variable = parseVariableDeclaration(allowVar);
ptr<Expression> value;
if (m_scanner->getCurrentToken() == Token::ASSIGN) {
m_scanner->next();

View File

@ -47,10 +47,10 @@ private:
ptr<ContractDefinition> parseContractDefinition();
ptr<FunctionDefinition> parseFunctionDefinition(bool _isPublic);
ptr<StructDefinition> parseStructDefinition();
ptr<VariableDeclaration> parseVariableDeclaration();
ptr<TypeName> parseTypeName();
ptr<VariableDeclaration> parseVariableDeclaration(bool _allowVar);
ptr<TypeName> parseTypeName(bool _allowVar);
ptr<Mapping> parseMapping();
ptr<ParameterList> parseParameterList(bool _permitEmpty = true);
ptr<ParameterList> parseParameterList(bool _allowEmpty = true);
ptr<Block> parseBlock();
ptr<Statement> parseStatement();
ptr<IfStatement> parseIfStatement();

48
Scope.cpp Normal file
View File

@ -0,0 +1,48 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
* @date 2014
* Scope - object that holds declaration of names.
*/
#include <libsolidity/Scope.h>
#include <libsolidity/AST.h>
namespace dev {
namespace solidity {
bool Scope::registerDeclaration(Declaration& _declaration)
{
if (m_declarations.find(_declaration.getName()) != m_declarations.end())
return false;
m_declarations[_declaration.getName()] = &_declaration;
return true;
}
Declaration*Scope::resolveName(ASTString const& _name, bool _recursive) const
{
auto result = m_declarations.find(_name);
if (result != m_declarations.end())
return result->second;
if (_recursive && m_outerScope != nullptr)
return m_outerScope->resolveName(_name, true);
return nullptr;
}
} }

24
Scope.h
View File

@ -24,6 +24,8 @@
#include <map>
#include <boost/noncopyable.hpp>
#include <libsolidity/ASTForward.h>
namespace dev {
@ -33,29 +35,15 @@ class Scope
{
public:
explicit Scope(Scope* _outerScope = nullptr) : m_outerScope(_outerScope) {}
/// Registers the name _name in the scope unless it is already declared. Returns true iff
/// Registers the declaration in the scope unless its name is already declared. Returns true iff
/// it was not yet declared.
bool registerName(ASTString const& _name, ASTNode& _declaration)
{
if (m_declaredNames.find(_name) != m_declaredNames.end())
return false;
m_declaredNames[_name] = &_declaration;
return true;
}
ASTNode* resolveName(ASTString const& _name, bool _recursive = false) const
{
auto result = m_declaredNames.find(_name);
if (result != m_declaredNames.end())
return result->second;
if (_recursive && m_outerScope != nullptr)
return m_outerScope->resolveName(_name, true);
return nullptr;
}
bool registerDeclaration(Declaration& _declaration);
Declaration* resolveName(ASTString const& _name, bool _recursive = false) const;
Scope* getOuterScope() const { return m_outerScope; }
private:
Scope* m_outerScope;
std::map<ASTString, ASTNode*> m_declaredNames;
std::map<ASTString, Declaration*> m_declarations;
};
} }

13
Token.h
View File

@ -93,6 +93,7 @@ namespace solidity {
T(INIT_CONST, "=init_const", 2) /* AST-use only. */ \
T(INIT_CONST_LEGACY, "=init_const_legacy", 2) /* AST-use only. */ \
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) \
@ -117,7 +118,6 @@ namespace solidity {
T(SHL, "<<", 11) \
T(SAR, ">>", 11) \
T(SHR, ">>>", 11) \
T(ROR, "rotate right", 11) /* only used by Crankshaft */ \
T(ADD, "+", 12) \
T(SUB, "-", 12) \
T(MUL, "*", 13) \
@ -181,7 +181,9 @@ namespace solidity {
K(WHILE, "while", 0) \
K(WITH, "with", 0) \
\
/* type keywords, keep them in this order, keep int as first keyword TODO more to be added */ \
/* 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(INT32, "int32", 0) \
K(INT64, "int64", 0) \
@ -274,7 +276,7 @@ public:
}
static bool IsTruncatingBinaryOp(Value op) {
return BIT_OR <= op && op <= ROR;
return BIT_OR <= op && op <= SHR;
}
static bool IsCompareOp(Value op) {
@ -332,6 +334,11 @@ public:
}
}
static Value AssignmentToBinaryOp(Value op) {
BOOST_ASSERT(IsAssignmentOp(op) && op != ASSIGN);
return Token::Value(op + (BIT_OR - ASSIGN_BIT_OR));
}
static bool IsBitOp(Value op) {
return (BIT_OR <= op && op <= SHR) || op == BIT_NOT;
}

152
Types.cpp Normal file
View File

@ -0,0 +1,152 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
* @date 2014
* Solidity data types
*/
#include <libsolidity/Types.h>
#include <libsolidity/AST.h>
namespace dev {
namespace solidity {
ptr<Type> Type::fromElementaryTypeName(Token::Value _typeToken)
{
if (Token::INT <= _typeToken && _typeToken <= Token::HASH256) {
int offset = _typeToken - Token::INT;
int bits = offset % 5;
if (bits == 0)
bits = 256;
else
bits = (1 << (bits - 1)) * 32;
int modifier = offset / 5;
return std::make_shared<IntegerType>(bits,
modifier == 0 ? IntegerType::Modifier::UNSIGNED :
modifier == 1 ? IntegerType::Modifier::SIGNED :
IntegerType::Modifier::HASH);
} else if (_typeToken == Token::ADDRESS) {
return std::make_shared<IntegerType>(0, IntegerType::Modifier::ADDRESS);
} else if (_typeToken == Token::BOOL) {
return std::make_shared<BoolType>();
} else {
BOOST_ASSERT(false);
// @todo add other tyes
}
}
ptr<Type> Type::fromUserDefinedTypeName(const UserDefinedTypeName& _typeName)
{
return std::make_shared<StructType>(*_typeName.getReferencedStruct());
}
ptr<Type> Type::fromMapping(const Mapping&)
{
BOOST_ASSERT(false); //@todo not yet implemented
return ptr<Type>();
}
ptr<Type> Type::forLiteral(const Literal& _literal)
{
switch (_literal.getToken()) {
case Token::TRUE_LITERAL:
case Token::FALSE_LITERAL:
return std::make_shared<BoolType>();
case Token::NUMBER:
return IntegerType::smallestTypeForLiteral(_literal.getValue());
case Token::STRING_LITERAL:
return ptr<Type>(); // @todo
default:
return ptr<Type>();
}
}
ptr<IntegerType> IntegerType::smallestTypeForLiteral(const std::string&)
{
//@todo
return std::make_shared<IntegerType>(256, Modifier::UNSIGNED);
}
IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier)
: m_bits(_bits), m_modifier(_modifier)
{
BOOST_ASSERT(_bits > 0 && _bits <= 256 && _bits % 8 == 0);
if (isAddress())
_bits = 160;
}
bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const
{
if (_convertTo.getCategory() != Category::INTEGER)
return false;
IntegerType const& convertTo = dynamic_cast<IntegerType const&>(_convertTo);
if (convertTo.m_bits < m_bits)
return false;
if (isAddress())
return convertTo.isAddress();
else if (isHash())
return convertTo.isHash();
else if (isSigned())
return convertTo.isSigned();
else
return !convertTo.isSigned() || convertTo.m_bits > m_bits;
}
bool IntegerType::isExplicitlyConvertibleTo(const Type& _convertTo) const
{
// @todo
return false;
}
bool IntegerType::acceptsBinaryOperator(Token::Value _operator) const
{
//@todo
return true;
}
bool IntegerType::acceptsUnaryOperator(Token::Value _operator) const
{
//@todo
return true;
}
bool BoolType::isExplicitlyConvertibleTo(const Type& _convertTo) const
{
//@todo conversion to integer is fine, but not to address
//@todo this is an example of explicit conversions being not transitive (though implicit should)
return isImplicitlyConvertibleTo(_convertTo);
}
bool ContractType::isImplicitlyConvertibleTo(const Type& _convertTo) const
{
if (_convertTo.getCategory() != Category::CONTRACT)
return false;
ContractType const& convertTo = dynamic_cast<ContractType const&>(_convertTo);
return &m_contract == &convertTo.m_contract;
}
bool StructType::isImplicitlyConvertibleTo(const Type& _convertTo) const
{
if (_convertTo.getCategory() != Category::STRUCT)
return false;
StructType const& convertTo = dynamic_cast<StructType const&>(_convertTo);
return &m_struct == &convertTo.m_struct;
}
} }

171
Types.h Normal file
View File

@ -0,0 +1,171 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
* @date 2014
* Solidity data types
*/
#pragma once
#include <memory>
#include <string>
#include <boost/noncopyable.hpp>
#include <boost/assert.hpp>
#include <libsolidity/Token.h>
namespace dev {
namespace solidity {
// AST forward declarations
class ContractDefinition;
class FunctionDefinition;
class StructDefinition;
class Literal;
class ElementaryTypeName;
class UserDefinedTypeName;
class Mapping;
template <typename T>
using ptr = std::shared_ptr<T>;
// @todo realMxN, string<N>, mapping
class Type : private boost::noncopyable
{
public:
enum class Category {
INTEGER, BOOL, REAL, STRING, CONTRACT, STRUCT, FUNCTION, MAPPING, VOID, TYPE
};
//! factory functions that convert an AST TypeName to a Type.
static ptr<Type> fromElementaryTypeName(Token::Value _typeToken);
static ptr<Type> fromUserDefinedTypeName(UserDefinedTypeName const& _typeName);
static ptr<Type> fromMapping(Mapping const& _typeName);
static ptr<Type> forLiteral(Literal const& _literal);
virtual Category getCategory() const = 0;
virtual bool isImplicitlyConvertibleTo(const Type& _convertTo) const { return false; }
virtual bool isExplicitlyConvertibleTo(const Type& _convertTo) const { return isImplicitlyConvertibleTo(_convertTo); }
virtual bool acceptsBinaryOperator(Token::Value _operator) const { return false; }
virtual bool acceptsUnaryOperator(Token::Value _operator) const { return false; }
};
class IntegerType : public Type
{
public:
enum class Modifier {
UNSIGNED, SIGNED, HASH, ADDRESS
};
virtual Category getCategory() const { return Category::INTEGER; }
static ptr<IntegerType> smallestTypeForLiteral(std::string const& _literal);
explicit IntegerType(int _bits, Modifier _modifier = Modifier::UNSIGNED);
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual bool isExplicitlyConvertibleTo(const Type& _convertTo) const override;
virtual bool acceptsBinaryOperator(Token::Value _operator) const override;
virtual bool acceptsUnaryOperator(Token::Value _operator) 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; }
int isSigned() const { return m_modifier == Modifier::SIGNED; }
private:
int m_bits;
Modifier m_modifier;
};
class BoolType : public Type
{
public:
virtual Category getCategory() const { return Category::BOOL; }
virtual bool isImplicitlyConvertibleTo(const Type& _convertTo) const override
{ return _convertTo.getCategory() == Category::BOOL; }
virtual bool isExplicitlyConvertibleTo(const Type& _convertTo) const override;
virtual bool acceptsBinaryOperator(Token::Value _operator) const override
{ return _operator == Token::AND || _operator == Token::OR; }
virtual bool acceptsUnaryOperator(Token::Value _operator) const override
{ return _operator == Token::NOT || _operator == Token::DELETE; }
};
class ContractType : public Type
{
public:
virtual Category getCategory() const { return Category::CONTRACT; }
ContractType(ContractDefinition const& _contract) : m_contract(_contract) {}
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const;
private:
ContractDefinition const& m_contract;
};
class StructType : public Type
{
public:
virtual Category getCategory() const { return Category::STRUCT; }
StructType(StructDefinition const& _struct) : m_struct(_struct) {}
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const;
virtual bool acceptsUnaryOperator(Token::Value _operator) const override
{ return _operator == Token::DELETE; }
private:
StructDefinition const& m_struct;
};
class FunctionType : public Type
{
public:
virtual Category getCategory() const { return Category::FUNCTION; }
FunctionType(FunctionDefinition const& _function) : m_function(_function) {}
FunctionDefinition const& getFunction() const { return m_function; }
private:
FunctionDefinition const& m_function;
};
class MappingType : public Type
{
public:
virtual Category getCategory() const { return Category::MAPPING; }
MappingType() {}
private:
//@todo
};
//@todo should be changed into "empty anonymous struct"
class VoidType : public Type
{
public:
virtual Category getCategory() const { return Category::VOID; }
VoidType() {}
};
class TypeType : public Type
{
public:
virtual Category getCategory() const { return Category::TYPE; }
TypeType(ptr<Type> const& _actualType) : m_actualType(_actualType) {}
ptr<Type> const& getActualType() { return m_actualType; }
private:
ptr<Type> m_actualType;
};
} }