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) } }