logo
class

compiler::FPod

sys::Obj
  compiler::FPod

Mixin: compiler::CPod, compiler::FConst
   1  //
   2  // Copyright (c) 2006, Brian Frank and Andy Frank
   3  // Licensed under the Academic Free License version 3.0
   4  //
   5  // History:
   6  //   26 Dec 05  Brian Frank  Creation
   7  //   19 Aug 06  Brian Frank  Ported from Java to Fan
   8  //
   9  
  10  **
  11  ** FPod is the read/write fcode representation of sys::Pod.  It's main job in
  12  ** life is to manage all the pod-wide constant tables for names, literals,
  13  ** type/slot references and type/slot definitions.
  14  **
  15  final class FPod : CPod, FConst
  16  {
  17  
  18  //////////////////////////////////////////////////////////////////////////
  19  // Constructor
  20  //////////////////////////////////////////////////////////////////////////
  21  
  22    new make(FPodNamespace ns, Str podName, Zip zip)
  23    {
  24      this.ns         = ns
  25      this.name       = podName
  26      this.zip        = zip
  27      this.names      = FTable.makeStrs(this)
  28      this.typeRefs   = FTable.makeTypeRefs(this)
  29      this.fieldRefs  = FTable.makeFieldRefs(this)
  30      this.methodRefs = FTable.makeMethodRefs(this)
  31      this.ints       = FTable.makeInts(this)
  32      this.floats     = FTable.makeFloats(this)
  33      this.strs       = FTable.makeStrs(this)
  34      this.durations  = FTable.makeDurations(this)
  35      this.uris       = FTable.makeStrs(this)
  36    }
  37  
  38  //////////////////////////////////////////////////////////////////////////
  39  // CPod
  40  //////////////////////////////////////////////////////////////////////////
  41  
  42    override CType resolveType(Str name, Bool checked)
  43    {
  44      t := ftypesByName[name]
  45      if (t != null) return t
  46      if (checked) throw UnknownTypeErr.make("${this.name}::$name")
  47      return null
  48    }
  49  
  50    override CType[] types()
  51    {
  52      return ftypes
  53    }
  54  
  55    CType toType(Int index)
  56    {
  57      if (index == 0xffff) return null
  58      r := typeRef(index)
  59  
  60      Str sig
  61      if (r.isGenericInstance)
  62        sig = r.sig
  63      else
  64        sig = n(r.podName) + "::" + n(r.typeName)
  65      return ns.resolveType(sig)
  66    }
  67  
  68    CType[] resolveTypes(Int[] indexes)
  69    {
  70      ctypes := CType[,]
  71      ctypes.capacity = indexes.size
  72      indexes.map(ctypes) |Int index->Obj| { return toType(index) }
  73      return ctypes
  74    }
  75  
  76  //////////////////////////////////////////////////////////////////////////
  77  // Convenience
  78  //////////////////////////////////////////////////////////////////////////
  79  
  80    Str n(Int index)                { return (Str)names[index] }
  81    FTypeRef typeRef(Int index)     { return (FTypeRef)typeRefs[index] }
  82    FFieldRef fieldRef(Int index)   { return (FFieldRef)fieldRefs[index] }
  83    FMethodRef methodRef(Int index) { return (FMethodRef)methodRefs[index] }
  84    Int integer(Int index)          { return (Int)ints[index] }
  85    Float float(Int index)          { return (Float)floats[index] }
  86    Str str(Int index)              { return (Str)strs[index] }
  87    Duration duration(Int index)    { return (Duration)durations[index] }
  88    Str uri(Int index)              { return (Str)uris[index] }
  89  
  90    Str typeRefStr(Int index) { return typeRef(index).format(this) }
  91    Str fieldRefStr(Int index) { return fieldRef(index).format(this) }
  92    Str methodRefStr(Int index) { return methodRef(index).format(this) }
  93  
  94  //////////////////////////////////////////////////////////////////////////
  95  // Compile Utils
  96  //////////////////////////////////////////////////////////////////////////
  97  
  98    Int addName(Str val)
  99    {
 100      return names.add(val)
 101    }
 102  
 103    Int addTypeRef(CType t)
 104    {
 105      p   := addName(t.pod.name)
 106      n   := addName(t.name)
 107      sig := t.isParameterized ? t.signature : ""
 108      return typeRefs.add(FTypeRef.make(p, n, sig))
 109    }
 110  
 111    Int addFieldRef(CField field)
 112    {
 113      p := addTypeRef(field.parent)
 114      n := addName(field.name)
 115      t := addTypeRef(field.fieldType)
 116      return fieldRefs.add(FFieldRef.make(p, n, t))
 117    }
 118  
 119    Int addMethodRef(CMethod method, Int argCount := null)
 120    {
 121      // if this is a generic instantiation, we want to call
 122      // against the original generic method using it's raw
 123      // types, since that is how the system library will
 124      // implement the type
 125      if (method.isParameterized) method = method.generic
 126  
 127      p := addTypeRef(method.parent)
 128      n := addName(method.name)
 129      r := addTypeRef(method.inheritedReturnType.raw)  // CLR can't deal with covariance
 130      params := (Int[])method.params.map(Int[,]) |CParam x->Obj| { return addTypeRef(x.paramType.raw) }
 131      if (argCount != null && argCount < params.size)
 132        params = params[0...argCount]
 133      return methodRefs.add(FMethodRef.make(p, n, r, params))
 134    }
 135  
 136    Void dump()
 137    {
 138      p := FPrinter.make(this)
 139      p.showCode = true
 140      p.ftypes
 141    }
 142  
 143  //////////////////////////////////////////////////////////////////////////
 144  // Read
 145  //////////////////////////////////////////////////////////////////////////
 146  
 147    **
 148    ** Read the just the pod and type meta-data, but
 149    ** not each type's full definition
 150    **
 151    Void read()
 152    {
 153      echo("     FPod.reading [$zip.file]...")
 154  
 155      // read tables
 156      names.read(in(`/names.def`))
 157      typeRefs.read(in(`/typeRefs.def`))
 158      fieldRefs.read(in(`/fieldRefs.def`))
 159      methodRefs.read(in(`/methodRefs.def`))
 160      ints.read(in(`/ints.def`))
 161      floats.read(in(`/floats.def`))
 162      strs.read(in(`/strs.def`))
 163      durations.read(in(`/durations.def`))
 164      uris.read(in(`/uris.def`))
 165  
 166      // read pod meta-data
 167      in := in(`/pod.def`)
 168      readPodMeta(in)
 169      in.close
 170  
 171      // read type meta-data
 172      in = this.in(`/types.def`)
 173      ftypes = FType[,]
 174      ftypesByName = Str:FType[:]
 175      in.readU2.times |,|
 176      {
 177        ftype := FType.make(this).readMeta(in)
 178        ftypes.add(ftype)
 179        ftypesByName[ftype.name] = ftype
 180        ns.types[ftype.qname] = ftype
 181      }
 182      in.close
 183    }
 184  
 185    **
 186    ** Read the entire pod into memory (including full type specifications)
 187    **
 188    Void readFully()
 189    {
 190      ftypes.each |FType t| { t.read }
 191    }
 192  
 193  //////////////////////////////////////////////////////////////////////////
 194  // Write
 195  //////////////////////////////////////////////////////////////////////////
 196  
 197    **
 198    ** Write the tables and type files out to zip storage
 199    **
 200    Void write(Zip zip := this.zip)
 201    {
 202      this.zip = zip
 203  
 204      // write non-empty tables
 205      if (!names.isEmpty)      names.write(out(`/names.def`))
 206      if (!typeRefs.isEmpty)   typeRefs.write(out(`/typeRefs.def`))
 207      if (!fieldRefs.isEmpty)  fieldRefs.write(out(`/fieldRefs.def`))
 208      if (!methodRefs.isEmpty) methodRefs.write(out(`/methodRefs.def`))
 209      if (!ints.isEmpty)       ints.write(out(`/ints.def`))
 210      if (!floats.isEmpty)     floats.write(out(`/floats.def`))
 211      if (!strs.isEmpty)       strs.write(out(`/strs.def`))
 212      if (!durations.isEmpty)  durations.write(out(`/durations.def`))
 213      if (!uris.isEmpty)       uris.write(out(`/uris.def`))
 214  
 215      // write pod meta-data
 216      out := out(`/pod.def`)
 217      writePodMeta(out)
 218      out.close
 219  
 220      // write type meta-data
 221      out = this.out(`/types.def`)
 222      out.writeI2(ftypes.size)
 223      ftypes.each |FType t| { t.writeMeta(out) }
 224      out.close
 225  
 226      // write type full fcode
 227      ftypes.each |FType t| { t.write }
 228    }
 229  
 230  //////////////////////////////////////////////////////////////////////////
 231  // Pod Meta
 232  //////////////////////////////////////////////////////////////////////////
 233  
 234    Void readPodMeta(InStream in)
 235    {
 236      if (in.readU4 != FCodeMagic)
 237        throw IOErr.make("Invalid fcode magic number")
 238      if (in.readU4 != FCodeVersion)
 239        throw IOErr.make("Unsupported fcode version")
 240  
 241      name = in.readUtf
 242      version = Version.fromStr(in.readUtf)
 243      depends = Depend[,]
 244      in.readU1.times |,| { depends.add(Depend.fromStr(in.readUtf)) }
 245      fattrs = FAttr[,]
 246      in.readU2.times |,| { fattrs.add(FAttr.make.read(in)) }
 247    }
 248  
 249    Void writePodMeta(OutStream out)
 250    {
 251      out.writeI4(FConst.FCodeMagic)
 252      out.writeI4(FConst.FCodeVersion)
 253      out.writeUtf(name)
 254      out.writeUtf(version.toStr)
 255      out.write(depends.size)
 256      depends.each |Depend d| { out.writeUtf(d.toStr) }
 257      out.writeI2(fattrs.size)
 258      fattrs.each |FAttr a| { a.write(out) }
 259    }
 260  
 261  //////////////////////////////////////////////////////////////////////////
 262  // Zip
 263  //////////////////////////////////////////////////////////////////////////
 264  
 265    **
 266    ** Get input stream to read the specified file from zip storage.
 267    **
 268    InStream in(Uri uri)
 269    {
 270      file := zip.contents[uri]
 271      if (file == null) return null
 272      return file.in
 273    }
 274  
 275    **
 276    ** Get output stream to write the specified file to zip storage.
 277    **
 278    OutStream out(Uri uri) { return zip.writeNext(uri) }
 279  
 280  //////////////////////////////////////////////////////////////////////////
 281  // Fields
 282  //////////////////////////////////////////////////////////////////////////
 283  
 284    override Namespace ns     // compiler's namespace
 285    override Str name         // pod's unique name
 286    override Version version  // pod version
 287    Depend[] depends          // pod dependencies
 288    FAttr[] fattrs            // pod attributes
 289    Zip zip                   // zipped storage
 290    FType[] ftypes            // pod's declared types
 291    FTable names              // identifier names: foo
 292    FTable typeRefs           // types refs:   [pod,type,sig]
 293    FTable fieldRefs          // fields refs:  [parent,name,type]
 294    FTable methodRefs         // methods refs: [parent,name,ret,params]
 295    FTable ints               // Int literals
 296    FTable floats             // Float literals
 297    FTable strs               // Str literals
 298    FTable durations          // Duration literals
 299    FTable uris               // Uri literals
 300    Str:FType ftypesByName    // if loaded
 301  
 302  }