Created
December 28, 2019 02:05
-
-
Save johnynek/ca0bca529f01b98c1d66aac04273380b to your computer and use it in GitHub Desktop.
attempt at using staging to make a parser in scala 3
This file contains hidden or 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
/** | |
* Error: | |
* | |
[info] Compiling 1 Scala source to /home/oscar/oss/olelo/target/scala-0.21/classes ... | |
[error] -- Error: /home/oscar/oss/olelo/src/main/scala/Olelo.scala:13:14 --------------- | |
[error] 13 | p.toExpr | |
[error] | ^ | |
[error] | access to type A from wrong staging level: | |
[error] | - the definition is at level 0, | |
[error] | - but the access is at level 1. | |
[error] | | |
[error] | The access would be accepted with an implict scala.quoted.Type[A] | |
[error] one error found | |
[error] (Compile / compileIncremental) Compilation failed | |
*/ | |
package olelo | |
import scala.quoted._ | |
import scala.quoted.staging._ | |
object Olelo { | |
sealed abstract class Parser[+A] { | |
def toExpr[A1 >: A](given QuoteContext, Type[A1]): Expr[String => Either[Int, (String, A1)]] | |
} | |
inline def compile[A](p: => Parser[A])(given Toolbox): String => Either[Int, (String, A)] = { | |
run { | |
p.toExpr | |
} | |
} | |
def str(s: String): Parser[Unit] = | |
Impl.Literal(s) | |
given [A](parser: Parser[A]) extended with { | |
def |(that: Parser[A]): Parser[A] = | |
Impl.Or(parser :: that :: Nil) | |
} | |
object Impl { | |
case class Literal(target: String) extends Parser[Unit] { | |
def toExpr[A1 >: Unit](given QuoteContext, Type[A1]) = { | |
val targ = Expr(target) | |
if (target.isEmpty) '{ | |
val good = Right(("", ())) | |
val bad = Left(0) | |
{ (s: String) => if (s.isEmpty) good else bad } | |
} | |
else { | |
'{ | |
val tlen = ${targ}.length | |
{ (s: String) => | |
var idx = 0 | |
val slen = s.length | |
var res: Either[Int, (String, Unit)] = null | |
while (idx < tlen) { | |
if (idx < slen) { | |
if (s.charAt(idx) == ${targ}.charAt(idx)) { | |
idx = idx + 1 | |
} | |
else { | |
res = Left(idx) | |
idx = tlen | |
} | |
} | |
else { | |
res = Left(idx) | |
idx = tlen | |
} | |
} | |
if (res == null) Right((s.substring(idx), ())) else res | |
} | |
} | |
} | |
} | |
} | |
case class Or[A](items: List[Parser[A]]) extends Parser[A] { | |
def toExpr[A1 >: A](given QuoteContext, Type[A1]) = { | |
def loop(items: List[Parser[A]]): Expr[String => Either[Int, (String, A1)]] = | |
items match { | |
case Nil => | |
'{ (s: String) => Left(0) } | |
case h :: tail => | |
val tailFn = loop(tail) | |
val headFn = h.toExpr[A1] | |
'{ (s: String) => | |
val res = ${Expr.betaReduce(headFn)('s)} | |
if (res.isLeft) ${Expr.betaReduce(tailFn)('s)} | |
else res | |
} | |
} | |
loop(items) | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment