logo
class

compiler::TypeParser

sys::Obj
  compiler::TypeParser
   1  //
   2  // Copyright (c) 2006, Brian Frank and Andy Frank
   3  // Licensed under the Academic Free License version 3.0
   4  //
   5  // History:
   6  //   30 Jan 06  Brian Frank  Creation
   7  //   06 Jul 07  Brian Frank  Port from Java
   8  //
   9  
  10  **
  11  ** TypeParser is used to parser formal type signatures into CTypes.
  12  **
  13  **   x::N
  14  **   x::V[]
  15  **   x::V[x::K]
  16  **   |x::A, ... -> x::R|
  17  **
  18  class TypeParser
  19  {
  20  
  21  //////////////////////////////////////////////////////////////////////////
  22  // Factory
  23  //////////////////////////////////////////////////////////////////////////
  24  
  25    **
  26    ** Parse the signature into a resolved CType.  We *don't*
  27    ** use the Namespace's cache - it is using me when a signature
  28    ** isn't found in the cache.  But we do use the CPod's type cache
  29    ** via CPod.resolveType.
  30    **
  31    public static CType resolve(Namespace ns, Str sig)
  32    {
  33      // if the last character isn't ] or |, then this a non-generic
  34      // type and we don't even need to allocate a parser
  35      last := sig[-1]
  36      if (last !== ']' && last !== '|')
  37      {
  38        colon    := sig.index("::")
  39        podName  := sig[0...colon]
  40        typeName := sig[colon+2..-1]
  41        return ns.resolvePod(podName, true).resolveType(typeName, true)
  42      }
  43  
  44      // we got our work cut out for us - create parser
  45      return TypeParser.make(ns, sig).loadTop
  46    }
  47  
  48  //////////////////////////////////////////////////////////////////////////
  49  // Constructor
  50  //////////////////////////////////////////////////////////////////////////
  51  
  52    private new make(Namespace ns, Str sig)
  53    {
  54      this.ns    = ns
  55      this.sig   = sig
  56      this.len   = sig.size
  57      this.pos   = 0
  58      this.cur   = sig[pos]
  59      this.peek  = sig[pos+1]
  60    }
  61  
  62  //////////////////////////////////////////////////////////////////////////
  63  // Parse
  64  //////////////////////////////////////////////////////////////////////////
  65  
  66    private CType loadTop()
  67    {
  68      t := loadAny
  69      if (cur != 0) throw err
  70      return t
  71    }
  72  
  73    private CType loadAny()
  74    {
  75      CType t
  76  
  77      // |...| is function
  78      if (cur === '|')
  79        t = loadFunc
  80  
  81      // [...] is map
  82      else if (cur === '[')
  83        t = loadMap
  84  
  85      // otherwise must be basic[]
  86      else
  87        t = loadBasic
  88  
  89      // anything left must be []
  90      while (cur == '[')
  91      {
  92        consume('[')
  93        consume(']')
  94        t = t.toListOf
  95      }
  96  
  97      return t
  98    }
  99  
 100    private CType loadMap()
 101    {
 102      consume('[')
 103      key := loadAny
 104      consume(':')
 105      val := loadAny
 106      consume(']')
 107      return MapType.make(key, val)
 108    }
 109  
 110    private CType loadFunc()
 111    {
 112      consume('|')
 113      params := CType[,]
 114      names  := Str[,]
 115      if (cur != '-')
 116      {
 117        while (true)
 118        {
 119          params.add(loadAny)
 120          names.add(('a'+names.size).toChar)
 121          if (cur == '-') break
 122          consume(',')
 123        }
 124      }
 125      consume('-')
 126      consume('>')
 127      ret := loadAny
 128      consume('|')
 129  
 130      return FuncType.make(params, names, ret)
 131    }
 132  
 133    private CType loadBasic()
 134    {
 135      start := pos
 136      while (cur.isAlphaNum || cur == '_') consume
 137      consume(':')
 138      consume(':')
 139      while (cur.isAlphaNum || cur == '_') consume
 140      qname := sig[start...pos]
 141      return ns.resolveType(qname)
 142    }
 143  
 144  //////////////////////////////////////////////////////////////////////////
 145  // Utils
 146  //////////////////////////////////////////////////////////////////////////
 147  
 148    private Void consume(Int expected := null)
 149    {
 150      if (expected != null && cur != expected) throw err
 151      cur = peek
 152      pos++
 153      peek = pos+1 < len ? sig[pos+1] : 0
 154    }
 155  
 156    private ArgErr err()
 157    {
 158      return ArgErr.make("Invalid type signature '" + sig + "'")
 159    }
 160  
 161  //////////////////////////////////////////////////////////////////////////
 162  // Fields
 163  //////////////////////////////////////////////////////////////////////////
 164  
 165    private Namespace ns   // namespace we are loading from
 166    private Str sig        // signature being parsed
 167    private Int len        // length of sig
 168    private Int pos        // index of cur in sig
 169    private Int cur        // cur character; sig[pos]
 170    private Int peek       // next character; sig[pos+1]
 171  
 172  }