Skip to content

Commit e6e802c

Browse files
committed
Extract parser into its own phase
1 parent 11acdd9 commit e6e802c

File tree

9 files changed

+85
-80
lines changed

9 files changed

+85
-80
lines changed

compiler/src/dotty/tools/dotc/Compiler.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import transform._
99
import dotty.tools.backend.jvm.{CollectSuperCalls, GenBCode}
1010
import dotty.tools.backend.sjs
1111
import dotty.tools.dotc.transform.localopt.StringInterpolatorOpt
12+
import dotty.tools.dotc.parsing.Parsing
1213

1314
/** The central class of the dotc compiler. The job of a compiler is to create
1415
* runs, which process given `phases` in a given `rootContext`.
@@ -36,6 +37,7 @@ class Compiler {
3637

3738
/** Phases dealing with the frontend up to trees ready for TASTY pickling */
3839
protected def frontendPhases: List[List[Phase]] =
40+
List(new Parsing) ::
3941
List(new FrontEnd) :: // Compiler frontend: scanner, parser, namer, typer
4042
List(new YCheckPositions) :: // YCheck positions
4143
List(new Staging) :: // Check PCP, heal quoted types and expand macros

compiler/src/dotty/tools/dotc/Run.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
155155
Stats.trackTime(s"$phase ms ") {
156156
val start = System.currentTimeMillis
157157
val profileBefore = profiler.beforePhase(phase)
158-
units = phase.runOn(units)
158+
units = phase.runOn(units)(ctx.fresh.setPhase(phase.start))
159159
profiler.afterPhase(phase, profileBefore)
160160
if (ctx.settings.Xprint.value.containsPhase(phase)) {
161161
for (unit <- units) {
@@ -217,7 +217,10 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
217217
val unit = ctx.compilationUnit
218218
val prevPhase = ctx.phase.prev // can be a mini-phase
219219
val squashedPhase = ctx.base.squashed(prevPhase)
220-
val treeString = unit.tpdTree.show(ctx.withProperty(XprintMode, Some(())))
220+
val tree =
221+
if (ctx.isAfterTyper) unit.tpdTree
222+
else unit.untpdTree
223+
val treeString = tree.show(ctx.withProperty(XprintMode, Some(())))
221224

222225
ctx.echo(s"result of $unit after $squashedPhase:")
223226

compiler/src/dotty/tools/dotc/core/Phases.scala

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import Denotations._
1010
import Decorators._
1111
import config.Printers.config
1212
import scala.collection.mutable.ListBuffer
13+
import scala.util.control.NonFatal
1314
import dotty.tools.dotc.transform.MegaPhase._
1415
import dotty.tools.dotc.transform._
1516
import Periods._
@@ -312,7 +313,7 @@ object Phases {
312313
/** @pre `isRunnable` returns true */
313314
def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] =
314315
units.map { unit =>
315-
val unitCtx = ctx.fresh.setPhase(this.start).setCompilationUnit(unit)
316+
val unitCtx = ctx.fresh.setCompilationUnit(unit)
316317
run(unitCtx)
317318
unitCtx.compilationUnit
318319
}
@@ -327,7 +328,7 @@ object Phases {
327328
def checkPostCondition(tree: tpd.Tree)(implicit ctx: Context): Unit = ()
328329

329330
/** Is this phase the standard typerphase? True for FrontEnd, but
330-
* not for other first phases (such as FromTasty). The predicate
331+
* not for other first phases (such as ReadTasty). The predicate
331332
* is tested in some places that perform checks and corrections. It's
332333
* different from isAfterTyper (and cheaper to test).
333334
*/
@@ -412,6 +413,14 @@ object Phases {
412413
final def iterator: Iterator[Phase] =
413414
Iterator.iterate(this)(_.next) takeWhile (_.hasNext)
414415

416+
final def monitor(doing: String)(body: => Unit)(implicit ctx: Context): Unit =
417+
try body
418+
catch {
419+
case NonFatal(ex) =>
420+
ctx.echo(s"exception occurred while $doing ${ctx.compilationUnit}")
421+
throw ex
422+
}
423+
415424
override def toString: String = phaseName
416425
}
417426

compiler/src/dotty/tools/dotc/interactive/InteractiveCompiler.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@ package interactive
55
import core._
66
import Phases._
77
import typer._
8+
import parsing.Parsing
89

910
class InteractiveCompiler extends Compiler {
1011
// TODO: Figure out what phases should be run in IDEs
1112
// More phases increase latency but allow us to report more errors.
1213
// This could be improved by reporting errors back to the IDE
1314
// after each phase group instead of waiting for the pipeline to finish.
1415
override def phases: List[List[Phase]] = List(
16+
List(new Parsing),
1517
List(new FrontEnd),
1618
List(new transform.SetRootTree),
1719
List(new transform.CookComments)
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package dotty.tools.dotc.parsing
2+
3+
import dotty.tools.dotc.ast.Trees
4+
import dotty.tools.dotc.config.Config
5+
import dotty.tools.dotc.core.Contexts.Context
6+
import dotty.tools.dotc.core.Phases.Phase
7+
import dotty.tools.dotc.core.Symbols.defn
8+
import dotty.tools.dotc.parsing.JavaParsers.JavaParser
9+
import dotty.tools.dotc.parsing.Parsers.Parser
10+
import dotty.tools.dotc.util.{SourcePosition, NoSourcePosition}
11+
import dotty.tools.dotc.util.Stats.record
12+
13+
class Parsing extends Phase {
14+
15+
override def phaseName: String = "parsing"
16+
17+
// We run TreeChecker only after type checking
18+
override def isCheckable: Boolean = false
19+
20+
override def isRunnable(implicit ctx: Context): Boolean =
21+
!ctx.settings.fromTasty.value
22+
23+
/** The position of the first XML literal encountered while parsing,
24+
* NoSourcePosition if there were no XML literals.
25+
*/
26+
private[this] var firstXmlPos: SourcePosition = NoSourcePosition
27+
28+
override def run(implicit ctx: Context): Unit = monitor("parsing") {
29+
val unit = ctx.compilationUnit
30+
unit.untpdTree =
31+
if (unit.isJava) new JavaParser(unit.source).parse()
32+
else {
33+
val p = new Parser(unit.source)
34+
val tree = p.parse()
35+
if (p.firstXmlPos.exists && !firstXmlPos.exists)
36+
firstXmlPos = p.firstXmlPos
37+
tree
38+
}
39+
40+
record("parsedTrees", Trees.ntrees)
41+
42+
if (firstXmlPos.exists && !defn.ScalaXmlPackageClass.exists)
43+
ctx.error("""To support XML literals, your project must depend on scala-xml.
44+
|See https://github.com/scala/scala-xml for more information.""".stripMargin,
45+
firstXmlPos)
46+
47+
if (Config.checkPositions)
48+
unit.untpdTree.checkPos(nonOverlapping = !unit.isJava && !ctx.reporter.hasErrors)
49+
}
50+
}

compiler/src/dotty/tools/dotc/typer/FrontEnd.scala

Lines changed: 11 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -6,79 +6,48 @@ import core._
66
import Phases._
77
import Contexts._
88
import Symbols._
9-
import dotty.tools.dotc.parsing.JavaParsers.JavaParser
10-
import parsing.Parsers.Parser
119
import config.Config
1210
import config.Printers.{typr, default}
1311
import util.Stats._
14-
import util.{ SourcePosition, NoSourcePosition }
1512
import scala.util.control.NonFatal
16-
import ast.Trees._
13+
import ast.{tpd, Trees}
14+
import Trees._
1715

1816
class FrontEnd extends Phase {
17+
import tpd._
1918

2019
override def phaseName: String = FrontEnd.name
2120
override def isTyper: Boolean = true
22-
import ast.tpd
21+
22+
// Run regardless of parsing errors
23+
override def isRunnable(implicit ctx: Context): Boolean = true
2324

2425
override def allowsImplicitSearch: Boolean = true
2526

2627
/** The contexts for compilation units that are parsed but not yet entered */
2728
private[this] var remaining: List[Context] = Nil
2829

29-
/** The position of the first XML literal encountered while parsing,
30-
* NoSourcePosition if there were no XML literals.
31-
*/
32-
private[this] var firstXmlPos: SourcePosition = NoSourcePosition
33-
3430
/** Does a source file ending with `<name>.scala` belong to a compilation unit
3531
* that is parsed but not yet entered?
3632
*/
3733
def stillToBeEntered(name: String): Boolean =
3834
remaining.exists(_.compilationUnit.toString.endsWith(name + ".scala"))
3935

40-
def monitor(doing: String)(body: => Unit)(implicit ctx: Context): Unit =
41-
try body
42-
catch {
43-
case NonFatal(ex) =>
44-
ctx.echo(s"exception occurred while $doing ${ctx.compilationUnit}")
45-
throw ex
46-
}
47-
48-
def parse(implicit ctx: Context): Unit = monitor("parsing") {
49-
val unit = ctx.compilationUnit
50-
51-
unit.untpdTree =
52-
if (unit.isJava) new JavaParser(unit.source).parse()
53-
else {
54-
val p = new Parser(unit.source)
55-
val tree = p.parse()
56-
if (p.firstXmlPos.exists && !firstXmlPos.exists)
57-
firstXmlPos = p.firstXmlPos
58-
tree
59-
}
60-
61-
val printer = if (ctx.settings.Xprint.value.contains("parser")) default else typr
62-
printer.println("parsed:\n" + unit.untpdTree.show)
63-
if (Config.checkPositions)
64-
unit.untpdTree.checkPos(nonOverlapping = !unit.isJava && !ctx.reporter.hasErrors)
65-
}
66-
67-
def enterSyms(implicit ctx: Context): Unit = monitor("indexing") {
36+
private def enterSyms(implicit ctx: Context): Unit = monitor("indexing") {
6837
val unit = ctx.compilationUnit
6938
ctx.typer.index(unit.untpdTree)
7039
typr.println("entered: " + unit.source)
7140
}
7241

73-
def typeCheck(implicit ctx: Context): Unit = monitor("typechecking") {
42+
private def typeCheck(implicit ctx: Context): Unit = monitor("typechecking") {
7443
val unit = ctx.compilationUnit
7544
unit.tpdTree = ctx.typer.typedExpr(unit.untpdTree)
7645
typr.println("typed: " + unit.source)
7746
record("retained untyped trees", unit.untpdTree.treeSize)
7847
record("retained typed trees after typer", unit.tpdTree.treeSize)
7948
}
8049

81-
private def firstTopLevelDef(trees: List[tpd.Tree])(implicit ctx: Context): Symbol = trees match {
50+
private def firstTopLevelDef(trees: List[Tree])(implicit ctx: Context): Symbol = trees match {
8251
case PackageDef(_, defs) :: _ => firstTopLevelDef(defs)
8352
case Import(_, _, _) :: defs => firstTopLevelDef(defs)
8453
case (tree @ TypeDef(_, _)) :: _ => tree.symbol
@@ -93,21 +62,15 @@ class FrontEnd extends Phase {
9362
ctx.inform(s"compiling ${unit.source}")
9463
ctx.fresh.setCompilationUnit(unit)
9564
}
96-
unitContexts foreach (parse(_))
97-
record("parsedTrees", ast.Trees.ntrees)
65+
9866
remaining = unitContexts
9967
while (remaining.nonEmpty) {
10068
enterSyms(remaining.head)
10169
remaining = remaining.tail
10270
}
10371

104-
if (firstXmlPos.exists && !defn.ScalaXmlPackageClass.exists)
105-
ctx.error("""To support XML literals, your project must depend on scala-xml.
106-
|See https://github.com/scala/scala-xml for more information.""".stripMargin,
107-
firstXmlPos)
108-
10972
unitContexts.foreach(typeCheck(_))
110-
record("total trees after typer", ast.Trees.ntrees)
73+
record("total trees after typer", Trees.ntrees)
11174
unitContexts.map(_.compilationUnit).filterNot(discardAfterTyper)
11275
}
11376

compiler/src/dotty/tools/repl/ReplCompiler.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import dotty.tools.dotc.core.StdNames._
1313
import dotty.tools.dotc.core.Symbols._
1414
import dotty.tools.dotc.reporting.diagnostic.messages
1515
import dotty.tools.dotc.transform.{PostTyper, Staging}
16-
import dotty.tools.dotc.typer.ImportInfo
16+
import dotty.tools.dotc.typer.{FrontEnd, ImportInfo}
1717
import dotty.tools.dotc.util.Spans._
1818
import dotty.tools.dotc.util.{ParsedComment, SourceFile}
1919
import dotty.tools.dotc.{CompilationUnit, Compiler, Run}
@@ -32,7 +32,7 @@ import scala.collection.mutable
3232
class ReplCompiler extends Compiler {
3333

3434
override protected def frontendPhases: List[List[Phase]] = List(
35-
List(new REPLFrontEnd),
35+
List(new FrontEnd),
3636
List(new CollectTopLevelImports),
3737
List(new Staging),
3838
List(new PostTyper)

compiler/src/dotty/tools/repl/ReplFrontEnd.scala

Lines changed: 0 additions & 26 deletions
This file was deleted.

doc-tool/src/dotty/tools/dottydoc/DocCompiler.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import dotc.typer.FrontEnd
1111

1212
import dotty.tools.dotc.fromtasty.{ReadTasty, TASTYRun}
1313
import dotty.tools.dotc.transform.CookComments
14+
import dotty.tools.dotc.parsing.Parsing
1415

1516
/** Custom Compiler with phases for the documentation tool
1617
*
@@ -53,6 +54,7 @@ class DocCompiler extends Compiler {
5354
}
5455

5556
override def phases: List[List[Phase]] = List(
57+
List(new Parsing),
5658
List(new DocFrontEnd),
5759
List(new ReadTasty),
5860
List(new CookComments),

0 commit comments

Comments
 (0)