logo

class

compiler::Assembler

sys::Obj
  compiler::CompilerSupport
    compiler::Assembler : compiler::FConst
//
// Copyright (c) 2006, Brian Frank and Andy Frank
// Licensed under the Academic Free License version 3.0
//
// History:
//   15 Sep 05  Brian Frank  Creation
//

**
** Assembler assembles all the TypeDefs into their fcode representation.
**
class Assembler : CompilerSupport, FConst
{

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

  new make(Compiler compiler)
    : super(compiler)
  {
  }

//////////////////////////////////////////////////////////////////////////
// Assemble
//////////////////////////////////////////////////////////////////////////

  FPod assemblePod()
  {
    fpod = FPod.make(null, compiler.pod.name, null)

    fpod.name    = compiler.input.podName
    fpod.version = compiler.input.version
    fpod.depends = compiler.input.depends
    fpod.fattrs  = assemblePodAttrs(fpod)

    fpod.ftypes = FType[,]
    types.each |TypeDef t|
    {
      fpod.ftypes.add(assembleType(t))
    }

    return fpod
  }

  private FAttr[] assemblePodAttrs(FPod fpod)
  {
    input := compiler.input
    asm := AttrAsm.make(compiler, fpod)

    buf := Buf.make
    buf.writeI2(4 + input.podFacets.size)
    buf.writeI2(fpod.addName("description")); buf.writeUtf(input.description.toCode)
    buf.writeI2(fpod.addName("buildHost"));   buf.writeUtf(Sys.hostName.toCode)
    buf.writeI2(fpod.addName("buildUser"));   buf.writeUtf(Sys.userName.toCode)
    buf.writeI2(fpod.addName("buildTime"));   buf.writeUtf(DateTime.now.toStr.toCode)
    input.podFacets.each |Obj val, Str key|
    {
      buf.writeI2(fpod.addName(key));
      buf.writeUtf(Buf.make.writeObj(val).flip.readAllStr)
    }
    asm.add(FConst.FacetsAttr, buf)

    return asm.attrs
  }

  private FType assembleType(TypeDef def)
  {
    t := FType.make(fpod)

    t.hollow = false
    t.flags  = def.flags
    t.self   = typeRef(def)
    t.fbase  = (def.base == null) ? -1 : typeRef(def.base)
    def.mixins.map(t.fmixins = Int[,]) |CType m->Obj| { return typeRef(m) }
    def.fieldDefs.map(t.ffields = FField[,]) |FieldDef f->Obj| { return assembleField(t, f) }
    def.methodDefs.map(t.fmethods = FMethod[,]) |MethodDef m->Obj| { return assembleMethod(t, m) }

    attrs := AttrAsm.make(compiler, fpod)
    if (compiler.input.mode == CompilerInputMode.str)
      attrs.sourceFile(def.location.fileUri)
    else
      attrs.sourceFile(def.location.filename)
    attrs.lineNumber(def.location.line)
    attrs.facets(def.facets)
    t.fattrs = attrs.attrs

    return t
  }

  FField assembleField(FType fparent, FieldDef def)
  {
    f := FField.make(fparent)
    f.nameIndex = name(def.name)
    f.flags     = def.flags
    f.typeRef   = typeRef(def.fieldType)

    attrs := AttrAsm.make(compiler, fpod)
    attrs.lineNumber(def.location.line)
    attrs.facets(def.facets)
    f.fattrs = attrs.attrs

    return f;
  }

  FMethod assembleMethod(FType fparent, MethodDef def)
  {
    attrs := AttrAsm.make(compiler, fpod)

    m := FMethod.make(fparent)

    m.nameIndex    = name(def.name)
    m.flags        = def.flags
    m.ret          = typeRef(def.ret)
    m.inheritedRet = typeRef(def.inheritedReturnType)
    m.paramCount   = def.params.size
    m.localCount   = def.vars.size - def.params.size

    m.vars = FMethodVar[,]
    def.vars.map(m.vars) |MethodVar v->Obj|
    {
      f := FMethodVar.make(m)
      f.nameIndex = name(v.name)
      f.typeRef   = typeRef(v.ctype)
      f.flags     = v.flags
      if (v.paramDef != null)
      {
        f.defNameIndex = name(ParamDefaultAttr)
        f.def = assembleExpr(v.paramDef.def)
      }
      return f
    }

    m.code = assembleCode(def, attrs)

    attrs.lineNumber(def.location.line)
    attrs.facets(def.facets)
    m.fattrs = attrs.attrs

    return m;
  }

//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////

  Int typeRef(CType type)
  {
    return fpod.addTypeRef(type)
  }

  Int name(Str val)
  {
    return fpod.addName(val)
  }

  private Buf assembleCode(MethodDef def , AttrAsm attrs)
  {
    block := def.code
    if (block == null) return null

    asm := CodeAsm.make(compiler, def.location, fpod)
    if (def.ctorChain != null) asm.expr(def.ctorChain)
    asm.block(block)

    if (asm.errCount > 0) attrs.add(ErrTableAttr, asm.finishErrTable)
    if (asm.lineCount > 0) attrs.add(LineNumbersAttr, asm.finishLines)

    return asm.finishCode
  }

  private Buf assembleExpr(Expr expr)
  {
    if (expr == null) return null
    asm := CodeAsm.make(compiler, expr.location, fpod)
    asm.expr(expr)
    return asm.finishCode
  }

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

  FPod fpod
}