blob: 6eff63e2be6f899dec8a76e06eae2368fcd51b26 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
package dotty.tools.dotc
package typer
import core._
import Phases._
import Contexts._
import Symbols._
import dotty.tools.dotc.parsing.JavaParsers.JavaParser
import parsing.Parsers.Parser
import config.Config
import config.Printers.{typr, default}
import util.Stats._
import scala.util.control.NonFatal
import ast.Trees._
class FrontEnd extends Phase {
override def phaseName = "frontend"
override def isTyper = true
import ast.tpd
/** The contexts for compilation units that are parsed but not yet entered */
private var remaining: List[Context] = Nil
/** Does a source file ending with `<name>.scala` belong to a compilation unit
* that is parsed but not yet entered?
*/
def stillToBeEntered(name: String): Boolean =
remaining.exists(_.compilationUnit.toString.endsWith(name + ".scala"))
def monitor(doing: String)(body: => Unit)(implicit ctx: Context) =
try body
catch {
case NonFatal(ex) =>
ctx.echo(s"exception occurred while $doing ${ctx.compilationUnit}")
throw ex
}
def parse(implicit ctx: Context) = monitor("parsing") {
val unit = ctx.compilationUnit
unit.untpdTree =
if (unit.isJava) new JavaParser(unit.source).parse()
else new Parser(unit.source).parse()
val printer = if (ctx.settings.Xprint.value.contains("parser")) default else typr
printer.println("parsed:\n" + unit.untpdTree.show)
if (Config.checkPositions)
unit.untpdTree.checkPos(nonOverlapping = !unit.isJava && !ctx.reporter.hasErrors)
}
def enterSyms(implicit ctx: Context) = monitor("indexing") {
val unit = ctx.compilationUnit
ctx.typer.index(unit.untpdTree)
typr.println("entered: " + unit.source)
}
def enterAnnotations(implicit ctx: Context) = monitor("annotating") {
val unit = ctx.compilationUnit
ctx.typer.annotate(unit.untpdTree :: Nil)
typr.println("annotated: " + unit.source)
}
def typeCheck(implicit ctx: Context) = monitor("typechecking") {
val unit = ctx.compilationUnit
unit.tpdTree = ctx.typer.typedExpr(unit.untpdTree)
typr.println("typed: " + unit.source)
record("retained untyped trees", unit.untpdTree.treeSize)
record("retained typed trees after typer", unit.tpdTree.treeSize)
}
private def firstTopLevelDef(trees: List[tpd.Tree])(implicit ctx: Context): Symbol = trees match {
case PackageDef(_, defs) :: _ => firstTopLevelDef(defs)
case Import(_, _) :: defs => firstTopLevelDef(defs)
case (tree @ TypeDef(_, _)) :: _ => tree.symbol
case _ => NoSymbol
}
protected def discardAfterTyper(unit: CompilationUnit)(implicit ctx: Context) =
unit.isJava || firstTopLevelDef(unit.tpdTree :: Nil).isPrimitiveValueClass
override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = {
val unitContexts = for (unit <- units) yield {
ctx.inform(s"compiling ${unit.source}")
ctx.fresh.setCompilationUnit(unit)
}
unitContexts foreach (parse(_))
record("parsedTrees", ast.Trees.ntrees)
remaining = unitContexts
while (remaining.nonEmpty) {
enterSyms(remaining.head)
remaining = remaining.tail
}
unitContexts.foreach(enterAnnotations(_))
unitContexts.foreach(typeCheck(_))
record("total trees after typer", ast.Trees.ntrees)
unitContexts.map(_.compilationUnit).filterNot(discardAfterTyper)
}
override def run(implicit ctx: Context): Unit = {
parse
enterSyms
typeCheck
}
}
|