-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Handle help, version and @file parameters in scalac and scaladoc #11476
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -64,19 +64,24 @@ class Driver { | |
|
||
protected def sourcesRequired: Boolean = true | ||
|
||
def setup(args: Array[String], rootCtx: Context): (List[AbstractFile], Context) = { | ||
protected def command: CompilerCommand = ScalacCommand | ||
|
||
def setup(args: Array[String], rootCtx: Context): (Option[List[AbstractFile]], Context) = { | ||
val ictx = rootCtx.fresh | ||
val summary = CompilerCommand.distill(args, config.ScalaSettings(), ictx.settingsState) | ||
val settings = config.ScalaSettings() | ||
val summary = command.distill(args, settings, settings.defaultState) | ||
ictx.setSettings(summary.sstate) | ||
MacroClassLoader.init(ictx) | ||
Positioned.init(using ictx) | ||
|
||
inContext(ictx) { | ||
if !ctx.settings.YdropComments.value || ctx.mode.is(Mode.ReadComments) then | ||
ictx.setProperty(ContextDoc, new ContextDocstrings) | ||
val fileNames = CompilerCommand.checkUsage(summary, sourcesRequired)(using ctx.settings)(using ctx.settingsState) | ||
val files = fileNames.map(ctx.getFile) | ||
(files, fromTastySetup(files)) | ||
val fileNamesOrNone = command.checkUsage(summary, sourcesRequired)(using ctx.settings)(using ctx.settingsState) | ||
fileNamesOrNone.fold((None, ictx)) { fileNames => | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not very important but we rarely use fold on Option in the compiler, instead we prefer to match on Some(...) and None There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fill fix |
||
val files = fileNames.map(ctx.getFile) | ||
(Some(files), fromTastySetup(files)) | ||
} | ||
} | ||
} | ||
|
||
|
@@ -183,7 +188,9 @@ class Driver { | |
*/ | ||
def process(args: Array[String], rootCtx: Context): Reporter = { | ||
val (files, compileCtx) = setup(args, rootCtx) | ||
doCompile(newCompiler(using compileCtx), files)(using compileCtx) | ||
files.fold(compileCtx.reporter) { | ||
doCompile(newCompiler(using compileCtx), _)(using compileCtx) | ||
} | ||
} | ||
|
||
def main(args: Array[String]): Unit = { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,16 +40,21 @@ class Resident extends Driver { | |
|
||
final override def process(args: Array[String], rootCtx: Context): Reporter = { | ||
@tailrec def loop(args: Array[String], prevCtx: Context): Reporter = { | ||
var (files, ctx) = setup(args, prevCtx) | ||
inContext(ctx) { doCompile(residentCompiler, files) } | ||
var nextCtx = ctx | ||
var line = getLine() | ||
while (line == reset) { | ||
nextCtx = rootCtx | ||
line = getLine() | ||
} | ||
if (line.startsWith(quit)) ctx.reporter | ||
else loop(line split "\\s+", nextCtx) | ||
var (possibleFiles, ctx) = setup(args, prevCtx) | ||
if possibleFiles.isDefined then | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would pattern match on possibleFiles here instead of using isDefined/get There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will fix |
||
inContext(ctx) { | ||
doCompile(residentCompiler, possibleFiles.get) // using more complex constructs like fold or map instead of get will make @tailrec complain | ||
} | ||
var nextCtx = ctx | ||
var line = getLine() | ||
while (line == reset) { | ||
nextCtx = rootCtx | ||
line = getLine() | ||
} | ||
if (line.startsWith(quit)) ctx.reporter | ||
else loop(line split "\\s+", nextCtx) | ||
else | ||
ctx.reporter | ||
} | ||
loop(args, rootCtx) | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package dotty.tools.dotc | ||
|
||
import config.Properties._ | ||
import config.CompilerCommand | ||
|
||
object ScalacCommand extends CompilerCommand: | ||
override def cmdName: String = "scalac" | ||
override def versionMsg: String = s"Scala compiler $versionString -- $copyrightString" | ||
override def ifErrorsMsg: String = " scalac -help gives more information" |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,19 +9,16 @@ import Properties._ | |
|
||
import scala.collection.JavaConverters._ | ||
|
||
object CompilerCommand extends CliCommand: | ||
type ConcreteSettings = ScalaSettings | ||
override def cmdName: String = "scalac" | ||
override def versionMsg: String = s"Scala compiler $versionString -- $copyrightString" | ||
override def ifErrorsMsg: String = " scalac -help gives more information" | ||
abstract class CompilerCommand extends CliCommand: | ||
final type ConcreteSettings = ScalaSettings | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think final on a type alias does anything. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can remove |
||
|
||
def infoMessage(using settings: ScalaSettings)(using SettingsState)(using Context): String = | ||
final def helpMsg(using settings: ScalaSettings)(using SettingsState, Context): String = | ||
if (settings.help.value) usageMessage | ||
else if (settings.Xhelp.value) xusageMessage | ||
else if (settings.Yhelp.value) yusageMessage | ||
else if (settings.showPlugins.value) ctx.base.pluginDescriptions | ||
else if (settings.XshowPhases.value) phasesMessage | ||
else "" | ||
|
||
def shouldStopWithInfo(using settings: ScalaSettings)(using SettingsState): Boolean = | ||
final def isHelpFlag(using settings: ScalaSettings)(using SettingsState): Boolean = | ||
Set(settings.help, settings.Xhelp, settings.Yhelp, settings.showPlugins, settings.XshowPhases) exists (_.value) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package dotty.tools.repl | ||
|
||
import dotty.tools.dotc.config.Properties._ | ||
import dotty.tools.dotc.config.CompilerCommand | ||
|
||
object ReplCommand extends CompilerCommand: | ||
override def cmdName: String = "scala" | ||
override def versionMsg: String = s"Scala code runner $versionString -- $copyrightString" | ||
override def ifErrorsMsg: String = " scala -help gives more information" |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,7 @@ import dotty.tools.dotc.reporting.{Message, Diagnostic} | |
import dotty.tools.dotc.util.Spans.Span | ||
import dotty.tools.dotc.util.{SourceFile, SourcePosition} | ||
import dotty.tools.dotc.{CompilationUnit, Driver} | ||
import dotty.tools.dotc.config.CompilerCommand | ||
import dotty.tools.io._ | ||
import org.jline.reader._ | ||
|
||
|
@@ -67,7 +68,8 @@ class ReplDriver(settings: Array[String], | |
private def initialCtx = { | ||
val rootCtx = initCtx.fresh.addMode(Mode.ReadPositions | Mode.Interactive | Mode.ReadComments) | ||
rootCtx.setSetting(rootCtx.settings.YcookComments, true) | ||
val ictx = setup(settings, rootCtx)._2 | ||
val (files, ictx) = setup(settings, rootCtx) | ||
shouldStart = files.isDefined | ||
ictx.base.initialize()(using ictx) | ||
ictx | ||
} | ||
|
@@ -91,13 +93,24 @@ class ReplDriver(settings: Array[String], | |
} | ||
|
||
private var rootCtx: Context = _ | ||
private var shouldStart: Boolean = _ | ||
private var compiler: ReplCompiler = _ | ||
private var rendering: Rendering = _ | ||
|
||
// initialize the REPL session as part of the constructor so that once `run` | ||
// is called, we're in business | ||
resetToInitial() | ||
|
||
override protected def command: CompilerCommand = ReplCommand | ||
|
||
/** Try to run REPL if there is nothing that prevents us doing so. | ||
* | ||
* Possible reason for unsuccessful run are raised flags in CLI like --help or --version | ||
*/ | ||
final def tryRunning = if shouldStart then | ||
println("Starting scala3 REPL...") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see this was here before, but I would just delete that line, the repl already prints enough stuff when it starts. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can remove |
||
runUntilQuit() | ||
|
||
/** Run REPL with `state` until `:quit` command found | ||
* | ||
* This method is the main entry point into the REPL. Its effects are not | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package dotty.tools.dotc | ||
|
||
import org.junit.Test | ||
import org.junit.Assert._ | ||
import org.junit.Rule | ||
import org.junit.rules.TemporaryFolder | ||
import dotty.tools.dotc.config.Settings._ | ||
|
||
class ScalaCommandTest: | ||
|
||
private val _temporaryFolder = new TemporaryFolder | ||
|
||
@Rule | ||
def temporaryFolder = _temporaryFolder | ||
|
||
@Test def `Simple one parameter`: Unit = | ||
val settings = config.ScalaSettings() | ||
val args = "-cp path/to/classes1:other/path/to/classes2 files".split(" ") | ||
val summary = ScalacCommand.distill(args, settings, settings.defaultState) | ||
given SettingsState = summary.sstate | ||
assertEquals("path/to/classes1:other/path/to/classes2", settings.classpath.value) | ||
assertEquals("files" :: Nil, summary.arguments) | ||
|
||
@Test def `Unfold @file`: Unit = | ||
val settings = config.ScalaSettings() | ||
val file = temporaryFolder.newFile("config") | ||
val writer = java.io.FileWriter(file); | ||
writer.write("-sourceroot myNewRoot someMoreFiles"); | ||
writer.close(); | ||
val args = s"-cp path/to/classes1:other/path/to/classes2 @$file someFiles".split(" ") | ||
val summary = ScalacCommand.distill(args, settings, settings.defaultState) | ||
|
||
given SettingsState = summary.sstate | ||
assertEquals("path/to/classes1:other/path/to/classes2", settings.classpath.value) | ||
assertEquals("myNewRoot", settings.sourceroot.value) | ||
assertEquals("someMoreFiles" :: "someFiles" :: Nil, summary.arguments) | ||
|
||
extension [T](setting: Setting[T]) | ||
private def value(using ss: SettingsState): T = setting.valueIn(ss) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An Option of a List is weird, the documentation of this method should explain clearly how None differs from Some(Nil) here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will update documentation