Fantom

 

class

compilerJs::JsPod

sys::Obj
  compilerJs::JsNode
    compilerJs::JsPod
//
// Copyright (c) 2009, Brian Frank and Andy Frank
// Licensed under the Academic Free License version 3.0
//
// History:
//   10 Jul 09  Andy Frank  Creation
//

using compiler

**
** JsPod
**
class JsPod : JsNode
{
  new make(CompilerSupport s, PodDef pod, TypeDef[] defs) : super(s)
  {
    this.name  = pod.name
    this.types = JsType[,]

    // build native map
    this.natives = Str:File[:]
    s.compiler.jsFiles?.each |f| { natives[f.name] = f }
    jsOutput := s.compiler.input.output === CompilerOutputMode.js

    defs.each |TypeDef def|
    {
      // we inline closures directly, so no need to generate
      // anonymous types like we do in Java and .NET
      if (def.isClosure) return

      // TODO FIXIT: do we still need this?
      if (def.qname.contains("\$Cvars"))
      {
        echo("WARN: Cvar class: $def.qname")
        return
      }

      // check for @js facet or explicit js output
      if (def.hasMarkerFacet("sys::js") || jsOutput)
        types.add(JsType(s,def))
    }
  }

  override Void write(JsWriter out)
  {
    // define namespace
    out.w("fan.$name = {};").nl

    // write types
    types.each |t|
    {
      t.write(out)
      if (t.hasNatives) writePeer(out, t)
    }

    // write type info
    writeTypeInfo(out)

    // write static init
    types.each |t| { t.writeStatic(out) }

    // write remaining natives
    natives.each |f|
    {
      in := f.in
      out.minify(in)
      in.close
    }
  }

  Void writePeer(JsWriter out, JsType t)
  {
    key  := "${t.peer.name}Peer.js"
    file := natives[key]
    if (file == null)
    {
      support.err("Missing native impl for $t.sig", Loc("${t.name}.fan"))
    }
    else
    {
      in := file.in
      out.minify(in)
      in.close
      natives.remove(key)
    }
  }

  Void writeTypeInfo(JsWriter out)
  {
    out.w("fan.${name}.\$pod = fan.sys.Pod.\$add('$name');").nl
    out.w("with (fan.${name}.\$pod)").nl
    out.w("{").nl

    // filter out synthetic types from reflection
    reflect := types.findAll |t| { !t.isSynthetic }

    // write all types first
    reflect.each |t|
    {
      adder  := t.isMixin ? "\$am" : "\$at"
      base   := "$t.base.pod::$t.base.name"
      mixins := t.mixins.join(",") |m| { "'$m.pod::$m.name'" }
      flags  := t->flags
      out.w("  fan.${t.pod}.${t.name}.\$type = $adder('$t.name','$base',[$mixins],$flags);").nl
    }

    // then write slot info
    reflect.each |t|
    {
      if (t.fields.isEmpty && t.methods.isEmpty) return
      //out.w("  \$$i")
      out.w("  fan.${t.pod}.${t.name}.\$type")
      t.fields.each |f| { out.w(".\$af('$f.name',$f.flags,'$f.ftype.sig')") }
      t.methods.each |m| { if (!m.isFieldAccessor) out.w(".\$am('$m.name',$m.flags)") }
      out.w(";").nl
    }
    out.w("}").nl
  }

  Str name           // pod name
  JsType[] types     // types in this pod
  Str:File natives   // natives
}