2014-10-13 16:22:15 +00:00
/*
2014-10-16 12:08:54 +00:00
This file is part of cpp - ethereum .
2014-10-13 16:22:15 +00:00
2014-10-16 12:08:54 +00:00
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 .
2014-10-13 16:22:15 +00:00
2014-10-16 12:08:54 +00:00
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 .
2014-10-13 16:22:15 +00:00
2014-10-16 12:08:54 +00:00
You should have received a copy of the GNU General Public License
along with cpp - ethereum . If not , see < http : //www.gnu.org/licenses/>.
2014-10-13 16:22:15 +00:00
*/
/**
* @ author Christian < c @ ethdev . com >
* @ date 2014
* Solidity data types
*/
# pragma once
# include <memory>
# include <string>
2014-11-20 09:19:43 +00:00
# include <map>
2014-10-13 16:22:15 +00:00
# include <boost/noncopyable.hpp>
2014-10-20 10:41:56 +00:00
# include <libdevcore/Common.h>
2014-11-05 13:20:56 +00:00
# include <libsolidity/Exceptions.h>
2014-10-20 12:00:37 +00:00
# include <libsolidity/ASTForward.h>
2014-10-13 16:22:15 +00:00
# include <libsolidity/Token.h>
2014-10-16 12:08:54 +00:00
namespace dev
{
namespace solidity
{
2014-10-13 16:22:15 +00:00
2014-12-09 17:46:18 +00:00
// @todo realMxN, dynamic strings, text, arrays
2014-10-13 16:22:15 +00:00
2014-11-20 09:19:43 +00:00
class Type ; // forward
2014-12-12 15:49:26 +00:00
class FunctionType ; // forward
2014-11-25 13:43:23 +00:00
using TypePointer = std : : shared_ptr < Type const > ;
using TypePointers = std : : vector < TypePointer > ;
2014-11-20 09:19:43 +00:00
/**
* List of members of a type .
*/
class MemberList
{
public :
using MemberMap = std : : map < std : : string , TypePointer > ;
MemberList ( ) { }
explicit MemberList ( MemberMap const & _members ) : m_memberTypes ( _members ) { }
TypePointer getMemberType ( std : : string const & _name ) const
{
auto it = m_memberTypes . find ( _name ) ;
2014-11-25 13:43:23 +00:00
return it ! = m_memberTypes . end ( ) ? it - > second : TypePointer ( ) ;
2014-11-20 09:19:43 +00:00
}
MemberMap : : const_iterator begin ( ) const { return m_memberTypes . begin ( ) ; }
MemberMap : : const_iterator end ( ) const { return m_memberTypes . end ( ) ; }
private :
MemberMap m_memberTypes ;
} ;
2014-10-28 15:51:26 +00:00
/**
* Abstract base class that forms the root of the type hierarchy .
*/
2014-10-16 21:49:45 +00:00
class Type : private boost : : noncopyable
2014-10-13 16:22:15 +00:00
{
public :
2014-10-16 12:08:54 +00:00
enum class Category
{
2014-11-21 18:14:56 +00:00
INTEGER , BOOL , REAL , STRING , CONTRACT , STRUCT , FUNCTION , MAPPING , VOID , TYPE , MAGIC
2014-10-13 16:22:15 +00:00
} ;
2014-10-23 15:06:12 +00:00
///@{
///@name Factory functions
/// Factory functions that convert an AST @ref TypeName to a Type.
2014-12-06 01:19:10 +00:00
static std : : shared_ptr < Type const > fromElementaryTypeName ( Token : : Value _typeToken ) ;
static std : : shared_ptr < Type const > fromUserDefinedTypeName ( UserDefinedTypeName const & _typeName ) ;
static std : : shared_ptr < Type const > fromMapping ( Mapping const & _typeName ) ;
static std : : shared_ptr < Type const > fromFunction ( FunctionDefinition const & _function ) ;
2014-10-23 15:06:12 +00:00
/// @}
2014-10-13 16:22:15 +00:00
2014-11-04 12:24:35 +00:00
/// Auto-detect the proper type for a literal. @returns an empty pointer if the literal does
/// not fit any type.
2014-12-06 01:19:10 +00:00
static std : : shared_ptr < Type const > forLiteral ( Literal const & _literal ) ;
2014-10-13 16:22:15 +00:00
virtual Category getCategory ( ) const = 0 ;
2014-10-20 10:41:56 +00:00
virtual bool isImplicitlyConvertibleTo ( Type const & _other ) const { return * this = = _other ; }
2014-10-20 11:02:06 +00:00
virtual bool isExplicitlyConvertibleTo ( Type const & _convertTo ) const
2014-10-16 12:08:54 +00:00
{
return isImplicitlyConvertibleTo ( _convertTo ) ;
}
2014-10-15 16:50:15 +00:00
virtual bool acceptsBinaryOperator ( Token : : Value ) const { return false ; }
virtual bool acceptsUnaryOperator ( Token : : Value ) const { return false ; }
2014-10-16 15:57:27 +00:00
2014-10-20 10:41:56 +00:00
virtual bool operator = = ( Type const & _other ) const { return getCategory ( ) = = _other . getCategory ( ) ; }
virtual bool operator ! = ( Type const & _other ) const { return ! this - > operator = = ( _other ) ; }
2014-10-30 17:15:25 +00:00
/// @returns number of bytes used by this type when encoded for CALL, or 0 if the encoding
/// is not a simple big-endian encoding or the type cannot be stored on the stack.
virtual unsigned getCalldataEncodedSize ( ) const { return 0 ; }
2014-11-07 01:06:37 +00:00
/// @returns number of bytes required to hold this value in storage.
/// For dynamically "allocated" types, it returns the size of the statically allocated head,
virtual u256 getStorageSize ( ) const { return 1 ; }
2014-11-20 17:33:23 +00:00
/// Returns true if the type can be stored in storage.
virtual bool canBeStored ( ) const { return true ; }
2014-11-10 16:31:09 +00:00
/// Returns false if the type cannot live outside the storage, i.e. if it includes some mapping.
virtual bool canLiveOutsideStorage ( ) const { return true ; }
2014-11-21 18:14:56 +00:00
/// Returns true if the type can be stored as a value (as opposed to a reference) on the stack,
/// i.e. it behaves differently in lvalue context and in value context.
virtual bool isValueType ( ) const { return false ; }
2014-11-25 17:23:39 +00:00
virtual unsigned getSizeOnStack ( ) const { return 1 ; }
2014-10-30 17:15:25 +00:00
2014-11-20 09:19:43 +00:00
/// Returns the list of all members of this type. Default implementation: no members.
virtual MemberList const & getMembers ( ) const { return EmptyMemberList ; }
/// Convenience method, returns the type of the given named member or an empty pointer if no such member exists.
2014-11-25 13:43:23 +00:00
TypePointer getMemberType ( std : : string const & _name ) const { return getMembers ( ) . getMemberType ( _name ) ; }
2014-11-20 09:19:43 +00:00
2014-10-16 15:57:27 +00:00
virtual std : : string toString ( ) const = 0 ;
2014-11-05 13:20:56 +00:00
virtual u256 literalValue ( Literal const & ) const
{
BOOST_THROW_EXCEPTION ( InternalCompilerError ( ) < < errinfo_comment ( " Literal value requested "
" for type without literals. " ) ) ;
}
2014-11-20 09:19:43 +00:00
protected :
/// Convenience object used when returning an empty member list.
static const MemberList EmptyMemberList ;
2014-10-13 16:22:15 +00:00
} ;
2014-10-28 15:51:26 +00:00
/**
* Any kind of integer type including hash and address .
*/
2014-10-16 21:49:45 +00:00
class IntegerType : public Type
2014-10-13 16:22:15 +00:00
{
public :
2014-10-16 12:08:54 +00:00
enum class Modifier
{
2014-10-13 16:22:15 +00:00
UNSIGNED , SIGNED , HASH , ADDRESS
} ;
2014-10-16 15:57:27 +00:00
virtual Category getCategory ( ) const override { return Category : : INTEGER ; }
2014-10-13 16:22:15 +00:00
2014-11-04 12:24:35 +00:00
/// @returns the smallest integer type for the given literal or an empty pointer
/// if no type fits.
2014-12-06 01:19:10 +00:00
static std : : shared_ptr < IntegerType const > smallestTypeForLiteral ( std : : string const & _literal ) ;
2014-10-13 16:22:15 +00:00
explicit IntegerType ( int _bits , Modifier _modifier = Modifier : : UNSIGNED ) ;
virtual bool isImplicitlyConvertibleTo ( Type const & _convertTo ) const override ;
2014-10-20 11:02:06 +00:00
virtual bool isExplicitlyConvertibleTo ( Type const & _convertTo ) const override ;
2014-10-13 16:22:15 +00:00
virtual bool acceptsBinaryOperator ( Token : : Value _operator ) const override ;
virtual bool acceptsUnaryOperator ( Token : : Value _operator ) const override ;
2014-10-20 10:41:56 +00:00
virtual bool operator = = ( Type const & _other ) const override ;
2014-11-20 17:33:23 +00:00
virtual unsigned getCalldataEncodedSize ( ) const override { return m_bits / 8 ; }
2014-11-21 18:14:56 +00:00
virtual bool isValueType ( ) const override { return true ; }
virtual MemberList const & getMembers ( ) const { return isAddress ( ) ? AddressMemberList : EmptyMemberList ; }
2014-10-30 17:15:25 +00:00
2014-10-16 15:57:27 +00:00
virtual std : : string toString ( ) const override ;
2014-10-30 00:20:32 +00:00
virtual u256 literalValue ( Literal const & _literal ) const override ;
2014-10-16 15:57:27 +00:00
2014-10-13 16:22:15 +00:00
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 ; }
2014-10-20 12:00:37 +00:00
2014-10-13 16:22:15 +00:00
private :
int m_bits ;
Modifier m_modifier ;
2014-11-21 18:14:56 +00:00
static const MemberList AddressMemberList ;
2014-10-13 16:22:15 +00:00
} ;
2014-12-09 17:46:18 +00:00
/**
* String type with fixed length , up to 32 bytes .
*/
class StaticStringType : public Type
{
public :
virtual Category getCategory ( ) const override { return Category : : STRING ; }
/// @returns the smallest string type for the given literal or an empty pointer
/// if no type fits.
static std : : shared_ptr < StaticStringType > smallestTypeForLiteral ( std : : string const & _literal ) ;
StaticStringType ( int _bytes ) ;
virtual bool isImplicitlyConvertibleTo ( Type const & _convertTo ) const override ;
virtual bool operator = = ( Type const & _other ) const override ;
virtual unsigned getCalldataEncodedSize ( ) const override { return m_bytes ; }
virtual bool isValueType ( ) const override { return true ; }
virtual std : : string toString ( ) const override { return " string " + dev : : toString ( m_bytes ) ; }
virtual u256 literalValue ( Literal const & _literal ) const override ;
int getNumBytes ( ) const { return m_bytes ; }
private :
int m_bytes ;
} ;
2014-10-28 15:51:26 +00:00
/**
* The boolean type .
*/
2014-10-16 21:49:45 +00:00
class BoolType : public Type
2014-10-13 16:22:15 +00:00
{
public :
2014-12-11 13:12:49 +00:00
BoolType ( ) { }
2014-10-13 16:22:15 +00:00
virtual Category getCategory ( ) const { return Category : : BOOL ; }
2014-10-20 11:02:06 +00:00
virtual bool isExplicitlyConvertibleTo ( Type const & _convertTo ) const override ;
2014-10-13 16:22:15 +00:00
virtual bool acceptsBinaryOperator ( Token : : Value _operator ) const override
2014-10-16 12:08:54 +00:00
{
return _operator = = Token : : AND | | _operator = = Token : : OR ;
}
2014-10-13 16:22:15 +00:00
virtual bool acceptsUnaryOperator ( Token : : Value _operator ) const override
2014-10-16 12:08:54 +00:00
{
return _operator = = Token : : NOT | | _operator = = Token : : DELETE ;
}
2014-10-20 10:41:56 +00:00
2014-10-30 17:15:25 +00:00
virtual unsigned getCalldataEncodedSize ( ) const { return 1 ; }
2014-11-21 18:14:56 +00:00
virtual bool isValueType ( ) const override { return true ; }
2014-10-30 17:15:25 +00:00
2014-10-16 15:57:27 +00:00
virtual std : : string toString ( ) const override { return " bool " ; }
2014-10-30 00:20:32 +00:00
virtual u256 literalValue ( Literal const & _literal ) const override ;
2014-10-13 16:22:15 +00:00
} ;
2014-10-28 15:51:26 +00:00
/**
* The type of a contract instance , there is one distinct type for each contract definition .
*/
2014-10-16 21:49:45 +00:00
class ContractType : public Type
2014-10-13 16:22:15 +00:00
{
public :
2014-10-16 15:57:27 +00:00
virtual Category getCategory ( ) const override { return Category : : CONTRACT ; }
2014-10-16 21:49:45 +00:00
ContractType ( ContractDefinition const & _contract ) : m_contract ( _contract ) { }
2014-11-20 17:33:23 +00:00
/// Contracts can be converted to themselves and to addresses.
virtual bool isExplicitlyConvertibleTo ( Type const & _convertTo ) const override ;
2014-10-20 10:41:56 +00:00
virtual bool operator = = ( Type const & _other ) const override ;
2014-11-20 17:33:23 +00:00
virtual u256 getStorageSize ( ) const override ;
2014-12-04 18:38:24 +00:00
virtual bool isValueType ( ) const override { return true ; }
2014-11-20 17:33:23 +00:00
virtual std : : string toString ( ) const override ;
2014-10-16 15:57:27 +00:00
2014-12-04 18:38:24 +00:00
virtual MemberList const & getMembers ( ) const override ;
2014-12-12 15:49:26 +00:00
/// Returns the function type of the constructor. Note that the location part of the function type
/// is not used, as this type cannot be the type of a variable or expression.
std : : shared_ptr < FunctionType const > const & getConstructorType ( ) const ;
2014-12-04 18:38:24 +00:00
unsigned getFunctionIndex ( std : : string const & _functionName ) const ;
2014-10-13 16:22:15 +00:00
private :
ContractDefinition const & m_contract ;
2014-12-12 15:49:26 +00:00
/// Type of the constructor, @see getConstructorType. Lazily initialized.
mutable std : : shared_ptr < FunctionType const > m_constructorType ;
2014-12-04 18:38:24 +00:00
/// List of member types, will be lazy-initialized because of recursive references.
mutable std : : unique_ptr < MemberList > m_members ;
2014-10-13 16:22:15 +00:00
} ;
2014-10-28 15:51:26 +00:00
/**
* The type of a struct instance , there is one distinct type per struct definition .
*/
2014-10-16 21:49:45 +00:00
class StructType : public Type
2014-10-13 16:22:15 +00:00
{
public :
2014-10-16 15:57:27 +00:00
virtual Category getCategory ( ) const override { return Category : : STRUCT ; }
2014-10-16 21:49:45 +00:00
StructType ( StructDefinition const & _struct ) : m_struct ( _struct ) { }
2014-10-13 16:22:15 +00:00
virtual bool acceptsUnaryOperator ( Token : : Value _operator ) const override
2014-10-16 12:08:54 +00:00
{
return _operator = = Token : : DELETE ;
}
2014-10-20 12:00:37 +00:00
2014-10-20 10:41:56 +00:00
virtual bool operator = = ( Type const & _other ) const override ;
2014-11-20 17:33:23 +00:00
virtual u256 getStorageSize ( ) const override ;
virtual bool canLiveOutsideStorage ( ) const override ;
2014-11-25 17:23:39 +00:00
virtual unsigned getSizeOnStack ( ) const override { return 1 ; /*@todo*/ }
2014-11-13 00:12:57 +00:00
virtual std : : string toString ( ) const override ;
2014-11-20 09:19:43 +00:00
virtual MemberList const & getMembers ( ) const override ;
u256 getStorageOffsetOfMember ( std : : string const & _name ) const ;
2014-10-16 15:57:27 +00:00
2014-10-13 16:22:15 +00:00
private :
StructDefinition const & m_struct ;
2014-11-20 09:19:43 +00:00
/// List of member types, will be lazy-initialized because of recursive references.
mutable std : : unique_ptr < MemberList > m_members ;
2014-10-13 16:22:15 +00:00
} ;
2014-10-28 15:51:26 +00:00
/**
2014-11-25 13:43:23 +00:00
* The type of a function , identified by its ( return ) parameter types .
* @ todo the return parameters should also have names , i . e . return parameters should be a struct
* type .
2014-10-28 15:51:26 +00:00
*/
2014-10-16 21:49:45 +00:00
class FunctionType : public Type
2014-10-13 16:22:15 +00:00
{
public :
2014-11-25 17:23:39 +00:00
/// The meaning of the value(s) on the stack referencing the function:
/// INTERNAL: jump tag, EXTERNAL: contract address + function index,
2014-12-10 22:01:40 +00:00
/// BARE: contract address (non-abi contract call)
2014-11-25 17:23:39 +00:00
/// OTHERS: special virtual function, nothing on the stack
2014-12-10 22:01:40 +00:00
enum class Location { INTERNAL , EXTERNAL , SEND , SHA3 , SUICIDE , ECRECOVER , SHA256 , RIPEMD160 , BARE } ;
2014-11-25 17:23:39 +00:00
2014-10-16 15:57:27 +00:00
virtual Category getCategory ( ) const override { return Category : : FUNCTION ; }
2014-12-04 18:38:24 +00:00
explicit FunctionType ( FunctionDefinition const & _function , bool _isInternal = true ) ;
2014-11-25 17:23:39 +00:00
FunctionType ( TypePointers const & _parameterTypes , TypePointers const & _returnParameterTypes ,
Location _location = Location : : INTERNAL ) :
m_parameterTypes ( _parameterTypes ) , m_returnParameterTypes ( _returnParameterTypes ) ,
m_location ( _location ) { }
2014-10-13 16:22:15 +00:00
2014-11-25 13:43:23 +00:00
TypePointers const & getParameterTypes ( ) const { return m_parameterTypes ; }
TypePointers const & getReturnParameterTypes ( ) const { return m_returnParameterTypes ; }
2014-10-20 12:00:37 +00:00
2014-10-20 10:41:56 +00:00
virtual bool operator = = ( Type const & _other ) const override ;
2014-11-13 00:12:57 +00:00
virtual std : : string toString ( ) const override ;
2014-11-20 17:33:23 +00:00
virtual bool canBeStored ( ) const override { return false ; }
virtual u256 getStorageSize ( ) const override { BOOST_THROW_EXCEPTION ( InternalCompilerError ( ) < < errinfo_comment ( " Storage size of non-storable function type requested. " ) ) ; }
virtual bool canLiveOutsideStorage ( ) const override { return false ; }
2014-11-25 17:23:39 +00:00
virtual unsigned getSizeOnStack ( ) const override ;
2014-12-06 01:39:58 +00:00
Location const & getLocation ( ) const { return m_location ; }
2015-01-07 01:27:05 +00:00
std : : string getCanonicalSignature ( ) const ;
2014-10-20 10:41:56 +00:00
2014-10-13 16:22:15 +00:00
private :
2014-11-25 13:43:23 +00:00
TypePointers m_parameterTypes ;
TypePointers m_returnParameterTypes ;
2014-11-25 17:23:39 +00:00
Location m_location ;
2014-10-13 16:22:15 +00:00
} ;
2014-10-28 15:51:26 +00:00
/**
* The type of a mapping , there is one distinct type per key / value type pair .
*/
2014-10-16 21:49:45 +00:00
class MappingType : public Type
2014-10-13 16:22:15 +00:00
{
public :
2014-10-16 15:57:27 +00:00
virtual Category getCategory ( ) const override { return Category : : MAPPING ; }
2014-11-25 13:43:23 +00:00
MappingType ( TypePointer const & _keyType , TypePointer const & _valueType ) :
2014-11-10 16:31:09 +00:00
m_keyType ( _keyType ) , m_valueType ( _valueType ) { }
2014-10-16 15:57:27 +00:00
2014-10-20 10:41:56 +00:00
virtual bool operator = = ( Type const & _other ) const override ;
2014-11-13 00:12:57 +00:00
virtual std : : string toString ( ) const override ;
2014-11-20 17:33:23 +00:00
virtual bool canLiveOutsideStorage ( ) const override { return false ; }
2014-10-20 10:41:56 +00:00
2014-12-12 15:49:26 +00:00
TypePointer const & getKeyType ( ) const { return m_keyType ; }
TypePointer const & getValueType ( ) const { return m_valueType ; }
2014-11-13 00:12:57 +00:00
2014-10-13 16:22:15 +00:00
private :
2014-11-25 13:43:23 +00:00
TypePointer m_keyType ;
TypePointer m_valueType ;
2014-10-13 16:22:15 +00:00
} ;
2014-10-28 15:51:26 +00:00
/**
* The void type , can only be implicitly used as the type that is returned by functions without
* return parameters .
*/
2014-10-16 21:49:45 +00:00
class VoidType : public Type
2014-10-13 16:22:15 +00:00
{
public :
2014-10-16 15:57:27 +00:00
virtual Category getCategory ( ) const override { return Category : : VOID ; }
2014-10-13 16:22:15 +00:00
VoidType ( ) { }
2014-10-20 10:41:56 +00:00
2014-10-16 15:57:27 +00:00
virtual std : : string toString ( ) const override { return " void " ; }
2014-11-20 17:33:23 +00:00
virtual bool canBeStored ( ) const override { return false ; }
virtual u256 getStorageSize ( ) const override { BOOST_THROW_EXCEPTION ( InternalCompilerError ( ) < < errinfo_comment ( " Storage size of non-storable void type requested. " ) ) ; }
virtual bool canLiveOutsideStorage ( ) const override { return false ; }
2014-11-25 17:23:39 +00:00
virtual unsigned getSizeOnStack ( ) const override { return 0 ; }
2014-10-13 16:22:15 +00:00
} ;
2014-10-28 15:51:26 +00:00
/**
* The type of a type reference . The type of " uint32 " when used in " a = uint32(2) " is an example
* of a TypeType .
*/
2014-10-16 21:49:45 +00:00
class TypeType : public Type
2014-10-13 16:22:15 +00:00
{
public :
2014-10-16 15:57:27 +00:00
virtual Category getCategory ( ) const override { return Category : : TYPE ; }
2014-11-25 13:43:23 +00:00
TypeType ( TypePointer const & _actualType ) : m_actualType ( _actualType ) { }
2014-10-20 12:00:37 +00:00
2014-11-25 13:43:23 +00:00
TypePointer const & getActualType ( ) const { return m_actualType ; }
2014-10-13 16:22:15 +00:00
2014-10-20 10:41:56 +00:00
virtual bool operator = = ( Type const & _other ) const override ;
2014-11-20 17:33:23 +00:00
virtual bool canBeStored ( ) const override { return false ; }
virtual u256 getStorageSize ( ) const override { BOOST_THROW_EXCEPTION ( InternalCompilerError ( ) < < errinfo_comment ( " Storage size of non-storable type type requested. " ) ) ; }
virtual bool canLiveOutsideStorage ( ) const override { return false ; }
2014-10-16 15:57:27 +00:00
virtual std : : string toString ( ) const override { return " type( " + m_actualType - > toString ( ) + " ) " ; }
2014-10-13 16:22:15 +00:00
private :
2014-11-25 13:43:23 +00:00
TypePointer m_actualType ;
2014-10-13 16:22:15 +00:00
} ;
2014-11-24 12:23:58 +00:00
/**
* Special type for magic variables ( block , msg , tx ) , similar to a struct but without any reference
* ( it always references a global singleton by name ) .
*/
class MagicType : public Type
{
public :
2014-11-26 12:19:17 +00:00
enum class Kind { BLOCK , MSG , TX } ;
2014-11-24 12:23:58 +00:00
virtual Category getCategory ( ) const override { return Category : : MAGIC ; }
MagicType ( Kind _kind ) ;
virtual bool operator = = ( Type const & _other ) const ;
virtual bool canBeStored ( ) const override { return false ; }
virtual bool canLiveOutsideStorage ( ) const override { return true ; }
2014-11-25 17:23:39 +00:00
virtual unsigned getSizeOnStack ( ) const override { return 0 ; }
2014-11-24 12:23:58 +00:00
virtual MemberList const & getMembers ( ) const override { return m_members ; }
virtual std : : string toString ( ) const override ;
private :
Kind m_kind ;
MemberList m_members ;
} ;
2014-10-16 12:08:54 +00:00
}
}