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. |  * Solidity abstract syntax tree. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
|  | #include <algorithm> | ||||||
|  | 
 | ||||||
| #include <libsolidity/AST.h> | #include <libsolidity/AST.h> | ||||||
| #include <libsolidity/ASTVisitor.h> | #include <libsolidity/ASTVisitor.h> | ||||||
| 
 | 
 | ||||||
| @ -66,8 +68,8 @@ void FunctionDefinition::accept(ASTVisitor& _visitor) | |||||||
| void VariableDeclaration::accept(ASTVisitor& _visitor) | void VariableDeclaration::accept(ASTVisitor& _visitor) | ||||||
| { | { | ||||||
| 	if (_visitor.visit(*this)) { | 	if (_visitor.visit(*this)) { | ||||||
| 		if (m_type) | 		if (m_typeName) | ||||||
| 			m_type->accept(_visitor); | 			m_typeName->accept(_visitor); | ||||||
| 	} | 	} | ||||||
| 	_visitor.endVisit(*this); | 	_visitor.endVisit(*this); | ||||||
| } | } | ||||||
| @ -170,12 +172,6 @@ void VariableDefinition::accept(ASTVisitor& _visitor) | |||||||
| 	_visitor.endVisit(*this); | 	_visitor.endVisit(*this); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Expression::accept(ASTVisitor& _visitor) |  | ||||||
| { |  | ||||||
| 	_visitor.visit(*this); |  | ||||||
| 	_visitor.endVisit(*this); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void Assignment::accept(ASTVisitor& _visitor) | void Assignment::accept(ASTVisitor& _visitor) | ||||||
| { | { | ||||||
| 	if (_visitor.visit(*this)) { | 	if (_visitor.visit(*this)) { | ||||||
| @ -228,12 +224,6 @@ void IndexAccess::accept(ASTVisitor& _visitor) | |||||||
| 	_visitor.endVisit(*this); | 	_visitor.endVisit(*this); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void PrimaryExpression::accept(ASTVisitor& _visitor) |  | ||||||
| { |  | ||||||
| 	_visitor.visit(*this); |  | ||||||
| 	_visitor.endVisit(*this); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void Identifier::accept(ASTVisitor& _visitor) | void Identifier::accept(ASTVisitor& _visitor) | ||||||
| { | { | ||||||
| 	_visitor.visit(*this); | 	_visitor.visit(*this); | ||||||
| @ -252,4 +242,230 @@ void Literal::accept(ASTVisitor& _visitor) | |||||||
| 	_visitor.endVisit(*this); | 	_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 | #pragma once | ||||||
| 
 | 
 | ||||||
|  | #include <boost/noncopyable.hpp> | ||||||
|  | 
 | ||||||
| #include <string> | #include <string> | ||||||
| #include <vector> | #include <vector> | ||||||
| #include <memory> | #include <memory> | ||||||
| @ -29,13 +31,14 @@ | |||||||
| #include <libsolidity/ASTForward.h> | #include <libsolidity/ASTForward.h> | ||||||
| #include <libsolidity/BaseTypes.h> | #include <libsolidity/BaseTypes.h> | ||||||
| #include <libsolidity/Token.h> | #include <libsolidity/Token.h> | ||||||
|  | #include <libsolidity/Types.h> | ||||||
| 
 | 
 | ||||||
| namespace dev { | namespace dev { | ||||||
| namespace solidity { | namespace solidity { | ||||||
| 
 | 
 | ||||||
| class ASTVisitor; | class ASTVisitor; | ||||||
| 
 | 
 | ||||||
| class ASTNode | class ASTNode : private boost::noncopyable | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	explicit ASTNode(Location const& _location) | 	explicit ASTNode(Location const& _location) | ||||||
| @ -55,7 +58,18 @@ private: | |||||||
| 	Location m_location; | 	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: | public: | ||||||
| 	ContractDefinition(Location const& _location, | 	ContractDefinition(Location const& _location, | ||||||
| @ -63,7 +77,7 @@ public: | |||||||
| 					   vecptr<StructDefinition> const& _definedStructs, | 					   vecptr<StructDefinition> const& _definedStructs, | ||||||
| 					   vecptr<VariableDeclaration> const& _stateVariables, | 					   vecptr<VariableDeclaration> const& _stateVariables, | ||||||
| 					   vecptr<FunctionDefinition> const& _definedFunctions) | 					   vecptr<FunctionDefinition> const& _definedFunctions) | ||||||
| 		: ASTNode(_location), m_name(_name), | 		: Declaration(_location, _name), | ||||||
| 		  m_definedStructs(_definedStructs), | 		  m_definedStructs(_definedStructs), | ||||||
| 		  m_stateVariables(_stateVariables), | 		  m_stateVariables(_stateVariables), | ||||||
| 		  m_definedFunctions(_definedFunctions) | 		  m_definedFunctions(_definedFunctions) | ||||||
| @ -71,30 +85,26 @@ public: | |||||||
| 
 | 
 | ||||||
| 	virtual void accept(ASTVisitor& _visitor) override; | 	virtual void accept(ASTVisitor& _visitor) override; | ||||||
| 
 | 
 | ||||||
| 	const ASTString& getName() const { return *m_name; } |  | ||||||
| 	vecptr<StructDefinition> const& getDefinedStructs() { return m_definedStructs; } | 	vecptr<StructDefinition> const& getDefinedStructs() { return m_definedStructs; } | ||||||
| 	vecptr<VariableDeclaration> const& getStateVariables() { return m_stateVariables; } | 	vecptr<VariableDeclaration> const& getStateVariables() { return m_stateVariables; } | ||||||
| 	vecptr<FunctionDefinition> const& getDefinedFunctions() { return m_definedFunctions; } | 	vecptr<FunctionDefinition> const& getDefinedFunctions() { return m_definedFunctions; } | ||||||
| private: | private: | ||||||
| 	ptr<ASTString> m_name; |  | ||||||
| 	vecptr<StructDefinition> m_definedStructs; | 	vecptr<StructDefinition> m_definedStructs; | ||||||
| 	vecptr<VariableDeclaration> m_stateVariables; | 	vecptr<VariableDeclaration> m_stateVariables; | ||||||
| 	vecptr<FunctionDefinition> m_definedFunctions; | 	vecptr<FunctionDefinition> m_definedFunctions; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class StructDefinition : public ASTNode | class StructDefinition : public Declaration | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	StructDefinition(Location const& _location, | 	StructDefinition(Location const& _location, | ||||||
| 					 ptr<ASTString> const& _name, | 					 ptr<ASTString> const& _name, | ||||||
| 					 vecptr<VariableDeclaration> const& _members) | 					 vecptr<VariableDeclaration> const& _members) | ||||||
| 		: ASTNode(_location), m_name(_name), m_members(_members) | 		: Declaration(_location, _name), m_members(_members) | ||||||
| 	{} | 	{} | ||||||
| 	virtual void accept(ASTVisitor& _visitor) override; | 	virtual void accept(ASTVisitor& _visitor) override; | ||||||
| 
 | 
 | ||||||
| 	const ASTString& getName() const { return *m_name; } |  | ||||||
| private: | private: | ||||||
| 	ptr<ASTString> m_name; |  | ||||||
| 	vecptr<VariableDeclaration> m_members; | 	vecptr<VariableDeclaration> m_members; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| @ -114,7 +124,7 @@ private: | |||||||
| 	vecptr<VariableDeclaration> m_parameters; | 	vecptr<VariableDeclaration> m_parameters; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class FunctionDefinition : public ASTNode | class FunctionDefinition : public Declaration | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	FunctionDefinition(Location const& _location, ptr<ASTString> const& _name, bool _isPublic, | 	FunctionDefinition(Location const& _location, ptr<ASTString> const& _name, bool _isPublic, | ||||||
| @ -122,43 +132,47 @@ public: | |||||||
| 					   bool _isDeclaredConst, | 					   bool _isDeclaredConst, | ||||||
| 					   ptr<ParameterList> const& _returnParameters, | 					   ptr<ParameterList> const& _returnParameters, | ||||||
| 					   ptr<Block> const& _body) | 					   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_isDeclaredConst(_isDeclaredConst), m_returnParameters(_returnParameters), | ||||||
| 		  m_body(_body) | 		  m_body(_body) | ||||||
| 	{} | 	{} | ||||||
| 	virtual void accept(ASTVisitor& _visitor) override; | 	virtual void accept(ASTVisitor& _visitor) override; | ||||||
| 
 | 
 | ||||||
| 	const ASTString& getName() const { return *m_name; } |  | ||||||
| 	bool isPublic() const { return m_isPublic; } | 	bool isPublic() const { return m_isPublic; } | ||||||
| 	bool isDeclaredConst() const { return m_isDeclaredConst; } | 	bool isDeclaredConst() const { return m_isDeclaredConst; } | ||||||
| 	vecptr<VariableDeclaration> const& getParameters() { return m_parameters->getParameters(); } | 	vecptr<VariableDeclaration> const& getParameters() const { return m_parameters->getParameters(); } | ||||||
| 	bool hasReturnParameters() const { return m_returnParameters.get() != nullptr; } | 	ParameterList& getParameterList() { return *m_parameters; } | ||||||
| 	vecptr<VariableDeclaration> const& getReturnParameters() { return m_returnParameters->getParameters(); } | 	ptr<ParameterList> const& getReturnParameterList() const { return m_returnParameters; } | ||||||
| 	Block& getBody() { return *m_body; } | 	Block& getBody() { return *m_body; } | ||||||
| private: | private: | ||||||
| 	ptr<ASTString> m_name; |  | ||||||
| 	bool m_isPublic; | 	bool m_isPublic; | ||||||
| 	ptr<ParameterList> m_parameters; | 	ptr<ParameterList> m_parameters; | ||||||
| 	bool m_isDeclaredConst; | 	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; | 	ptr<Block> m_body; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class VariableDeclaration : public ASTNode | class VariableDeclaration : public Declaration | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	VariableDeclaration(Location const& _location, | 	VariableDeclaration(Location const& _location, | ||||||
| 						ptr<TypeName> const& _type, | 						ptr<TypeName> const& _type, | ||||||
| 						ptr<ASTString> const& _name) | 						ptr<ASTString> const& _name) | ||||||
| 		: ASTNode(_location), m_type(_type), m_name(_name) | 		: Declaration(_location, _name), m_typeName(_type) | ||||||
| 	{} | 	{} | ||||||
| 	virtual void accept(ASTVisitor& _visitor) override; | 	virtual void accept(ASTVisitor& _visitor) override; | ||||||
| 
 | 
 | ||||||
| 	TypeName* getTypeName() const { return m_type.get(); } | 	bool isTypeGivenExplicitly() const { return m_typeName.get() != nullptr; } | ||||||
| 	const ASTString& getName() const { return *m_name; } | 	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: | private: | ||||||
| 	ptr<TypeName> m_type; ///< can be empty ("var")
 | 	ptr<TypeName> m_typeName; ///< can be empty ("var")
 | ||||||
| 	ptr<ASTString> m_name; | 
 | ||||||
|  | 	ptr<Type> m_type; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// types
 | /// types
 | ||||||
| @ -169,6 +183,8 @@ class TypeName : public ASTNode | |||||||
| public: | public: | ||||||
| 	explicit TypeName(Location const& _location) : ASTNode(_location) {} | 	explicit TypeName(Location const& _location) : ASTNode(_location) {} | ||||||
| 	virtual void accept(ASTVisitor& _visitor) override; | 	virtual void accept(ASTVisitor& _visitor) override; | ||||||
|  | 
 | ||||||
|  | 	virtual ptr<Type> toType() = 0; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// any pre-defined type that is not a mapping
 | /// any pre-defined type that is not a mapping
 | ||||||
| @ -179,6 +195,7 @@ public: | |||||||
| 		: TypeName(_location), m_type(_type) | 		: TypeName(_location), m_type(_type) | ||||||
| 	{} | 	{} | ||||||
| 	virtual void accept(ASTVisitor& _visitor) override; | 	virtual void accept(ASTVisitor& _visitor) override; | ||||||
|  | 	virtual ptr<Type> toType() override { return Type::fromElementaryTypeName(m_type); } | ||||||
| 
 | 
 | ||||||
| 	Token::Value getType() const { return m_type; } | 	Token::Value getType() const { return m_type; } | ||||||
| private: | private: | ||||||
| @ -192,10 +209,15 @@ public: | |||||||
| 		: TypeName(_location), m_name(_name) | 		: TypeName(_location), m_name(_name) | ||||||
| 	{} | 	{} | ||||||
| 	virtual void accept(ASTVisitor& _visitor) override; | 	virtual void accept(ASTVisitor& _visitor) override; | ||||||
|  | 	virtual ptr<Type> toType() override { return Type::fromUserDefinedTypeName(*this); } | ||||||
| 
 | 
 | ||||||
| 	const ASTString& getName() const { return *m_name; } | 	const ASTString& getName() const { return *m_name; } | ||||||
|  | 	void setReferencedStruct(StructDefinition& _referencedStruct) { m_referencedStruct = &_referencedStruct; } | ||||||
|  | 	StructDefinition const* getReferencedStruct() const { return m_referencedStruct; } | ||||||
| private: | private: | ||||||
| 	ptr<ASTString> m_name; | 	ptr<ASTString> m_name; | ||||||
|  | 
 | ||||||
|  | 	StructDefinition* m_referencedStruct; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class Mapping : public TypeName | class Mapping : public TypeName | ||||||
| @ -206,6 +228,7 @@ public: | |||||||
| 		: TypeName(_location), m_keyType(_keyType), m_valueType(_valueType) | 		: TypeName(_location), m_keyType(_keyType), m_valueType(_valueType) | ||||||
| 	{} | 	{} | ||||||
| 	virtual void accept(ASTVisitor& _visitor) override; | 	virtual void accept(ASTVisitor& _visitor) override; | ||||||
|  | 	virtual ptr<Type> toType() override { return Type::fromMapping(*this); } | ||||||
| private: | private: | ||||||
| 	ptr<ElementaryTypeName> m_keyType; | 	ptr<ElementaryTypeName> m_keyType; | ||||||
| 	ptr<TypeName> m_valueType; | 	ptr<TypeName> m_valueType; | ||||||
| @ -221,6 +244,15 @@ class Statement : public ASTNode | |||||||
| public: | public: | ||||||
| 	explicit Statement(Location const& _location) : ASTNode(_location) {} | 	explicit Statement(Location const& _location) : ASTNode(_location) {} | ||||||
| 	virtual void accept(ASTVisitor& _visitor) override; | 	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 | class Block : public Statement | ||||||
| @ -230,6 +262,8 @@ public: | |||||||
| 		: Statement(_location), m_statements(_statements) | 		: Statement(_location), m_statements(_statements) | ||||||
| 	{} | 	{} | ||||||
| 	virtual void accept(ASTVisitor& _visitor) override; | 	virtual void accept(ASTVisitor& _visitor) override; | ||||||
|  | 
 | ||||||
|  | 	virtual ptr<Type> checkTypeRequirements() override; | ||||||
| private: | private: | ||||||
| 	vecptr<Statement> m_statements; | 	vecptr<Statement> m_statements; | ||||||
| }; | }; | ||||||
| @ -243,6 +277,7 @@ public: | |||||||
| 		  m_trueBody(_trueBody), m_falseBody(_falseBody) | 		  m_trueBody(_trueBody), m_falseBody(_falseBody) | ||||||
| 	{} | 	{} | ||||||
| 	virtual void accept(ASTVisitor& _visitor) override; | 	virtual void accept(ASTVisitor& _visitor) override; | ||||||
|  | 	virtual ptr<Type> checkTypeRequirements() override; | ||||||
| private: | private: | ||||||
| 	ptr<Expression> m_condition; | 	ptr<Expression> m_condition; | ||||||
| 	ptr<Statement> m_trueBody; | 	ptr<Statement> m_trueBody; | ||||||
| @ -264,6 +299,7 @@ public: | |||||||
| 		: BreakableStatement(_location), m_condition(_condition), m_body(_body) | 		: BreakableStatement(_location), m_condition(_condition), m_body(_body) | ||||||
| 	{} | 	{} | ||||||
| 	virtual void accept(ASTVisitor& _visitor) override; | 	virtual void accept(ASTVisitor& _visitor) override; | ||||||
|  | 	virtual ptr<Type> checkTypeRequirements() override; | ||||||
| private: | private: | ||||||
| 	ptr<Expression> m_condition; | 	ptr<Expression> m_condition; | ||||||
| 	ptr<Statement> m_body; | 	ptr<Statement> m_body; | ||||||
| @ -274,6 +310,7 @@ class Continue : public Statement | |||||||
| public: | public: | ||||||
| 	Continue(Location const& _location) : Statement(_location) {} | 	Continue(Location const& _location) : Statement(_location) {} | ||||||
| 	virtual void accept(ASTVisitor& _visitor) override; | 	virtual void accept(ASTVisitor& _visitor) override; | ||||||
|  | 	virtual ptr<Type> checkTypeRequirements() override; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class Break : public Statement | class Break : public Statement | ||||||
| @ -281,6 +318,7 @@ class Break : public Statement | |||||||
| public: | public: | ||||||
| 	Break(Location const& _location) : Statement(_location) {} | 	Break(Location const& _location) : Statement(_location) {} | ||||||
| 	virtual void accept(ASTVisitor& _visitor) override; | 	virtual void accept(ASTVisitor& _visitor) override; | ||||||
|  | 	virtual ptr<Type> checkTypeRequirements() override; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class Return : public Statement | class Return : public Statement | ||||||
| @ -290,8 +328,13 @@ public: | |||||||
| 		: Statement(_location), m_expression(_expression) | 		: Statement(_location), m_expression(_expression) | ||||||
| 	{} | 	{} | ||||||
| 	virtual void accept(ASTVisitor& _visitor) override; | 	virtual void accept(ASTVisitor& _visitor) override; | ||||||
|  | 	virtual ptr<Type> checkTypeRequirements() override; | ||||||
|  | 
 | ||||||
|  | 	void setFunctionReturnParameters(ParameterList& _parameters) { m_returnParameters = &_parameters; } | ||||||
| private: | private: | ||||||
| 	ptr<Expression> m_expression; //< value to return, optional
 | 	ptr<Expression> m_expression; //< value to return, optional
 | ||||||
|  | 
 | ||||||
|  | 	ParameterList* m_returnParameters; //< extracted from the function declaration
 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class VariableDefinition : public Statement | class VariableDefinition : public Statement | ||||||
| @ -302,6 +345,8 @@ public: | |||||||
| 		: Statement(_location), m_variable(_variable), m_value(_value) | 		: Statement(_location), m_variable(_variable), m_value(_value) | ||||||
| 	{} | 	{} | ||||||
| 	virtual void accept(ASTVisitor& _visitor) override; | 	virtual void accept(ASTVisitor& _visitor) override; | ||||||
|  | 	virtual ptr<Type> checkTypeRequirements() override; | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
| 	ptr<VariableDeclaration> m_variable; | 	ptr<VariableDeclaration> m_variable; | ||||||
| 	ptr<Expression> m_value; ///< can be missing
 | 	ptr<Expression> m_value; ///< can be missing
 | ||||||
| @ -311,7 +356,9 @@ class Expression : public Statement | |||||||
| { | { | ||||||
| public: | public: | ||||||
| 	Expression(Location const& _location) : Statement(_location) {} | 	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) | 		  m_assigmentOperator(_assignmentOperator), m_rightHandSide(_rightHandSide) | ||||||
| 	{} | 	{} | ||||||
| 	virtual void accept(ASTVisitor& _visitor) override; | 	virtual void accept(ASTVisitor& _visitor) override; | ||||||
|  | 	virtual ptr<Type> checkTypeRequirements() override; | ||||||
| 
 | 
 | ||||||
| 	Token::Value getAssignmentOperator() const { return m_assigmentOperator; } | 	Token::Value getAssignmentOperator() const { return m_assigmentOperator; } | ||||||
| private: | private: | ||||||
| @ -345,6 +393,7 @@ public: | |||||||
| 		  m_subExpression(_subExpression), m_isPrefix(_isPrefix) | 		  m_subExpression(_subExpression), m_isPrefix(_isPrefix) | ||||||
| 	{} | 	{} | ||||||
| 	virtual void accept(ASTVisitor& _visitor) override; | 	virtual void accept(ASTVisitor& _visitor) override; | ||||||
|  | 	virtual ptr<Type> checkTypeRequirements() override; | ||||||
| 
 | 
 | ||||||
| 	Token::Value getOperator() const { return m_operator; } | 	Token::Value getOperator() const { return m_operator; } | ||||||
| 	bool isPrefixOperation() const { return m_isPrefix; } | 	bool isPrefixOperation() const { return m_isPrefix; } | ||||||
| @ -362,12 +411,15 @@ public: | |||||||
| 		: Expression(_location), m_left(_left), m_operator(_operator), m_right(_right) | 		: Expression(_location), m_left(_left), m_operator(_operator), m_right(_right) | ||||||
| 	{} | 	{} | ||||||
| 	virtual void accept(ASTVisitor& _visitor) override; | 	virtual void accept(ASTVisitor& _visitor) override; | ||||||
|  | 	virtual ptr<Type> checkTypeRequirements() override; | ||||||
| 
 | 
 | ||||||
| 	Token::Value getOperator() const { return m_operator; } | 	Token::Value getOperator() const { return m_operator; } | ||||||
| private: | private: | ||||||
| 	ptr<Expression> m_left; | 	ptr<Expression> m_left; | ||||||
| 	Token::Value m_operator; | 	Token::Value m_operator; | ||||||
| 	ptr<Expression> m_right; | 	ptr<Expression> m_right; | ||||||
|  | 
 | ||||||
|  | 	ptr<Type> m_commonType; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// Can be ordinary function call, type cast or struct construction.
 | /// Can be ordinary function call, type cast or struct construction.
 | ||||||
| @ -379,6 +431,7 @@ public: | |||||||
| 		: Expression(_location), m_expression(_expression), m_arguments(_arguments) | 		: Expression(_location), m_expression(_expression), m_arguments(_arguments) | ||||||
| 	{} | 	{} | ||||||
| 	virtual void accept(ASTVisitor& _visitor) override; | 	virtual void accept(ASTVisitor& _visitor) override; | ||||||
|  | 	virtual ptr<Type> checkTypeRequirements() override; | ||||||
| private: | private: | ||||||
| 	ptr<Expression> m_expression; | 	ptr<Expression> m_expression; | ||||||
| 	vecptr<Expression> m_arguments; | 	vecptr<Expression> m_arguments; | ||||||
| @ -393,6 +446,7 @@ public: | |||||||
| 	{} | 	{} | ||||||
| 	virtual void accept(ASTVisitor& _visitor) override; | 	virtual void accept(ASTVisitor& _visitor) override; | ||||||
| 	const ASTString& getMemberName() const { return *m_memberName; } | 	const ASTString& getMemberName() const { return *m_memberName; } | ||||||
|  | 	virtual ptr<Type> checkTypeRequirements() override; | ||||||
| private: | private: | ||||||
| 	ptr<Expression> m_expression; | 	ptr<Expression> m_expression; | ||||||
| 	ptr<ASTString> m_memberName; | 	ptr<ASTString> m_memberName; | ||||||
| @ -406,6 +460,7 @@ public: | |||||||
| 		: Expression(_location), m_base(_base), m_index(_index) | 		: Expression(_location), m_base(_base), m_index(_index) | ||||||
| 	{} | 	{} | ||||||
| 	virtual void accept(ASTVisitor& _visitor) override; | 	virtual void accept(ASTVisitor& _visitor) override; | ||||||
|  | 	virtual ptr<Type> checkTypeRequirements() override; | ||||||
| private: | private: | ||||||
| 	ptr<Expression> m_base; | 	ptr<Expression> m_base; | ||||||
| 	ptr<Expression> m_index; | 	ptr<Expression> m_index; | ||||||
| @ -415,7 +470,6 @@ class PrimaryExpression : public Expression | |||||||
| { | { | ||||||
| public: | public: | ||||||
| 	PrimaryExpression(Location const& _location) : Expression(_location) {} | 	PrimaryExpression(Location const& _location) : Expression(_location) {} | ||||||
| 	virtual void accept(ASTVisitor& _visitor) override; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class Identifier : public PrimaryExpression | class Identifier : public PrimaryExpression | ||||||
| @ -424,27 +478,29 @@ public: | |||||||
| 	Identifier(Location const& _location, ptr<ASTString> const& _name) | 	Identifier(Location const& _location, ptr<ASTString> const& _name) | ||||||
| 		: PrimaryExpression(_location), m_name(_name) {} | 		: PrimaryExpression(_location), m_name(_name) {} | ||||||
| 	virtual void accept(ASTVisitor& _visitor) override; | 	virtual void accept(ASTVisitor& _visitor) override; | ||||||
|  | 	virtual ptr<Type> checkTypeRequirements() override; | ||||||
| 
 | 
 | ||||||
| 	ASTString const& getName() const { return *m_name; } | 	ASTString const& getName() const { return *m_name; } | ||||||
| 	void setReferencedObject(ASTNode& _referencedObject) { m_referencedObject = &_referencedObject; } | 	void setReferencedDeclaration(Declaration& _referencedDeclaration) { m_referencedDeclaration = &_referencedDeclaration; } | ||||||
| 	ASTNode* getReferencedVariable() { return m_referencedObject; } | 	Declaration* getReferencedDeclaration() { return m_referencedDeclaration; } | ||||||
| private: | private: | ||||||
| 	ptr<ASTString> m_name; | 	ptr<ASTString> m_name; | ||||||
| 
 | 
 | ||||||
| 	//! Node the name refers to. Has to be a declaration of some sort.
 | 	//! Declaration the name refers to.
 | ||||||
| 	ASTNode* m_referencedObject; | 	Declaration* m_referencedDeclaration; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class ElementaryTypeNameExpression : public PrimaryExpression | class ElementaryTypeNameExpression : public PrimaryExpression | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	ElementaryTypeNameExpression(Location const& _location, Token::Value _type) | 	ElementaryTypeNameExpression(Location const& _location, Token::Value _typeToken) | ||||||
| 		: PrimaryExpression(_location), m_type(_type) {} | 		: PrimaryExpression(_location), m_typeToken(_typeToken) {} | ||||||
| 	virtual void accept(ASTVisitor& _visitor) override; | 	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: | private: | ||||||
| 	Token::Value m_type; | 	Token::Value m_typeToken; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class Literal : public PrimaryExpression | class Literal : public PrimaryExpression | ||||||
| @ -454,6 +510,7 @@ public: | |||||||
| 		: PrimaryExpression(_location), m_token(_token), m_value(_value) | 		: PrimaryExpression(_location), m_token(_token), m_value(_value) | ||||||
| 	{} | 	{} | ||||||
| 	virtual void accept(ASTVisitor& _visitor) override; | 	virtual void accept(ASTVisitor& _visitor) override; | ||||||
|  | 	virtual ptr<Type> checkTypeRequirements() override; | ||||||
| 
 | 
 | ||||||
| 	Token::Value getToken() const { return m_token; } | 	Token::Value getToken() const { return m_token; } | ||||||
| 	ASTString const& getValue() const { return *m_value; } | 	ASTString const& getValue() const { return *m_value; } | ||||||
|  | |||||||
| @ -32,6 +32,7 @@ namespace dev { | |||||||
| namespace solidity { | namespace solidity { | ||||||
| 
 | 
 | ||||||
| class ASTNode; | class ASTNode; | ||||||
|  | class Declaration; | ||||||
| class ContractDefinition; | class ContractDefinition; | ||||||
| class StructDefinition; | class StructDefinition; | ||||||
| class ParameterList; | class ParameterList; | ||||||
|  | |||||||
| @ -233,7 +233,7 @@ bool ASTPrinter::visit(Identifier& _node) | |||||||
| 
 | 
 | ||||||
| bool ASTPrinter::visit(ElementaryTypeNameExpression& _node) | bool ASTPrinter::visit(ElementaryTypeNameExpression& _node) | ||||||
| { | { | ||||||
| 	writeLine(std::string("ElementaryTypeNameExpression ") + Token::String(_node.getType())); | 	writeLine(std::string("ElementaryTypeNameExpression ") + Token::String(_node.getTypeToken())); | ||||||
| 	printSourcePart(_node); | 	printSourcePart(_node); | ||||||
| 	return goDeeper(); | 	return goDeeper(); | ||||||
| } | } | ||||||
|  | |||||||
| @ -31,10 +31,10 @@ namespace solidity { | |||||||
| 
 | 
 | ||||||
| class NameAndTypeResolver::ScopeHelper { | class NameAndTypeResolver::ScopeHelper { | ||||||
| public: | public: | ||||||
| 	ScopeHelper(NameAndTypeResolver& _resolver, ASTString const& _name, ASTNode& _declaration) | 	ScopeHelper(NameAndTypeResolver& _resolver, Declaration& _declaration) | ||||||
| 		: m_resolver(_resolver) | 		: m_resolver(_resolver) | ||||||
| 	{ | 	{ | ||||||
| 		m_resolver.registerName(_name, _declaration); | 		m_resolver.registerDeclaration(_declaration); | ||||||
| 		m_resolver.enterNewSubScope(_declaration); | 		m_resolver.enterNewSubScope(_declaration); | ||||||
| 	} | 	} | ||||||
| 	~ScopeHelper() | 	~ScopeHelper() | ||||||
| @ -60,16 +60,15 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) | |||||||
| 
 | 
 | ||||||
| void NameAndTypeResolver::handleContract(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()) | 	for (ptr<VariableDeclaration> const& variable : _contract.getStateVariables()) | ||||||
| 		registerName(variable->getName(), *variable); | 		registerVariableDeclarationAndResolveType(*variable); | ||||||
| 	// @todo structs
 |  | ||||||
| 
 | 
 | ||||||
| 	for (ptr<FunctionDefinition> const& function : _contract.getDefinedFunctions()) | 	for (ptr<FunctionDefinition> const& function : _contract.getDefinedFunctions()) | ||||||
| 		handleFunction(*function); | 		handleFunction(*function); | ||||||
| 
 |  | ||||||
| 	// @todo resolve names used in mappings
 |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void NameAndTypeResolver::reset() | void NameAndTypeResolver::reset() | ||||||
| @ -81,30 +80,20 @@ void NameAndTypeResolver::reset() | |||||||
| 
 | 
 | ||||||
| void NameAndTypeResolver::handleFunction(FunctionDefinition& _function) | void NameAndTypeResolver::handleFunction(FunctionDefinition& _function) | ||||||
| { | { | ||||||
| 	ScopeHelper scopeHelper(*this, _function.getName(), _function); | 	ScopeHelper scopeHelper(*this, _function); | ||||||
| 
 | 
 | ||||||
| 	// @todo resolve names used in mappings
 | 	registerVariablesInFunction(_function); | ||||||
| 	for (ptr<VariableDeclaration> const& variable  : _function.getParameters()) | 	resolveReferencesInFunction(*_function.getReturnParameterList(), _function.getBody()); | ||||||
| 		registerName(variable->getName(), *variable); | 	_function.getBody().checkTypeRequirements(); | ||||||
| 	if (_function.hasReturnParameters()) |  | ||||||
| 		for (ptr<VariableDeclaration> const& variable  : _function.getReturnParameters()) |  | ||||||
| 			registerName(variable->getName(), *variable); |  | ||||||
| 	handleFunctionBody(_function.getBody()); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void NameAndTypeResolver::handleFunctionBody(Block& _functionBody) | void NameAndTypeResolver::registerVariablesInFunction(FunctionDefinition& _function) | ||||||
| { |  | ||||||
| 	registerVariablesInFunction(_functionBody); |  | ||||||
| 	resolveReferencesInFunction(_functionBody); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void NameAndTypeResolver::registerVariablesInFunction(Block& _functionBody) |  | ||||||
| { | { | ||||||
| 	class VariableDeclarationFinder : public ASTVisitor { | 	class VariableDeclarationFinder : public ASTVisitor { | ||||||
| 	public: | 	public: | ||||||
| 		VariableDeclarationFinder(NameAndTypeResolver& _resolver) : m_resolver(_resolver) {} | 		VariableDeclarationFinder(NameAndTypeResolver& _resolver) : m_resolver(_resolver) {} | ||||||
| 		virtual bool visit(VariableDeclaration& _variable) override { | 		virtual bool visit(VariableDeclaration& _variable) override { | ||||||
| 			m_resolver.registerName(_variable.getName(), _variable); | 			m_resolver.registerVariableDeclarationAndResolveType(_variable); | ||||||
| 			return false; | 			return false; | ||||||
| 		} | 		} | ||||||
| 	private: | 	private: | ||||||
| @ -112,37 +101,85 @@ void NameAndTypeResolver::registerVariablesInFunction(Block& _functionBody) | |||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	VariableDeclarationFinder declarationFinder(*this); | 	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 { | 	class ReferencesResolver : public ASTVisitor { | ||||||
| 	public: | 	public: | ||||||
| 		ReferencesResolver(NameAndTypeResolver& _resolver) : m_resolver(_resolver) {} | 		ReferencesResolver(NameAndTypeResolver& _resolver, | ||||||
|  | 						   ParameterList& _returnParameters) | ||||||
|  | 			: m_resolver(_resolver), m_returnParameters(_returnParameters) {} | ||||||
| 		virtual bool visit(Identifier& _identifier) override { | 		virtual bool visit(Identifier& _identifier) override { | ||||||
| 			ASTNode* node = m_resolver.getNameFromCurrentScope(_identifier.getName()); | 			Declaration* declaration = m_resolver.getNameFromCurrentScope(_identifier.getName()); | ||||||
| 			if (node == nullptr) | 			if (declaration == nullptr) | ||||||
| 				throw std::exception(); // @todo
 | 				throw std::exception(); // @todo
 | ||||||
| 			_identifier.setReferencedObject(*node); | 			_identifier.setReferencedDeclaration(*declaration); | ||||||
| 			return false; | 			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: | 	private: | ||||||
| 		NameAndTypeResolver& m_resolver; | 		NameAndTypeResolver& m_resolver; | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	ReferencesResolver referencesResolver(*this); | 	UserDefinedTypeNameResolver resolver(*this); | ||||||
| 	_functionBody.accept(referencesResolver); | 	_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
 | 		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); | 	return m_currentScope->resolveName(_name, _recursive); | ||||||
| } | } | ||||||
|  | |||||||
| @ -24,13 +24,15 @@ | |||||||
| 
 | 
 | ||||||
| #include <map> | #include <map> | ||||||
| 
 | 
 | ||||||
|  | #include <boost/noncopyable.hpp> | ||||||
|  | 
 | ||||||
| #include <libsolidity/Scope.h> | #include <libsolidity/Scope.h> | ||||||
| #include <libsolidity/ASTVisitor.h> | #include <libsolidity/ASTVisitor.h> | ||||||
| 
 | 
 | ||||||
| namespace dev { | namespace dev { | ||||||
| namespace solidity { | namespace solidity { | ||||||
| 
 | 
 | ||||||
| class NameAndTypeResolver | class NameAndTypeResolver : private boost::noncopyable | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	NameAndTypeResolver(); | 	NameAndTypeResolver(); | ||||||
| @ -43,12 +45,13 @@ private: | |||||||
| 
 | 
 | ||||||
| 	void handleContract(ContractDefinition& _contract); | 	void handleContract(ContractDefinition& _contract); | ||||||
| 	void handleFunction(FunctionDefinition& _function); | 	void handleFunction(FunctionDefinition& _function); | ||||||
| 	void handleFunctionBody(Block& _functionBody); | 	void registerVariablesInFunction(FunctionDefinition& _function); | ||||||
| 	void registerVariablesInFunction(Block& _functionBody); | 	void resolveReferencesInFunction(ParameterList& _returnParameters, | ||||||
| 	void resolveReferencesInFunction(Block& _functionBody); | 									 Block& _functionBody); | ||||||
| 
 | 
 | ||||||
| 	void registerName(ASTString const& _name, ASTNode& _declaration); | 	void registerVariableDeclarationAndResolveType(VariableDeclaration& _variable); | ||||||
| 	ASTNode* getNameFromCurrentScope(ASTString const& _name, bool _recursive = true); | 	void registerDeclaration(Declaration& _declaration); | ||||||
|  | 	Declaration* getNameFromCurrentScope(ASTString const& _name, bool _recursive = true); | ||||||
| 
 | 
 | ||||||
| 	void enterNewSubScope(ASTNode& _node); | 	void enterNewSubScope(ASTNode& _node); | ||||||
| 	void closeCurrentScope(); | 	void closeCurrentScope(); | ||||||
|  | |||||||
							
								
								
									
										37
									
								
								Parser.cpp
									
									
									
									
									
								
							
							
						
						
									
										37
									
								
								Parser.cpp
									
									
									
									
									
								
							| @ -47,6 +47,8 @@ public: | |||||||
| 
 | 
 | ||||||
| 	void markEndPosition() { m_location.end = m_parser.getEndPosition(); } | 	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.
 | 	/// Set the end position to the one of the given node.
 | ||||||
| 	void setEndPositionFromNode(const ptr<ASTNode>& _node) | 	void setEndPositionFromNode(const ptr<ASTNode>& _node) | ||||||
| 	{ | 	{ | ||||||
| @ -104,7 +106,8 @@ ptr<ContractDefinition> Parser::parseContractDefinition() | |||||||
| 			structs.push_back(parseStructDefinition()); | 			structs.push_back(parseStructDefinition()); | ||||||
| 		} else if (currentToken == Token::IDENTIFIER || currentToken == Token::MAPPING || | 		} else if (currentToken == Token::IDENTIFIER || currentToken == Token::MAPPING || | ||||||
| 				   Token::IsElementaryTypeName(currentToken)) { | 				   Token::IsElementaryTypeName(currentToken)) { | ||||||
| 			stateVariables.push_back(parseVariableDeclaration()); | 			bool const allowVar = false; | ||||||
|  | 			stateVariables.push_back(parseVariableDeclaration(allowVar)); | ||||||
| 			expectToken(Token::SEMICOLON); | 			expectToken(Token::SEMICOLON); | ||||||
| 		} else { | 		} else { | ||||||
| 			throwExpectationError("Function, variable or struct declaration expected."); | 			throwExpectationError("Function, variable or struct declaration expected."); | ||||||
| @ -135,6 +138,11 @@ ptr<FunctionDefinition> Parser::parseFunctionDefinition(bool _isPublic) | |||||||
| 		const bool permitEmptyParameterList = false; | 		const bool permitEmptyParameterList = false; | ||||||
| 		m_scanner->next(); | 		m_scanner->next(); | ||||||
| 		returnParameters = parseParameterList(permitEmptyParameterList); | 		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(); | 	ptr<Block> block = parseBlock(); | ||||||
| 	nodeFactory.setEndPositionFromNode(block); | 	nodeFactory.setEndPositionFromNode(block); | ||||||
| @ -151,7 +159,8 @@ ptr<StructDefinition> Parser::parseStructDefinition() | |||||||
| 	vecptr<VariableDeclaration> members; | 	vecptr<VariableDeclaration> members; | ||||||
| 	expectToken(Token::LBRACE); | 	expectToken(Token::LBRACE); | ||||||
| 	while (m_scanner->getCurrentToken() != Token::RBRACE) { | 	while (m_scanner->getCurrentToken() != Token::RBRACE) { | ||||||
| 		members.push_back(parseVariableDeclaration()); | 		bool const allowVar = false; | ||||||
|  | 		members.push_back(parseVariableDeclaration(allowVar)); | ||||||
| 		expectToken(Token::SEMICOLON); | 		expectToken(Token::SEMICOLON); | ||||||
| 	} | 	} | ||||||
| 	nodeFactory.markEndPosition(); | 	nodeFactory.markEndPosition(); | ||||||
| @ -160,16 +169,16 @@ ptr<StructDefinition> Parser::parseStructDefinition() | |||||||
| 	return nodeFactory.createNode<StructDefinition>(name, members); | 	return nodeFactory.createNode<StructDefinition>(name, members); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ptr<VariableDeclaration> Parser::parseVariableDeclaration() | ptr<VariableDeclaration> Parser::parseVariableDeclaration(bool _allowVar) | ||||||
| { | { | ||||||
| 	ASTNodeFactory nodeFactory(*this); | 	ASTNodeFactory nodeFactory(*this); | ||||||
| 
 | 
 | ||||||
| 	ptr<TypeName> type = parseTypeName(); | 	ptr<TypeName> type = parseTypeName(_allowVar); | ||||||
| 	nodeFactory.markEndPosition(); | 	nodeFactory.markEndPosition(); | ||||||
| 	return nodeFactory.createNode<VariableDeclaration>(type, expectIdentifierToken()); | 	return nodeFactory.createNode<VariableDeclaration>(type, expectIdentifierToken()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ptr<TypeName> Parser::parseTypeName() | ptr<TypeName> Parser::parseTypeName(bool _allowVar) | ||||||
| { | { | ||||||
| 	ptr<TypeName> type; | 	ptr<TypeName> type; | ||||||
| 	Token::Value token = m_scanner->getCurrentToken(); | 	Token::Value token = m_scanner->getCurrentToken(); | ||||||
| @ -177,7 +186,8 @@ ptr<TypeName> Parser::parseTypeName() | |||||||
| 		type = ASTNodeFactory(*this).createNode<ElementaryTypeName>(token); | 		type = ASTNodeFactory(*this).createNode<ElementaryTypeName>(token); | ||||||
| 		m_scanner->next(); | 		m_scanner->next(); | ||||||
| 	} else if (token == Token::VAR) { | 	} else if (token == Token::VAR) { | ||||||
| 		type = ASTNodeFactory(*this).createNode<TypeName>(); | 		if (!_allowVar) | ||||||
|  | 			throwExpectationError("Expected explicit type name."); | ||||||
| 		m_scanner->next(); | 		m_scanner->next(); | ||||||
| 	} else if (token == Token::MAPPING) { | 	} else if (token == Token::MAPPING) { | ||||||
| 		type = parseMapping(); | 		type = parseMapping(); | ||||||
| @ -206,24 +216,26 @@ ptr<Mapping> Parser::parseMapping() | |||||||
| 	m_scanner->next(); | 	m_scanner->next(); | ||||||
| 
 | 
 | ||||||
| 	expectToken(Token::ARROW); | 	expectToken(Token::ARROW); | ||||||
| 	ptr<TypeName> valueType = parseTypeName(); | 	bool const allowVar = false; | ||||||
|  | 	ptr<TypeName> valueType = parseTypeName(allowVar); | ||||||
| 	nodeFactory.markEndPosition(); | 	nodeFactory.markEndPosition(); | ||||||
| 	expectToken(Token::RPAREN); | 	expectToken(Token::RPAREN); | ||||||
| 
 | 
 | ||||||
| 	return nodeFactory.createNode<Mapping>(keyType, valueType); | 	return nodeFactory.createNode<Mapping>(keyType, valueType); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ptr<ParameterList> Parser::parseParameterList(bool _permitEmpty) | ptr<ParameterList> Parser::parseParameterList(bool _allowEmpty) | ||||||
| { | { | ||||||
| 	ASTNodeFactory nodeFactory(*this); | 	ASTNodeFactory nodeFactory(*this); | ||||||
| 
 | 
 | ||||||
| 	vecptr<VariableDeclaration> parameters; | 	vecptr<VariableDeclaration> parameters; | ||||||
| 	expectToken(Token::LPAREN); | 	expectToken(Token::LPAREN); | ||||||
| 	if (!_permitEmpty || m_scanner->getCurrentToken() != Token::RPAREN) { | 	if (!_allowEmpty || m_scanner->getCurrentToken() != Token::RPAREN) { | ||||||
| 		parameters.push_back(parseVariableDeclaration()); | 		bool const allowVar = false; | ||||||
|  | 		parameters.push_back(parseVariableDeclaration(allowVar)); | ||||||
| 		while (m_scanner->getCurrentToken() != Token::RPAREN) { | 		while (m_scanner->getCurrentToken() != Token::RPAREN) { | ||||||
| 			expectToken(Token::COMMA); | 			expectToken(Token::COMMA); | ||||||
| 			parameters.push_back(parseVariableDeclaration()); | 			parameters.push_back(parseVariableDeclaration(allowVar)); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	nodeFactory.markEndPosition(); | 	nodeFactory.markEndPosition(); | ||||||
| @ -328,7 +340,8 @@ ptr<WhileStatement> Parser::parseWhileStatement() | |||||||
| ptr<VariableDefinition> Parser::parseVariableDefinition() | ptr<VariableDefinition> Parser::parseVariableDefinition() | ||||||
| { | { | ||||||
| 	ASTNodeFactory nodeFactory(*this); | 	ASTNodeFactory nodeFactory(*this); | ||||||
| 	ptr<VariableDeclaration> variable = parseVariableDeclaration(); | 	bool const allowVar = true; | ||||||
|  | 	ptr<VariableDeclaration> variable = parseVariableDeclaration(allowVar); | ||||||
| 	ptr<Expression> value; | 	ptr<Expression> value; | ||||||
| 	if (m_scanner->getCurrentToken() == Token::ASSIGN) { | 	if (m_scanner->getCurrentToken() == Token::ASSIGN) { | ||||||
| 		m_scanner->next(); | 		m_scanner->next(); | ||||||
|  | |||||||
							
								
								
									
										6
									
								
								Parser.h
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								Parser.h
									
									
									
									
									
								
							| @ -47,10 +47,10 @@ private: | |||||||
| 	ptr<ContractDefinition> parseContractDefinition(); | 	ptr<ContractDefinition> parseContractDefinition(); | ||||||
| 	ptr<FunctionDefinition> parseFunctionDefinition(bool _isPublic); | 	ptr<FunctionDefinition> parseFunctionDefinition(bool _isPublic); | ||||||
| 	ptr<StructDefinition> parseStructDefinition(); | 	ptr<StructDefinition> parseStructDefinition(); | ||||||
| 	ptr<VariableDeclaration> parseVariableDeclaration(); | 	ptr<VariableDeclaration> parseVariableDeclaration(bool _allowVar); | ||||||
| 	ptr<TypeName> parseTypeName(); | 	ptr<TypeName> parseTypeName(bool _allowVar); | ||||||
| 	ptr<Mapping> parseMapping(); | 	ptr<Mapping> parseMapping(); | ||||||
| 	ptr<ParameterList> parseParameterList(bool _permitEmpty = true); | 	ptr<ParameterList> parseParameterList(bool _allowEmpty = true); | ||||||
| 	ptr<Block> parseBlock(); | 	ptr<Block> parseBlock(); | ||||||
| 	ptr<Statement> parseStatement(); | 	ptr<Statement> parseStatement(); | ||||||
| 	ptr<IfStatement> parseIfStatement(); | 	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 <map> | ||||||
| 
 | 
 | ||||||
|  | #include <boost/noncopyable.hpp> | ||||||
|  | 
 | ||||||
| #include <libsolidity/ASTForward.h> | #include <libsolidity/ASTForward.h> | ||||||
| 
 | 
 | ||||||
| namespace dev { | namespace dev { | ||||||
| @ -33,29 +35,15 @@ class Scope | |||||||
| { | { | ||||||
| public: | public: | ||||||
| 	explicit Scope(Scope* _outerScope = nullptr) : m_outerScope(_outerScope) {} | 	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.
 | 	/// it was not yet declared.
 | ||||||
| 	bool registerName(ASTString const& _name, ASTNode& _declaration) | 	bool registerDeclaration(Declaration& _declaration); | ||||||
| 	{ | 	Declaration* resolveName(ASTString const& _name, bool _recursive = false) const; | ||||||
| 		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; |  | ||||||
| 	} |  | ||||||
| 	Scope* getOuterScope() const { return m_outerScope; } | 	Scope* getOuterScope() const { return m_outerScope; } | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
| 	Scope* m_outerScope; | 	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, "=init_const", 2)               /* AST-use only. */  \ | ||||||
| 	T(INIT_CONST_LEGACY, "=init_const_legacy", 2) /* AST-use only. */  \ | 	T(INIT_CONST_LEGACY, "=init_const_legacy", 2) /* AST-use only. */  \ | ||||||
| 	T(ASSIGN, "=", 2)                                                  \ | 	T(ASSIGN, "=", 2)                                                  \ | ||||||
|  | 	/* The following have to be in exactly the same order as the simple binary operators*/ \ | ||||||
| 	T(ASSIGN_BIT_OR, "|=", 2)                                          \ | 	T(ASSIGN_BIT_OR, "|=", 2)                                          \ | ||||||
| 	T(ASSIGN_BIT_XOR, "^=", 2)                                         \ | 	T(ASSIGN_BIT_XOR, "^=", 2)                                         \ | ||||||
| 	T(ASSIGN_BIT_AND, "&=", 2)                                         \ | 	T(ASSIGN_BIT_AND, "&=", 2)                                         \ | ||||||
| @ -117,7 +118,6 @@ namespace solidity { | |||||||
| 	T(SHL, "<<", 11)                                                   \ | 	T(SHL, "<<", 11)                                                   \ | ||||||
| 	T(SAR, ">>", 11)                                                   \ | 	T(SAR, ">>", 11)                                                   \ | ||||||
| 	T(SHR, ">>>", 11)                                                  \ | 	T(SHR, ">>>", 11)                                                  \ | ||||||
| 	T(ROR, "rotate right", 11) /* only used by Crankshaft */           \ |  | ||||||
| 	T(ADD, "+", 12)                                                    \ | 	T(ADD, "+", 12)                                                    \ | ||||||
| 	T(SUB, "-", 12)                                                    \ | 	T(SUB, "-", 12)                                                    \ | ||||||
| 	T(MUL, "*", 13)                                                    \ | 	T(MUL, "*", 13)                                                    \ | ||||||
| @ -181,7 +181,9 @@ namespace solidity { | |||||||
| 	K(WHILE, "while", 0)                                               \ | 	K(WHILE, "while", 0)                                               \ | ||||||
| 	K(WITH, "with", 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(INT, "int", 0)                                                   \ | ||||||
| 	K(INT32, "int32", 0)                                               \ | 	K(INT32, "int32", 0)                                               \ | ||||||
| 	K(INT64, "int64", 0)                                               \ | 	K(INT64, "int64", 0)                                               \ | ||||||
| @ -274,7 +276,7 @@ public: | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	static bool IsTruncatingBinaryOp(Value op) { | 	static bool IsTruncatingBinaryOp(Value op) { | ||||||
| 		return BIT_OR <= op && op <= ROR; | 		return BIT_OR <= op && op <= SHR; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	static bool IsCompareOp(Value op) { | 	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) { | 	static bool IsBitOp(Value op) { | ||||||
| 		return (BIT_OR <= op && op <= SHR) || op == BIT_NOT; | 		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