//
// Copyright (c) 2006, Brian Frank and Andy Frank
// Licensed under the Academic Free License version 3.0
//
// History:
// 4 Jan 06 Brian Frank Creation
//
**
** Type defines the contract of an Obj by the slots its supports.
** Types model the inheritance relationships and provide a mapping
** for all the slots both inherited and declared. You can create
** new types at runtime via the `Type.makeDynamic` constructor.
**
class Type
{
//////////////////////////////////////////////////////////////////////////
// Management
//////////////////////////////////////////////////////////////////////////
**
** Find a Type by it's qualified name "pod::Type". If the type
** doesn't exist and checked is false then return null, otherwise
** throw UnknownTypeErr.
**
static Type find(Str qname, Bool checked := true)
**
** Find all the types annotated with the specified facet name/value
** pair. The facet name must be declared as an indexed facet
** by an installed pod, otherwise Err is thrown. Return an empty
** list of no matches found.
**
** If 'facetVal' is a 'Type', then you may pass 'true' for 'options'
** to check 'facetVals' inheritance hierarchy.
**
** See [Facet Indexing]`docLang::TypeDatabase#facetIndexing` for details.
**
static Type[] findByFacet(Str facetName, Obj facetVal, Obj options := null)
//////////////////////////////////////////////////////////////////////////
// Constructor
//////////////////////////////////////////////////////////////////////////
**
** Make a dynamic type which implements the specified list of existing
** types. Only one 'class' type may be specified and it must be the
** first item in the list. All other types must be mixins. None of
** the 'supers' may be dynamic, abstract, final, or const.
**
** Refer to [Dynamic Types]`docLang::DynamicTypes` for more details.
**
** NOTE: creating dynamics using mixins is not supported yet.
**
new makeDynamic(Type[] supers, Str:Obj facets := null)
//////////////////////////////////////////////////////////////////////////
// Naming
//////////////////////////////////////////////////////////////////////////
**
** Parent pod which defines this type. For parameterized types derived
** from List, Map, or Func, this method always returns the sys pod.
** Return null if dynamic type.
**
** Examples:
** Str.type.pod => sys
** acme::Foo.type.pod => acme
** acme::Foo[].type.pod => sys
**
Pod pod()
**
** Simple name of the type such as "Str". For parameterized types derived
** from List, Map, or Func, this method always returns "List", "Map",
** or "Func" respectively. Return "dynamic" if dynamic type.
**
** Examples:
** Str.type.name => "Str"
** acme::Foo.type.name => "Foo"
** acme::Foo[].type.name => "List"
**
Str name()
**
** Qualified name formatted as "pod::name". For parameterized
** types derived from List, Map, or Func, this method always returns
** "sys::List", "sys::Map", or "sys::Func" respectively. Return
** "dynamic" if dynamic type.
**
** Examples:
** Str.type.qname => "sys::Str"
** acme::Foo.type.qname => "acme::Foo"
** acme::Foo[].type.qname => "sys::List"
**
Str qname()
**
** Return the formal signature of this type. In the case of non-parameterized
** types the signature is the same as qname. Return "dynamic" if dynamic type.
** For parameterized types derived from List, Map, or Func the signature uses
** the following special syntax:
** List => V[]
** Map => [K:V]
** Func => |A,B...->R|
**
** Examples:
** Str.type.signature => "sys::Str"
** Int[].type.signature => "sys::Int[]"
** Int:Str.type.signature => "[sys::Int:sys::Str]"
** Str:Buf[].type.signature => [sys::Str:sys::Buf[]]
** |Float x->Bool|.type.signature => "|sys::Float->sys::Bool|"
** |Float x, Int y|.type.signature => |sys::Float,sys::Int->sys::Void|
**
Str signature()
//////////////////////////////////////////////////////////////////////////
// Inheritance
//////////////////////////////////////////////////////////////////////////
**
** The direct super class of this type (null for Obj).
** Return sys::Obj for all mixin types.
**
** Examples:
** Obj.type.base => null
** Int.type.base => sys::Num
** OutStream.type.base => sys::Obj
**
Type base()
**
** Return the mixins directly implemented by this type.
**
** Examples:
** Obj.type.mixins => [,]
** Buf.type.mixins => [sys::InStream, sys::OutStream]
** OutStream.type.mixins => [,]
**
Type[] mixins()
**
** Return a recursive flattened list of all the types this type
** inherits from. The result list always includes this type itself.
** The result of this method represents the complete list of types
** implemented by this type - instances of this type are assignable
** to any type in this list. All types (including mixins) will
** include sys::Obj in this list.
**
** Examples:
** Obj.type.inheritance => [sys::Obj]
** Int.type.inheritance => [sys::Int, sys::Num, sys::Obj]
**
Type[] inheritance()
**
** Does this type implement the specified type. If true, then
** this type is assignable to the specified type (although the
** converse is not necessarily true). This method provides the
** same semantics as the 'is' operator, but between two types
** rather than an instance and a type. All types (including
** mixin types) fit 'sys::Obj'.
**
** Example:
** Float.type.fits(Float.type) => true
** Float.type.fits(Num.type) => true
** Float.type.fits(Obj.type) => true
** Float.type.fits(Str.type) => false
** Obj.type.fits(Float.type) => false
**
Bool fits(Type t)
//////////////////////////////////////////////////////////////////////////
// Generics
//////////////////////////////////////////////////////////////////////////
**
** A generic type contains slot signatures which may be parameterized - for
** example Map's key and value types are generic as K and V. Fan supports
** three built-in generic types: List, Map, and Func. A parameterized
** type such as Str[] is not a generic type (all of its generic parameters
** have been filled in). User defined generic types are not supported in Fan.
**
** Examples:
** Str.type.isGeneric => false
** List.type.isGeneric => true
** Str[].type.isGeneric => false
**
Bool isGeneric()
**
** If this is a parameterized type, then return the map of names to
** types. If this is not a parameterized type return an empty map.
**
** Examples:
** Str.type.params => [:]
** Str[].type.params => ["V":Str, "L":Str[]]
** Int:Slot.type.params => ["K":Int, "V":Slot, "M":Int:Slot]
** |Int x, Float y->Bool|.type.params => ["A":Int, "B":Float, "R":Bool]
**
Str:Type params()
**
** If this is a generic type, then dynamically create a new parameterized
** type with the specified name to type map. If this type is not generic
** then throw UnsupportedErr. Throw ArgErr if params fails to specify
** the required parameters:
** List => V required
** Map => K, V required
** Func => R required, A-H optional
**
** Examples:
** List.type.parameterize(["V":Bool.type]) => Bool[]
** Map.type.parameterize(["K":Str.type, "V":Obj.type]) => Str:Obj
**
Type parameterize(Str:Type params)
**
** Convenience for List.type.parameterize(["V":this])
**
** Examples:
** Int.type.toListOf => Int[]
** Str[].type.toListOf => Str[][]
**
Type toListOf()
//////////////////////////////////////////////////////////////////////////
// Flags
//////////////////////////////////////////////////////////////////////////
**
** Return if this is a dynamic type which was created at
** runtime via the `Type.makeDynamic` method.
**
Bool isDynamic()
**
** Return if this Type is abstract and cannot be instantiated. This
** method will always return true if the type is a mixin.
**
Bool isAbstract()
**
** Return if this Type is a class (as opposed to enum or mixin)
**
Bool isClass()
**
** Return if this is a const class which means instances of this
** class are immutable.
**
Bool isConst()
**
** Return if this Type is an Enum type.
**
Bool isEnum()
**
** Return if this Type is marked final which means it may not be subclassed.
**
Bool isFinal()
**
** Return if this Type has internal protection scope.
**
Bool isInternal()
**
** Return if this Type is a mixin type and cannot be instantiated.
**
Bool isMixin()
**
** Return if this Type has public protection scope.
**
Bool isPublic()
**
** Return if this Type was generated by the compiler.
**
Bool isSynthetic()
//////////////////////////////////////////////////////////////////////////
// Slots
//////////////////////////////////////////////////////////////////////////
**
** List of the all defined fields (including inherited fields).
**
Field[] fields()
**
** List of the all defined methods (including inherited methods).
**
Method[] methods()
**
** List of the all defined slots, both fields and methods (including
** inherited slots).
**
Slot[] slots()
**
** Convenience for (Field)slot(name, checked)
**
Field field(Str name, Bool checked := true)
**
** Convenience for (Method)slot(name, checked)
**
Method method(Str name, Bool checked := true)
**
** Lookup a slot by name. If the slot doesn't exist and checked
** is false then return null, otherwise throw UnknownSlotErr.
**
Slot slot(Str name, Bool checked := true)
**
** Add a new slot to a dynamic type. If not a dynamic
** type or a duplicate slot name exists, then throw Err.
**
** Refer to [Dynamic Types]`docLang::DynamicTypes` for more details.
**
Void add(Slot slot)
**
** Remove a slot from a dynamic type. If not a dynamic
** type or the slot is inherited, then throw Err.
**
** Refer to [Dynamic Types]`docLang::DynamicTypes` for more details.
**
Void remove(Slot slot)
**
** Create a new instance of this Type using a public constructor
** called "make". Throw Err if public constructor "make" is
** not available.
**
Obj make(Obj[] args := null)
//////////////////////////////////////////////////////////////////////////
// Facets
//////////////////////////////////////////////////////////////////////////
**
** Return all the facets defined for this slot or an empty map
** if no facets are defined. If 'inherited' is true, then this method
** returns a map of all the facets of this type's `inheritance`. If
** looking up a facet by name, then use the `facet` method which will
** provide better performance. See the [Facets Doc]`docLang::Facets`
** for details.
**
Str:Obj facets(Bool inherited := false)
**
** Get a facet by name, or return the 'def' is the facet is not defined.
** If 'inherited' is true, then this type's `inheritance` chain is
** searched. See the [Facets Doc]`docLang::Facets` for details.
**
Obj facet(Str name, Obj def := null, Bool inherited := false)
//////////////////////////////////////////////////////////////////////////
// Documentation
//////////////////////////////////////////////////////////////////////////
**
** Return the raw fandoc for this type or null if not available.
** If there is additional documentation meta-data available it is
** included an the start of the string as a series of "@name=value"
** lines.
**
Str doc()
//////////////////////////////////////////////////////////////////////////
// Conversion
//////////////////////////////////////////////////////////////////////////
**
** Always return signature().
**
override Str toStr()
**
** If this type is not dynamic, then return this. If this
** type is dynamic, then NotImmutableErr is thrown. This method
** must be used whenever setting a const Type field.
**
Type toImmutable()
}