mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Type system, not yet complete.
This commit is contained in:
		
							parent
							
								
									bdac5c7b4b
								
							
						
					
					
						commit
						89b794f1dc
					
				
							
								
								
									
										244
									
								
								AST.cpp
									
									
									
									
									
								
							
							
						
						
									
										244
									
								
								AST.cpp
									
									
									
									
									
								
							| @ -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
									
									
									
									
									
								
							
							
						
						
									
										123
									
								
								AST.h
									
									
									
									
									
								
							| @ -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; } | ||||
|  | ||||
| @ -32,6 +32,7 @@ namespace dev { | ||||
| namespace solidity { | ||||
| 
 | ||||
| class ASTNode; | ||||
| class Declaration; | ||||
| class ContractDefinition; | ||||
| class StructDefinition; | ||||
| class ParameterList; | ||||
|  | ||||
| @ -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(); | ||||
| } | ||||
|  | ||||
| @ -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); | ||||
| } | ||||
|  | ||||
| @ -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(); | ||||
|  | ||||
							
								
								
									
										37
									
								
								Parser.cpp
									
									
									
									
									
								
							
							
						
						
									
										37
									
								
								Parser.cpp
									
									
									
									
									
								
							| @ -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(); | ||||
|  | ||||
							
								
								
									
										6
									
								
								Parser.h
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								Parser.h
									
									
									
									
									
								
							| @ -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
									
								
							
							
						
						
									
										48
									
								
								Scope.cpp
									
									
									
									
									
										Normal 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
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								Scope.h
									
									
									
									
									
								
							| @ -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
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								Token.h
									
									
									
									
									
								
							| @ -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
									
								
							
							
						
						
									
										152
									
								
								Types.cpp
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										171
									
								
								Types.h
									
									
									
									
									
										Normal 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; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| } } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user