//
// Copyright (c) 2006, Brian Frank and Andy Frank
// Licensed under the Academic Free License version 3.0
//
// History:
//   23 Sep 06  Brian Frank  Creation
//

**
** OrderByInheritance orders the list of TypeDefs from top to bottom
** such that any inherited types are guaranteed to be positioned first
** in the types list.  During this process we check for duplicate type
** names and cyclic inheritance.
**
class OrderByInheritance : CompilerStep
{

//////////////////////////////////////////////////////////////////////////
// Constructor
//////////////////////////////////////////////////////////////////////////

  new make(Compiler compiler)
    : super(compiler)
  {
    ordered = TypeDef[,]
    processing = Str:TypeDef[:]
    todo = Str:TypeDef[:]
  }

//////////////////////////////////////////////////////////////////////////
// Run
//////////////////////////////////////////////////////////////////////////

  override Void run()
  {
    log.debug("OrderByInheritance")
    ordered.capacity = types.size

    // create the todo map which is our working input,
    // check for duplicate type names in this loop
    types.each |TypeDef t|
    {
      todo[t.qname] = t
    }
    bombIfErr

    // process each type in order
    types.each |TypeDef t| { process(t) }
    bombIfErr

    // use ordered types for rest of pipeline
    if (ordered.size != compiler.types.size) throw Err("Internal error")
    compiler.types = ordered
  }

//////////////////////////////////////////////////////////////////////////
// Process
//////////////////////////////////////////////////////////////////////////

  private Void process(CType t)
  {
    // check that this type is still in the todo
    // list, otherwise we've already processed it
    // or it is imported from another pod
    def := todo[t.qname]
    if (def == null) return

    // check if this guy is in the processing queue,
    // in which case we have cyclic inheritance
    if (processing.containsKey(def.qname))
    {
      err("Cyclic inheritance for '$def.name'", def.loc)
      return
    }
    processing[def.qname] = def

    // process inheritance
    if (def.base != null) process(def.base)
    def.mixins.each |CType m| { process(m) }

    // now that is has been processed, removed it the
    // todo map and add it to the ordered result list
    processing.remove(def.qname)
    todo.remove(def.qname)
    ordered.add(def)
  }

//////////////////////////////////////////////////////////////////////////
// Fields
//////////////////////////////////////////////////////////////////////////

  Str:TypeDef processing  // map of qname to typse being processed
  Str:TypeDef todo        // map of qname to types left to process
  TypeDef[] ordered       // ordered result list
}