132 lines
3.4 KiB
Scala
132 lines
3.4 KiB
Scala
package minisql.parsing
|
|
|
|
import minisql.ast
|
|
import minisql.context.{ReturningMultipleFieldSupported, _}
|
|
import minisql.norm.BetaReduction
|
|
import minisql.norm.capture.AvoidAliasConflict
|
|
import minisql.idiom.Idiom
|
|
import scala.annotation.tailrec
|
|
import minisql.ast.Implicits._
|
|
import minisql.ast.Renameable.Fixed
|
|
import minisql.ast.Visibility.{Hidden, Visible}
|
|
import minisql.util.{Interleave, extractTerm}
|
|
import scala.quoted.*
|
|
|
|
type Parser[A] = PartialFunction[Expr[Any], Expr[A]]
|
|
|
|
private def termParser[A](using q: Quotes)(
|
|
pf: PartialFunction[q.reflect.Term, Expr[A]]
|
|
): Parser[A] = {
|
|
import quotes.reflect._
|
|
{
|
|
case e if pf.isDefinedAt(e.asTerm) => pf(e.asTerm)
|
|
}
|
|
}
|
|
|
|
private def parser[A](
|
|
f: PartialFunction[Expr[Any], Expr[A]]
|
|
)(using Quotes): Parser[A] = {
|
|
case e if f.isDefinedAt(e) => f(e)
|
|
}
|
|
|
|
private[minisql] object Parsing {
|
|
|
|
def parseExpr(
|
|
expr: Expr[?]
|
|
)(using q: Quotes): Expr[ast.Ast] = {
|
|
|
|
import q.reflect._
|
|
|
|
def unwrapped(
|
|
f: Parser[ast.Ast]
|
|
): Parser[ast.Ast] = {
|
|
case expr =>
|
|
val t = extractTerm(expr.asTerm)
|
|
if (t.isExpr)
|
|
f(t.asExpr)
|
|
else f(expr)
|
|
}
|
|
|
|
lazy val astParser: Parser[ast.Ast] =
|
|
unwrapped {
|
|
typedParser
|
|
.orElse(propertyParser)
|
|
.orElse(liftParser)
|
|
.orElse(infixParser)
|
|
.orElse(identParser)
|
|
.orElse(valueParser)
|
|
.orElse(operationParser)
|
|
.orElse(constantParser)
|
|
.orElse(blockParser)
|
|
.orElse(boxingParser)
|
|
.orElse(ifParser)
|
|
.orElse(traversableOperationParser)
|
|
.orElse(patMatchParser)
|
|
.orElse(aggParser)
|
|
.orElse {
|
|
case o =>
|
|
val str = scala.util.Try(o.show).getOrElse("")
|
|
report.errorAndAbort(
|
|
s"cannot parse ${str}",
|
|
o.asTerm.pos
|
|
)
|
|
}
|
|
}
|
|
|
|
lazy val typedParser: Parser[ast.Ast] = termParser {
|
|
case (Typed(t, _)) =>
|
|
astParser(t.asExpr)
|
|
}
|
|
|
|
lazy val blockParser: Parser[ast.Ast] = blockParsing(astParser)
|
|
|
|
lazy val valueParser: Parser[ast.Value] = valueParsing(astParser)
|
|
|
|
lazy val liftParser: Parser[ast.Lift] = liftParsing(astParser)
|
|
|
|
lazy val constantParser: Parser[ast.Constant] = termParser {
|
|
case Literal(x) =>
|
|
'{ ast.Constant(${ Literal(x).asExpr }) }
|
|
}
|
|
|
|
lazy val identParser: Parser[ast.Ident] = termParser {
|
|
case x @ Ident(n) =>
|
|
'{ ast.Ident(${ Expr(n) }) }
|
|
}
|
|
|
|
lazy val propertyParser: Parser[ast.Property] = propertyParsing(astParser)
|
|
|
|
lazy val operationParser: Parser[ast.Operation] = operationParsing(
|
|
astParser
|
|
)
|
|
|
|
lazy val boxingParser: Parser[ast.Ast] = boxingParsing(astParser)
|
|
|
|
lazy val ifParser: Parser[ast.If] = {
|
|
case '{ if ($a) $b else $c } =>
|
|
'{ ast.If(${ astParser(a) }, ${ astParser(b) }, ${ astParser(c) }) }
|
|
}
|
|
lazy val patMatchParser: Parser[ast.Ast] = patMatchParsing(astParser)
|
|
|
|
lazy val traversableOperationParser: Parser[ast.IterableOperation] =
|
|
traversableOperationParsing(astParser)
|
|
|
|
lazy val infixParser: Parser[ast.Infix] = infixParsing(
|
|
astParser
|
|
)
|
|
|
|
lazy val aggParser: Parser[ast.Aggregation] = {
|
|
case '{ ($t: minisql.GroupCollection[t]).size } =>
|
|
'{ ast.Aggregation(ast.AggregationOperator.size, ${ astParser(t) }) }
|
|
}
|
|
|
|
astParser(expr)
|
|
}
|
|
|
|
private[minisql] inline def parse[A](
|
|
inline a: A
|
|
): ast.Ast = ${
|
|
parseExpr('a)
|
|
}
|
|
|
|
}
|