-
-
Save Katrix/7f989ee734ae5107daa42ba1ab2f9a93 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package dottyspongetext | |
import org.spongepowered.api.text.Text | |
import org.spongepowered.api.text.translation.{Translatable, Translation} | |
import org.spongepowered.api.text.selector.Selector | |
import org.spongepowered.api.scoreboard.Score | |
import scala.quoted._ | |
import scala.quoted.matching._ | |
import reflect._ | |
//Lot's of stuff in here taken from the f interpolator | |
inline def (sc: => StringContext) t(args: Any*) <: Text = ${ textOfMacro('sc, 'args) } | |
private def getPartsExprs(scExpr: Expr[StringContext])(given qctx: QuoteContext): Option[(List[Expr[String]], List[String])] = | |
def notStatic = | |
qctx.error("Expected statically known String Context", scExpr) | |
None | |
def splitParts(seq: Expr[Seq[String]]) = (seq, seq) match | |
case (ExprSeq(p1), ConstSeq(p2)) => Some((p1.toList, p2.toList)) | |
case (_, _) => notStatic | |
scExpr match | |
case '{ StringContext($parts: _*) } => splitParts(parts) | |
case '{ new StringContext($parts: _*) } => splitParts(parts) | |
case _ => notStatic | |
def getArgsExprs(argsExpr: Expr[Seq[Any]])(given qctx: QuoteContext): Option[List[Expr[Any]]] = | |
import qctx.tasty.{_, given} | |
argsExpr.unseal.underlyingArgument match | |
case Typed(Repeated(args, _), _) => | |
Some(args.map(_.seal)) | |
case tree => | |
qctx.error("Expected statically known argument list", argsExpr) | |
None | |
def checkSizes(format: Int, argument : Int)(given qctx: QuoteContext): Unit = | |
if (format > argument && !(format == -1 && argument == 0)) | |
if (argument == 0) | |
qctx.error("too few arguments for interpolated string") | |
else | |
qctx.error("too few arguments for interpolated string") | |
if (format < argument && !(format == -1 && argument == 0)) | |
if (argument == 0) | |
qctx.error("too many arguments for interpolated string") | |
else | |
qctx.error("too many arguments for interpolated string") | |
if (format == -1) | |
qctx.error("there are no parts") | |
private def textOfMacro(scExpr: Expr[StringContext], argsExpr: Expr[Seq[Any]])(given qctx: QuoteContext): Expr[Text] = | |
import qctx.tasty.{_, given} | |
val (partsExpr, parts) = getPartsExprs(scExpr) match | |
case Some(x) => x | |
case None => return '{Text.EMPTY} | |
val args = getArgsExprs(argsExpr) match | |
case Some(args) => args | |
case None => return '{Text.EMPTY} | |
checkSizes(parts.size - 1, args.size) | |
def firstPartEmpty: Boolean = parts.head.isEmpty | |
def singleArgOf[T: scala.quoted.Type]: Boolean = | |
parts.forall(_.isEmpty) && parts.size == 2 && firstArgIs[T] | |
def firstArgIs[T](given tpe: scala.quoted.Type[T]): Boolean = | |
firstPartEmpty && args.headOption.exists(h => h.unseal.tpe <:< tpe.unseal.tpe) | |
def castObj(e: Expr[Any]): Expr[AnyRef] = | |
e.unseal.tpe.seal match | |
case '[Byte] => '{ $e.asInstanceOf[java.lang.Byte] } | |
case '[Short] => '{ $e.asInstanceOf[java.lang.Short] } | |
case '[Int] => '{ $e.asInstanceOf[java.lang.Integer] } | |
case '[Long] => '{ $e.asInstanceOf[java.lang.Long] } | |
case '[Float] => '{ $e.asInstanceOf[java.lang.Float] } | |
case '[Double] => '{ $e.asInstanceOf[java.lang.Double] } | |
case '[Boolean] => '{ $e.asInstanceOf[java.lang.Boolean] } | |
case '[Unit] => '{ $e.asInstanceOf[scala.runtime.BoxedUnit] } | |
case _ => e.cast[AnyRef] | |
if singleArgOf[Score] then | |
'{ Text.of(${args.head.cast[Score]}) } | |
else if singleArgOf[Selector] then | |
'{ Text.of(${args.head.cast[Selector]}) } | |
else if firstArgIs[Translatable] then | |
val objsList = (partsExpr.tail.head +: args.tail.zip(partsExpr.tail.tail).flatMap((a, p) => Seq(a, p))).map(castObj) | |
val objs = Expr.ofSeq(objsList) | |
'{ Text.of(${args.head.cast[Translatable]}, $objs: _*) } | |
else if firstArgIs[Translation] then | |
val objsList = (partsExpr.tail.head +: args.tail.zip(partsExpr.tail.tail).flatMap((a, p) => Seq(a, p))).map(castObj) | |
val objs = Expr.ofSeq(objsList) | |
'{ Text.of(${args.head.cast[Translation]}, $objs: _*) } | |
else if parts.size == 1 && args.isEmpty then | |
'{ Text.of(${partsExpr.head}) } | |
else | |
val objsList = (partsExpr.head +: args.zip(partsExpr.tail).flatMap((a, p) => Seq(a, p))).map(castObj) | |
val objs = Expr.ofSeq(objsList) | |
'{ Text.of($objs: _*) } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment