Scalaのソースコードを読んでみる　その６

[前回](http://qiita.com/JunSuzukiJapan@github/items/12f956875685ddec7cc0)からの流れで、
つぎは、メソッドtopStatSeq()の中で呼ばれている
メソッドtopLevelTmplDefを見てみましょう。

```scala:
    /** Hook for IDE, for top-level classes/objects. */
    def topLevelTmplDef: Tree = {
      val annots = annotations(skipNewLines = true)
      val pos    = caseAwareTokenOffset
      val mods   = modifiers() withAnnotations annots
      tmplDef(pos, mods)
    }
```

これは、「改行をスキップしたり」とかの多少の設定をして、
すぐにメソッドtmplDef()を呼び出してるだけですね。
では、tmplDef()を見てみましょう。

```scala:
    /** {{{
     *  TmplDef ::= [case] class ClassDef
     *            |  [case] object ObjectDef
     *            |  [override] trait TraitDef
     *  }}}
     */
    def tmplDef(pos: Int, mods: Modifiers): Tree = {
      if (mods.isLazy) syntaxError("classes cannot be lazy", skipIt = false)
      in.token match {
        case TRAIT =>
          classDef(pos, (mods | Flags.TRAIT | Flags.ABSTRACT) withPosition (Flags.TRAIT, tokenRange(in)))
        case CLASS =>
          classDef(pos, mods)
        case CASECLASS =>
          classDef(pos, (mods | Flags.CASE) withPosition (Flags.CASE, tokenRange(in.prev /*scanner skips on &#39;case&#39; to &#39;class&#39;, thus take prev*/)))
        case OBJECT =>
          objectDef(pos, mods)
        case CASEOBJECT =>
          objectDef(pos, (mods | Flags.CASE) withPosition (Flags.CASE, tokenRange(in.prev /*scanner skips on &#39;case&#39; to &#39;object&#39;, thus take prev*/)))
        case _ =>
          syntaxErrorOrIncompleteAnd("expected start of definition", skipIt = true)(EmptyTree)
      }
    }
```

ここでもコメントに生成規則が書かれています。
class定義や、objectの定義、trait定義がされています（case classなども含む）。

それぞれの場合に応じて、メソッドclassDef()やobjectDef()を呼び出しています。

試しにclassDef()を見てみましょう。

```scala:
    /** {{{
     *  ClassDef ::= Id [TypeParamClause] {Annotation}
     *               [AccessModifier] ClassParamClauses RequiresTypeOpt ClassTemplateOpt
     *  TraitDef ::= Id [TypeParamClause] RequiresTypeOpt TraitTemplateOpt
     *  }}}
     */
    def classDef(start: Int, mods: Modifiers): ClassDef = {
      in.nextToken()
      val nameOffset = in.offset
      val name = identForType()
      atPos(start, if (name == tpnme.ERROR) start else nameOffset) {
        savingClassContextBounds {
          val contextBoundBuf = new ListBuffer[Tree]
          val tparams = typeParamClauseOpt(name, contextBoundBuf)
          classContextBounds = contextBoundBuf.toList
          val tstart = (in.offset :: classContextBounds.map(_.pos.startOrPoint)).min
          if (!classContextBounds.isEmpty && mods.isTrait) {
            syntaxError("traits cannot have type parameters with context bounds `: ...&#39; nor view bounds `<% ...&#39;", skipIt = false)
            classContextBounds = List()
          }
          val constrAnnots = constructorAnnotations()
          val (constrMods, vparamss) =
            if (mods.isTrait) (Modifiers(Flags.TRAIT), List())
            else (accessModifierOpt(), paramClauses(name, classContextBounds, ofCaseClass = mods.isCase))
          var mods1 = mods
          if (mods.isTrait) {
            if (settings.YvirtClasses && in.token == SUBTYPE) mods1 |= Flags.DEFERRED
          } else if (in.token == SUBTYPE) {
            syntaxError("classes are not allowed to be virtual", skipIt = false)
          }
          val template = templateOpt(mods1, name, constrMods withAnnotations constrAnnots, vparamss, tstart)
          if (isInterface(mods1, template.body)) mods1 |= Flags.INTERFACE
          val result = ClassDef(mods1, name, tparams, template)
          // Context bounds generate implicit parameters (part of the template) with types
          // from tparams: we need to ensure these don&#39;t overlap
          if (!classContextBounds.isEmpty)
            ensureNonOverlapping(template, tparams)
          result
        }
      }
    }
```

さて、ようやく定義っぽい定義がでてきましたね。
（場合分けに応じたメソッドに飛ぶだけ、には飽きてきたところです。）

def classDefのすぐ次の行の

```scala:
  in.nextToken()
```

は、ソースファイル中の"class"というトークンを読み飛ばしているのでしょう。こういう処理は、構文解析ではよくあるパターンです。

```scala:
      val nameOffset = in.offset
      val name = identForType()
      atPos(start, if (name == tpnme.ERROR) start else nameOffset) {
```

あたりは、クラス名を読み込んでるところだと思われます。
で、クラス名がtpnme.ERRORだったらちょっと処理を変える感じかな…。

```scala:
        savingClassContextBounds {
          val contextBoundBuf = new ListBuffer[Tree]
```

ここは、現在のコンテキストを保存しておいて、新しいコンテキストを作成という感じでしょう。コンテキストが具体的に何かはわかりませんが、変数のスコープとかなんやからだと推測。

```scala:
          val tstart = (in.offset :: classContextBounds.map(_.pos.startOrPoint)).min
          if (!classContextBounds.isEmpty && mods.isTrait) {
            syntaxError("traits cannot have type parameters with context bounds `: ...&#39; nor view bounds `<% ...&#39;", skipIt = false)
            classContextBounds = List()
          }
```

ここは、拡張BNFでいうところの[TypeParamClause] のあたりでしょう。

```scala:
          val constrAnnots = constructorAnnotations()
```

ここは、 {Annotation}。

```scala:
          val (constrMods, vparamss) =
            if (mods.isTrait) (Modifiers(Flags.TRAIT), List())
            else (accessModifierOpt(), paramClauses(name, classContextBounds, ofCaseClass = mods.isCase))
          var mods1 = mods
          if (mods.isTrait) {
            if (settings.YvirtClasses && in.token == SUBTYPE) mods1 |= Flags.DEFERRED
          } else if (in.token == SUBTYPE) {
            syntaxError("classes are not allowed to be virtual", skipIt = false)
          }
```

この辺が、[AccessModifier]かな。
となると、

```scala:
          val template = templateOpt(mods1, name, constrMods withAnnotations constrAnnots, vparamss, tstart)
          if (isInterface(mods1, template.body)) mods1 |= Flags.INTERFACE
          val result = ClassDef(mods1, name, tparams, template)
```

このあたりが、ClassParamClauses RequiresTypeOpt ClassTemplateOpt　にあたることになりますね。

```scala:
          val template = templateOpt(mods1, name, constrMods withAnnotations constrAnnots, vparamss, tstart)
```

の１行で、ClassParamClauses RequiresTypeOpt ClassTemplateOpt　の３つ分ってことになるけど、あってるかな…。
残りの、

```scala:
          // Context bounds generate implicit parameters (part of the template) with types
          // from tparams: we need to ensure these don&#39;t overlap
          if (!classContextBounds.isEmpty)
            ensureNonOverlapping(template, tparams)
          result
```

のところは、新しく作成したコンテキストが空でなければ、なんらかの処理をするっぽい。

てな感じで読んでいけば、だいたいの生成規則は読めそうですね。

つぎは、（私が今）実装したい文法を実装する方法をどうやって実装するかを考えてみたいと思います。

（つづく）