//
// Copyright (c) 2006, Brian Frank and Andy Frank
// Licensed under the Academic Free License version 3.0
//
// History:
//    3 Sep 05  Brian Frank  Creation
//   18 May 06  Brian Frank  Ported from Java to Fan
//

**
** Compiler manages the top level process of the compiler pipeline.
** There are a couple different "pipelines" used to accomplish
** various twists on compiling Fantom code (from memory, files, etc).
** The pipelines are implemented as discrete CompilerSteps.
** As the steps are executed, the Compiler instance itself stores
** the state as we move from files -> ast -> resolved ast -> code.
**
** Error reporting is managed via the Compiler.errors list.  If
** the compiler encounters problems it accumulates the errors as
** CompileExceptions in this list, then raises the first exception
** to the caller.  All errors go thru the CompilerSupport.err()
** methods for logging.  To log an error and continue we simply
** call err().  To fail fast, we code something like: throw err().
** Or at the end of a step we may call bombIfErr() which throws the
** first exception if any errors have accumulated.
**
class Compiler
{

//////////////////////////////////////////////////////////////////////////
// Construction
//////////////////////////////////////////////////////////////////////////

  **
  ** Construct with reasonable defaults
  **
  new make(CompilerInput input)
  {
    if ((Obj?)input.log == null)
      throw ArgErr("CompilerInput.log is null")

    this.input      = input
    this.log        = input.log
    this.errs       = CompilerErr[,]
    this.warns      = CompilerErr[,]
    this.depends    = CDepend[,]
    this.wrappers   = Str:CField[:]
    this.localeDefs = LocaleLiteralExpr[,]
  }

//////////////////////////////////////////////////////////////////////////
// Compile
//////////////////////////////////////////////////////////////////////////

  **
  ** Compile fan source code from the configured CompilerInput
  ** into a fan pod and return the resulting CompilerOutput.
  **
  virtual CompilerOutput compile()
  {
    log.info("Compile [${input.podName}]")
    log.indent

    try
    {
      frontend
      backend
    }
    catch (CompilerErr e)
    {
      if (errs.isEmpty) CompilerSupport(this).errReport(e)
      throw e
    }
    finally cleanup

    log.unindent
    return output
  }

  **
  ** Execute front-end compiler pipeline
  **
  virtual Void frontend()
  {
    InitInput(this).run
    Tokenize(this).run
    ResolveDepends(this).run
    ScanForUsingsAndTypes(this).run
    ResolveImports(this).run
    Parse(this).run
    OrderByInheritance(this).run
    CheckInheritance(this).run
    Inherit(this).run
    DefaultCtor(this).run
    InitEnum(this).run
    InitFacet(this).run
    InitClosures(this).run
    Normalize(this).run
    ResolveExpr(this).run
    CheckErrors(this).run
    CheckParamDefs(this).run
    LocaleProps(this).run
    CompileJs(this).run
    ClosureVars(this).run
    ClosureToImmutable(this).run
    ConstChecks(this).run
  }

  **
  ** Execute back-end compiler pipeline
  **
  virtual Void backend()
  {
    Assemble(this).run
    GenerateOutput(this).run
  }

  **
  ** Guaranteed cleanup of resources
  **
  private Void cleanup()
  {
    try
    {
      ns.cleanup
    }
    catch (Err e) e.trace
  }

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

  CompilerInput input       // ctor
  CompilerLog log           // ctor
  CompilerErr[] errs        // accumulated errors
  CompilerErr[] warns       // accumulated warnings
  CDepend[] depends         // InitInput
  CNamespace? ns            // InitInput
  PodDef? pod               // InitInput
  Bool isSys := false       // InitInput; are we compiling sys itself
  File[]? srcFiles          // InitInput
  File[]? resFiles          // InitInput
  File[]? jsFiles           // InitInput
  File[]? jsPropsFiles      // InitInput
  TypeDef[]? types          // Parse
  ClosureExpr[]? closures   // Parse
  Str:CField wrappers       // ClosureVars
  Obj? jsPod                // CompileJs (JavaScript AST)
  Str? js                   // CompileJs (JavaScript code)
  Str? jsSourceMap          // CompileJs (JavaScript sourcemap)
  Str? cjs                  // CompileJs (JavaScript code (CommonJS))
  Str? cjsSourceMap         // CompileJs (JavaScript sourcemap (CommonJs))
  Str? esm                  // CompileJs (JavaScript code (ESM))
  Str? tsDecl               // CompileJs (TypeScript declaration file)
  LocaleLiteralExpr[] localeDefs  // ResolveExpr.resolveLocaleLiteral
  Str? localeProps          // LocaleProps
  FPod? fpod                // Assemble
  CompilerOutput? output    // GenerateOutput

}