logo

class

compiler::UsingAndTypeScanner

sys::Obj
  compiler::CompilerSupport
    compiler::UsingAndTypeScanner
   1  //
   2  // Copyright (c) 2006, Brian Frank and Andy Frank
   3  // Licensed under the Academic Free License version 3.0
   4  //
   5  // History:
   6  //   5 Jun 06  Brian Frank  Creation
   7  //
   8  
   9  **
  10  ** ScanForUsingsAndTypes is the first phase in a two pass parser.  Here
  11  ** we scan thru the tokens to parse using declarations and type definitions
  12  ** so that we can fully define the namespace of types.  The result of this
  13  ** step is to populate each CompilationUnit's using and types, and the
  14  ** PodDef.typeDefs map.
  15  **
  16  class ScanForUsingsAndTypes : CompilerStep
  17  {
  18  
  19  //////////////////////////////////////////////////////////////////////////
  20  // Construction
  21  //////////////////////////////////////////////////////////////////////////
  22  
  23    **
  24    ** Constructor takes the associated Compiler
  25    **
  26    new make(Compiler compiler)
  27      : super(compiler)
  28    {
  29    }
  30  
  31  //////////////////////////////////////////////////////////////////////////
  32  // Methods
  33  //////////////////////////////////////////////////////////////////////////
  34  
  35    **
  36    ** Run the step
  37    **
  38    override Void run()
  39    {
  40      log.debug("ScanForUsingsAndTypes")
  41  
  42      allTypes := Str:TypeDef[:]
  43  
  44      units.each |CompilationUnit unit|
  45      {
  46        UsingAndTypeScanner.make(compiler, unit, allTypes).parse
  47      }
  48      bombIfErr
  49  
  50      compiler.pod.typeDefs = allTypes
  51    }
  52  
  53  }
  54  
  55  **************************************************************************
  56  ** UsingAndTypeScanner
  57  **************************************************************************
  58  
  59  class UsingAndTypeScanner : CompilerSupport
  60  {
  61    new make(Compiler compiler, CompilationUnit unit, Str:TypeDef allTypes)
  62      : super(compiler)
  63    {
  64      this.unit     = unit
  65      this.tokens   = unit.tokens
  66      this.pos      = 0
  67      this.allTypes = allTypes
  68      if (compiler != null) this.isSys = compiler.isSys
  69    }
  70  
  71    Void parse()
  72    {
  73      // sys is imported implicitly (unless this is sys itself)
  74      if (!isSys)
  75        unit.usings.add(Using.make(unit.location, "sys"))
  76  
  77      // scan tokens quickly looking for keywords
  78      inClassHeader := false
  79      while (true)
  80      {
  81        tok := consume
  82        if (tok.kind === Token.eof) break
  83        switch (tok.kind)
  84        {
  85          case Token.usingKeyword:
  86            parseUsing(tok)
  87          case Token.lbrace:
  88            inClassHeader = false
  89          case Token.classKeyword:
  90          case Token.mixinKeyword:
  91          case Token.enumKeyword:
  92            if (!inClassHeader)
  93            {
  94              inClassHeader = true;
  95              parseType(tok);
  96            }
  97        }
  98      }
  99    }
 100  
 101    private Void parseUsing(TokenVal tok)
 102    {
 103      imp := Using.make(tok, consumeId)
 104      if (curt === Token.doubleColon)
 105      {
 106        consume
 107        imp.typeName = consumeId
 108        if (curt === Token.asKeyword)
 109        {
 110          consume
 111          imp.asName = consumeId
 112        }
 113      }
 114      unit.usings.add(imp)
 115    }
 116  
 117    private Void parseType(TokenVal tok)
 118    {
 119      name := consumeId
 120      typeDef := TypeDef.make(ns, tok, unit, name)
 121      unit.types.add(typeDef)
 122  
 123      // set enum/mixin flag to use by Parser
 124      if (tok.kind === Token.mixinKeyword)
 125        typeDef.flags |= FConst.Mixin
 126      else if (tok.kind === Token.enumKeyword)
 127        typeDef.flags |= FConst.Enum
 128  
 129      // check for duplicate type names
 130      if (allTypes.containsKey(name))
 131        err("Duplicate type name '$name'", typeDef.location)
 132      else
 133        allTypes[name] = typeDef
 134    }
 135  
 136    private Str consumeId()
 137    {
 138      id := consume
 139      if (id.kind != Token.identifier)
 140      {
 141        err("Expected identifier", id)
 142        return ""
 143      }
 144      return (Str)id.val
 145    }
 146  
 147    private TokenVal consume()
 148    {
 149      return tokens[pos++]
 150    }
 151  
 152    private Token curt()
 153    {
 154      return tokens[pos].kind
 155    }
 156  
 157    private CompilationUnit unit
 158    private TokenVal[] tokens
 159    private Int pos
 160    private Bool isSys := false
 161    private Str:TypeDef allTypes
 162  
 163  }