Skip to content

Commit

Permalink
added -Xmacro-settings option and API with the same behaviour as in S…
Browse files Browse the repository at this point in the history
…cala2

added test-case from #12039 with workarround against changes in compiler

Co-authored-by: David Barri <japgolly@gmail.com>
Co-authored-by: Nicolas Stucki <nicolas.stucki@gmail.com>
  • Loading branch information
3 people committed Jan 11, 2022
1 parent 0b4c6e7 commit d122b13
Show file tree
Hide file tree
Showing 11 changed files with 137 additions and 0 deletions.
2 changes: 2 additions & 0 deletions compiler/src/dotty/tools/dotc/config/ScalaSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,8 @@ private sealed trait XSettings:
def isTruthy(using Context) = XmixinForceForwarders.value == "true"
def isAtLeastJunit(using Context) = isTruthy || XmixinForceForwarders.value == "junit"
}

val XmacroSettings: Setting[List[String]] = MultiStringSetting("-Xmacro-settings", "setting1,setting2,..settingN", "List of settings which exposed to the macros")
end XSettings

/** -Y "Forking" as in forked tongue or "Private" settings */
Expand Down
1 change: 1 addition & 0 deletions compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler

object CompilationInfo extends CompilationInfoModule:
def isWhileTyping: Boolean = !ctx.isAfterTyper
def XmacroSettings: List[String] = ctx.settings.XmacroSettings.value
end CompilationInfo

extension (expr: Expr[Any])
Expand Down
2 changes: 2 additions & 0 deletions compiler/test/dotty/tools/dotc/CompilationTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ class CompilationTests {
compileFile("tests/run-custom-args/defaults-serizaliable-no-forwarders.scala", defaultOptions and "-Xmixin-force-forwarders:false"),
compileFilesInDir("tests/run-custom-args/erased", defaultOptions.and("-language:experimental.erasedDefinitions")),
compileFilesInDir("tests/run-custom-args/fatal-warnings", defaultOptions.and("-Xfatal-warnings")),
compileDir("tests/run-custom-args/Xmacro-settings/simple", defaultOptions.and("-Xmacro-settings:one,two,three")),
compileDir("tests/run-custom-args/Xmacro-settings/compileTimeEnv", defaultOptions.and("-Xmacro-settings:a,b=1,c.b.a=x.y.z=1,myLogger.level=INFO")),
compileFilesInDir("tests/run-deep-subtype", allowDeepSubtypes),
compileFilesInDir("tests/run", defaultOptions.and("-Ysafe-init"))
).checkRuns()
Expand Down
9 changes: 9 additions & 0 deletions library/src/scala/quoted/Quotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,15 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
* This will be true when the macro is used in a transparent inline.
*/
def isWhileTyping: Boolean

/** Expose macro-specific settings as a list of strings.
* Settings can be set from command line with help of -Xmacro-settings options.
*
* These will be used to expand any transparent macros or any non-transparent macro that is forced to expand while expanding the transparent macro.
* Non-transparent macros are not guaranteed to be expanded with the same set of settings.
*/
@experimental
def XmacroSettings: List[String]
}


Expand Down
2 changes: 2 additions & 0 deletions project/MiMaFilters.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ object MiMaFilters {
ProblemFilters.exclude[MissingClassProblem]("scala.compiletime.ops.float$"),
ProblemFilters.exclude[MissingClassProblem]("scala.compiletime.ops.long"),
ProblemFilters.exclude[MissingClassProblem]("scala.compiletime.ops.long$"),
ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule#CompilationInfoModule.XmacroSettings"),
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.quoted.Quotes#reflectModule#CompilationInfoModule.XmacroSettings"),

// Should have been added in 3.1.0
// These are only allowed on imports and therefore should not be present in binaries emitted before
Expand Down
6 changes: 6 additions & 0 deletions tests/run-custom-args/Xmacro-settings/compileTimeEnv.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
I'm a info msg
I'm a warn msg
a = []
b = [1]
c.b.a = [x.y.z=1]
wat is not defined
35 changes: 35 additions & 0 deletions tests/run-custom-args/Xmacro-settings/compileTimeEnv/Logging.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import scala.compiletime.*
import scala.quoted.*


object Logging {

// Just use your imagination for now :)
private inline val Trace = 0
private inline val Debug = 1
private inline val Info = 2
private inline val Warn = 3

private transparent inline def chosenThreshold: Int = ${
choosenTresholdImpl
}


private def choosenTresholdImpl(using Quotes):Expr[Int] =
import quotes.reflect.*
MacroEnv.getInMacro("myLogger.level") match
case Some("TRACE") => Expr(Trace)
case Some("DEBUG") => Expr(Debug)
case Some("INFO") => Expr(Info)
case Some("WARN") => Expr(Warn)
case Some(x) => report.errorAndAbort("Unsupported logging level: " + x)
case None => Expr(Trace)

private inline def log(inline lvl: Int, inline msg: String): Unit =
inline if lvl >= chosenThreshold then println(msg)

inline def trace(inline msg: String): Unit = log(Trace, msg)
inline def debug(inline msg: String): Unit = log(Debug, msg)
inline def info (inline msg: String): Unit = log(Info , msg)
inline def warn (inline msg: String): Unit = log(Warn , msg)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import scala.quoted.*

object MacroEnv {

transparent inline def get(inline key:String):Option[String] = ${
getImpl('key)
}

def getImpl(key:Expr[String])(using Quotes):Expr[Option[String]] = {
import quotes.reflect.*
val retval = getInMacro(key.valueOrAbort)
Expr(retval)
}

def getInMacro(key:String)(using Quotes):Option[String] = {
import quotes.reflect.*
val keyEq = key + "="
CompilationInfo.XmacroSettings.collectFirst{
case v if v == key => ""
case v if v.startsWith(keyEq) =>
v.substring(keyEq.length)
}
}

}
30 changes: 30 additions & 0 deletions tests/run-custom-args/Xmacro-settings/compileTimeEnv/Test.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import scala.compiletime.*

object Test {
import Logging.*

def main(args: Array[String]): Unit = {
runLog()
runBasic()
}

def runLog(): Unit = {
trace("I'm a trace msg")
debug("I'm a debug msg")
info("I'm a info msg")
warn("I'm a warn msg")
}

def runBasic(): Unit = {
printEnv("a")
printEnv("b")
printEnv("c.b.a")
printEnv("wat")
}

inline def printEnv(inline k: String): Unit =
inline MacroEnv.get(k) match
case Some(v) => println(s"$k = [$v]")
case None => println(k + " is not defined")

}
15 changes: 15 additions & 0 deletions tests/run-custom-args/Xmacro-settings/simple/M1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package x

import scala.quoted.*

object M:

inline def settingsContains(inline x:String): Boolean = ${
settingsContainsImpl('x)
}

def settingsContainsImpl(x:Expr[String])(using Quotes): Expr[Boolean] =
import quotes.reflect.*
val v = x.valueOrAbort
val r = CompilationInfo.XmacroSettings.contains(v)
Expr(r)
10 changes: 10 additions & 0 deletions tests/run-custom-args/Xmacro-settings/simple/Test.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import x.*

object Test {

def main(args: Array[String]):Unit =
assert(M.settingsContains("one"))
assert(!M.settingsContains("notwo"))
assert(M.settingsContains("two"))

}

0 comments on commit d122b13

Please sign in to comment.