minisql/src/main/scala/minisql/parsing/Parsing.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)
}
}