You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pekko.apache.org by jr...@apache.org on 2022/11/03 11:23:37 UTC

[incubator-pekko-http] 07/47: parsing: use latest parboiled2 version

This is an automated email from the ASF dual-hosted git repository.

jrudolph pushed a commit to branch scala-3
in repository https://gitbox.apache.org/repos/asf/incubator-pekko-http.git

commit 9a589a3c3b66d86ef126b8cb948355759e86a5d7
Author: Johannes Rudolph <jo...@gmail.com>
AuthorDate: Tue Feb 15 16:18:13 2022 +0100

    parsing: use latest parboiled2 version
---
 .../scala-3/akka/parboiled2/ParserMacros.scala     | 985 +--------------------
 .../akka/parboiled2/support/HListable.scala        |   2 +-
 .../OpTreeContext.scala}                           | 212 +----
 3 files changed, 50 insertions(+), 1149 deletions(-)

diff --git a/akka-parsing/src/main/scala-3/akka/parboiled2/ParserMacros.scala b/akka-parsing/src/main/scala-3/akka/parboiled2/ParserMacros.scala
index 5654a6bfc..aeb06959f 100644
--- a/akka-parsing/src/main/scala-3/akka/parboiled2/ParserMacros.scala
+++ b/akka-parsing/src/main/scala-3/akka/parboiled2/ParserMacros.scala
@@ -16,9 +16,7 @@
 
 package akka.parboiled2
 
-import akka.parboiled2.support.hlist.HList
-
-import scala.annotation.tailrec
+import support.hlist.HList
 
 private[parboiled2] trait ParserMacroMethods { parser: Parser =>
 
@@ -45,985 +43,6 @@ private[parboiled2] trait RuleRunnable {
   }
 }
 
-import scala.quoted._
-class OpTreeContext(parser: Expr[Parser])(using Quotes) {
-  import quotes.reflect.*
-
-  sealed trait OpTree {
-    def render(wrapped: Boolean): Expr[Boolean]
-  }
-
-  sealed abstract class NonTerminalOpTree extends OpTree {
-    def bubbleUp(e: Expr[akka.parboiled2.Parser#TracingBubbleException], start: Expr[Int]): Expr[Nothing]
-
-    // renders a Boolean Tree
-    def render(wrapped: Boolean): Expr[Boolean] =
-      if (wrapped) '{
-        val start = $parser.cursor
-        try ${ renderInner('start, wrapped) } catch {
-          case e: akka.parboiled2.Parser#TracingBubbleException => ${ bubbleUp('e, 'start) }
-        }
-      }
-      else renderInner(Expr(-1) /* dummy, won't be used */, wrapped)
-
-    // renders a Boolean Tree
-    protected def renderInner(start: Expr[Int], wrapped: Boolean): Expr[Boolean]
-  }
-
-  sealed abstract class DefaultNonTerminalOpTree extends NonTerminalOpTree {
-    def bubbleUp(e: Expr[akka.parboiled2.Parser#TracingBubbleException], start: Expr[Int]): Expr[Nothing] = '{
-      $e.bubbleUp($ruleTraceNonTerminalKey, $start)
-    }
-    def ruleTraceNonTerminalKey: Expr[RuleTrace.NonTerminalKey]
-  }
-
-  sealed abstract class TerminalOpTree extends OpTree {
-    def bubbleUp: Expr[Nothing] = '{ $parser.__bubbleUp($ruleTraceTerminal) }
-    def ruleTraceTerminal: Expr[RuleTrace.Terminal]
-
-    final def render(wrapped: Boolean): Expr[Boolean] =
-      if (wrapped) '{
-        try ${ renderInner(wrapped) } catch { case akka.parboiled2.Parser.StartTracingException => $bubbleUp }
-      }
-      else renderInner(wrapped)
-
-    protected def renderInner(wrapped: Boolean): Expr[Boolean]
-  }
-  sealed abstract private class PotentiallyNamedTerminalOpTree(arg: Term) extends TerminalOpTree {
-    override def bubbleUp: Expr[Nothing] =
-      callName(arg) match {
-        case Some(name) =>
-          '{ $parser.__bubbleUp(RuleTrace.NonTerminal(RuleTrace.Named(${ Expr(name) }), 0) :: Nil, $ruleTraceTerminal) }
-        case None => super.bubbleUp
-      }
-  }
-
-  def Sequence(lhs: OpTree, rhs: OpTree): Sequence =
-    lhs -> rhs match {
-      case (Sequence(lops), Sequence(rops)) => Sequence(lops ++ rops)
-      case (Sequence(lops), _)              => Sequence(lops :+ rhs)
-      case (_, Sequence(ops))               => Sequence(lhs +: ops)
-      case _                                => Sequence(Seq(lhs, rhs))
-    }
-
-  case class Sequence(ops: Seq[OpTree]) extends DefaultNonTerminalOpTree {
-    require(ops.size >= 2)
-    override def ruleTraceNonTerminalKey = '{ RuleTrace.Sequence }
-    override def renderInner(start: quoted.Expr[Int], wrapped: Boolean): Expr[Boolean] =
-      ops
-        .map(_.render(wrapped))
-        .reduceLeft((l, r) => '{ val ll = $l; if (ll) $r else false })
-  }
-
-  case class Cut(lhs: OpTree, rhs: OpTree) extends DefaultNonTerminalOpTree {
-    override def ruleTraceNonTerminalKey = '{ RuleTrace.Cut }
-    override def renderInner(start: Expr[Int], wrapped: Boolean): Expr[Boolean] = '{
-      var matched = ${ lhs.render(wrapped) }
-      if (matched) {
-        matched = ${ rhs.render(wrapped) }
-        if (!matched) throw akka.parboiled2.Parser.CutError
-        true
-      } else false
-    } // work-around for https://issues.scala-lang.org/browse/SI-8657
-  }
-
-  def FirstOf(lhs: OpTree, rhs: OpTree): FirstOf =
-    lhs -> rhs match {
-      case (FirstOf(lops), FirstOf(rops)) => FirstOf(lops ++ rops)
-      case (FirstOf(lops), _)             => FirstOf(lops :+ rhs)
-      case (_, FirstOf(ops))              => FirstOf(lhs +: ops)
-      case _                              => FirstOf(Seq(lhs, rhs))
-    }
-  case class FirstOf(ops: Seq[OpTree]) extends DefaultNonTerminalOpTree {
-    def ruleTraceNonTerminalKey = '{ RuleTrace.FirstOf }
-
-    def renderInner(start: Expr[Int], wrapped: Boolean): Expr[Boolean] =
-      '{
-        val mark = $parser.__saveState
-        ${
-          ops
-            .map(_.render(wrapped))
-            .reduceLeft((l0, r) =>
-              '{
-                val l = $l0
-                if (!l) {
-                  $parser.__restoreState(mark)
-                  $r
-                } else
-                  true // work-around for https://issues.scala-lang.org/browse/SI-8657", FIXME: still valid for dotty?
-              }
-            )
-        }
-      }
-  }
-
-  sealed abstract class WithSeparator extends DefaultNonTerminalOpTree {
-    def withSeparator(sep: Separator): OpTree
-  }
-
-  case class ZeroOrMore(op: OpTree, collector: Collector, separator: Separator = null) extends WithSeparator {
-    def withSeparator(sep: Separator) = copy(separator = sep)
-    def ruleTraceNonTerminalKey       = '{ RuleTrace.ZeroOrMore }
-
-    def renderInner(start: Expr[Int], wrapped: Boolean): Expr[Boolean] =
-      collector.withCollector { coll =>
-        '{
-          @ _root_.scala.annotation.tailrec
-          def rec(mark: akka.parboiled2.Parser.Mark): akka.parboiled2.Parser.Mark = {
-            val matched = ${ op.render(wrapped) }
-            if (matched) {
-              ${ coll.popToBuilder }
-              ${
-                if (separator eq null) '{ rec($parser.__saveState) }
-                else
-                  '{
-                    val m = $parser.__saveState
-                    if (${ separator(wrapped) }) rec(m) else m
-                  }
-              }
-            } else mark
-          }
-
-          $parser.__restoreState(rec($parser.__saveState))
-          ${ coll.pushBuilderResult }
-          true
-        }
-      }
-  }
-  case class OneOrMore(op: OpTree, collector: Collector, separator: Separator = null) extends WithSeparator {
-    def withSeparator(sep: Separator) = copy(separator = sep)
-    def ruleTraceNonTerminalKey       = '{ RuleTrace.OneOrMore }
-
-    def renderInner(start: Expr[Int], wrapped: Boolean): Expr[Boolean] =
-      collector.withCollector { coll =>
-        '{
-          @ _root_.scala.annotation.tailrec
-          def rec(mark: akka.parboiled2.Parser.Mark): akka.parboiled2.Parser.Mark = {
-            val matched = ${ op.render(wrapped) }
-            if (matched) {
-              ${ coll.popToBuilder }
-              ${
-                if (separator eq null) '{ rec($parser.__saveState) }
-                else
-                  '{
-                    val m = $parser.__saveState
-                    if (${ separator(wrapped) }) rec(m) else m
-                  }
-              }
-            } else mark
-          }
-
-          val firstMark = $parser.__saveState
-          val mark      = rec(firstMark)
-          mark != firstMark && { // FIXME: almost the same as ZeroOrMore and should be combined
-            $parser.__restoreState(mark)
-            ${ coll.pushBuilderResult }
-            true
-          }
-        }
-      }
-  }
-
-  case class Optional(op: OpTree, collector: Collector) extends DefaultNonTerminalOpTree {
-    def ruleTraceNonTerminalKey = '{ RuleTrace.Optional }
-    def renderInner(start: Expr[Int], wrapped: Boolean): Expr[Boolean] =
-      collector.withCollector { coll =>
-        '{
-          val mark    = $parser.__saveState
-          val matched = ${ op.render(wrapped) }
-          if (matched) {
-            ${ coll.pushSomePop }
-          } else {
-            $parser.__restoreState(mark)
-            ${ coll.pushNone }
-          }
-          true
-        }
-      }
-  }
-
-  trait MinMaxSupplier {
-    def apply[T: Type](f: (Expr[Int], Expr[Int]) => Expr[T]): Expr[T]
-  }
-  object MinMaxSupplier {
-    def constant(n: Expr[Int]): MinMaxSupplier =
-      new MinMaxSupplier {
-        override def apply[T: Type](f: (Expr[Int], Expr[Int]) => Expr[T]): Expr[T] =
-          '{
-            val min = $n
-            val max = min
-
-            ${ f('min, 'max) }
-          }
-      }
-
-    def range(rangeExpr: Expr[Range]): MinMaxSupplier =
-      new MinMaxSupplier {
-        override def apply[T: Type](f: (Expr[Int], Expr[Int]) => Expr[T]): Expr[T] =
-          '{
-            val r   = $rangeExpr
-            val min = r.min
-            val max = r.max
-
-            ${ f('min, 'max) }
-          }
-      }
-
-    /* FIXME: implement optimzations for literal values as shown below
-
-base match {
-  case q"$a.this.int2NTimes($n)" =>
-    n match {
-      case Literal(Constant(i: Int)) =>
-        if (i <= 0) c.abort(base.pos, "`x` in `x.times` must be positive")
-        else if (i == 1) rule
-        else Times(rule, q"val min, max = $n", collector, separator)
-      case x @ (Ident(_) | Select(_, _)) => Times(rule, q"val min = $n; val max = min", collector, separator)
-      case _                             => c.abort(n.pos, "Invalid int base expression for `.times(...)`: " + n)
-    }
-  case q"$a.this.range2NTimes($r)" =>
-    r match {
-      case q"${_}.Predef.intWrapper($mn).to($mx)" =>
-        mn match {
-          case Literal(Constant(min: Int)) =>
-            if (min <= 0) c.abort(mn.pos, "`min` in `(min to max).times` must be positive")
-          case (Ident(_) | Select(_, _)) =>
-          case _                         => c.abort(r.pos, "Invalid int range expression for `min` in `.times(...)`: " + r)
-        }
-        mx match {
-          case Literal(Constant(max: Int)) =>
-            if (max <= 0) c.abort(mx.pos, "`max` in `(min to max).times` must be positive")
-          case (Ident(_) | Select(_, _)) =>
-          case _                         => c.abort(r.pos, "Invalid int range expression for `max` in `.times(...)`: " + r)
-        }
-        (mn, mx) match {
-          case (Literal(Constant(min: Int)), Literal(Constant(max: Int))) =>
-            if (max < min) c.abort(mx.pos, "`max` in `(min to max).times` must be >= `min`")
-          case _ =>
-        }
-        Times(rule, q"val min = $mn; val max = $mx", collector, separator)
-      case x @ (Ident(_) | Select(_, _)) =>
-        Times(rule, q"val r = $r; val min = r.start; val max = r.end", collector, separator)
-      case _ => c.abort(r.pos, "Invalid range base expression for `.times(...)`: " + r)
-    }
-  case _ => c.abort(base.pos, "Invalid base expression for `.times(...)`: " + base)
-}*/
-  }
-
-  case class Times(
-      op: OpTree,
-      withMinMax: MinMaxSupplier,
-      collector: Collector,
-      separator: Separator
-  ) extends WithSeparator {
-    def withSeparator(sep: Separator) = copy(separator = sep)
-    def ruleTraceNonTerminalKey       = withMinMax((min, max) => '{ akka.parboiled2.RuleTrace.Times($min, $max) })
-
-    def renderInner(start: Expr[Int], wrapped: Boolean): Expr[Boolean] =
-      collector.withCollector { coll =>
-        withMinMax { (minE, maxE) =>
-          '{
-            val min = $minE
-            val max = $maxE
-            require(min <= max, "`max` in `(min to max).times` must be >= `min`")
-
-            @ _root_.scala.annotation.tailrec
-            def rec(count: Int, mark: akka.parboiled2.Parser.Mark): Boolean = {
-              val matched = ${ op.render(wrapped) }
-              if (matched) {
-                ${ coll.popToBuilder }
-                if (count < max) ${
-                  if (separator eq null) '{ rec(count + 1, $parser.__saveState) }
-                  else
-                    '{
-                      val m = $parser.__saveState
-                      if (${ separator(wrapped) }) rec(count + 1, m)
-                      else (count >= min) && { $parser.__restoreState(m); true }
-                    }
-                }
-                else true
-
-              } else (count > min) && { $parser.__restoreState(mark); true }
-            }
-
-            (max <= 0) || rec(1, $parser.__saveState) && { ${ coll.pushBuilderResult }; true }
-          }
-        }
-      }
-  }
-
-  case class AndPredicate(op: OpTree) extends DefaultNonTerminalOpTree {
-    def ruleTraceNonTerminalKey = '{ RuleTrace.AndPredicate }
-    def renderInner(start: Expr[Int], wrapped: Boolean): Expr[Boolean] =
-      '{
-        val mark    = $parser.__saveState
-        val matched = ${ op.render(wrapped) }
-        $parser.__restoreState(mark)
-        matched
-      }
-  }
-
-  case class NotPredicate(op: OpTree) extends OpTree {
-
-    def render(wrapped: Boolean): Expr[Boolean] = {
-      def unwrappedExpr(setMatchEnd: Option[Expr[Int] => Expr[Unit]]): Expr[Boolean] = '{
-        val mark    = $parser.__saveState
-        val saved   = $parser.__enterNotPredicate()
-        val matched = ${ op.render(wrapped) }
-        $parser.__exitNotPredicate(saved)
-        ${
-          setMatchEnd match {
-            case Some(matchEndSetter) => matchEndSetter('{ $parser.cursor })
-            case None                 => '{}
-          }
-        }
-        $parser.__restoreState(mark)
-        !matched
-      }
-
-      if (wrapped) {
-        val base = op match {
-          case x: TerminalOpTree   => '{ RuleTrace.NotPredicate.Terminal(${ x.ruleTraceTerminal }) }
-          case x: RuleCall         => '{ RuleTrace.NotPredicate.RuleCall(${ x.calleeNameTree }) }
-          case x: StringMatch      => '{ RuleTrace.NotPredicate.Named(s"\"${${ x.stringTree }}\"") }
-          case x: IgnoreCaseString => '{ RuleTrace.NotPredicate.Named(s"\"${${ x.stringTree }}\"") }
-          case x: Named            => '{ RuleTrace.NotPredicate.Named(s"\"${${ x.stringExpr }}\"") }
-          case _                   => '{ RuleTrace.NotPredicate.Anonymous }
-        }
-        '{
-          var matchEnd = 0
-          try ${ unwrappedExpr(Some(v => '{ matchEnd = $v })) } || $parser.__registerMismatch()
-          catch {
-            case Parser.StartTracingException =>
-              $parser.__bubbleUp {
-                RuleTrace.NotPredicate($base, matchEnd - $parser.cursor)
-              }
-          }
-        }
-      } else unwrappedExpr(None)
-    }
-  }
-
-  private def expandLambda(body: Term, wrapped: Boolean): Expr[Boolean] = {
-    def popToVals(valdefs: List[ValDef]): List[Statement] = {
-      def convertOne(v: ValDef): ValDef =
-        v.tpt.tpe.asType match {
-          case '[t] => ValDef.copy(v)(v.name, v.tpt, Some('{ $parser.valueStack.pop().asInstanceOf[t] }.asTerm))
-        }
-
-      valdefs.map(convertOne).reverse
-    }
-
-    body match {
-      case Lambda(args, body) =>
-        def rewrite(tree: Term): Term =
-          tree.tpe.asType match {
-            case '[Rule[_, _]] => expand(tree, wrapped).asInstanceOf[Term]
-            case _ =>
-              tree match {
-                case Block(statements, res) => block(statements, rewrite(res))
-                case x                      => '{ $parser.__push(${ x.asExpr }) }.asTerm
-              }
-          }
-        // do a beta reduction, using the parameter definitions as stubs for variables
-        // that hold values popped from the stack
-        block(popToVals(args), rewrite(body)).asExprOf[Boolean]
-    }
-  }
-
-  private case class Action(body: Term, ts: List[TypeTree]) extends DefaultNonTerminalOpTree {
-    def ruleTraceNonTerminalKey = '{ RuleTrace.Action }
-
-    def renderInner(start: Expr[Int], wrapped: Boolean): Expr[Boolean] = expandLambda(body, wrapped)
-  }
-
-  case class RunAction(body: Expr[_]) extends DefaultNonTerminalOpTree {
-    def ruleTraceNonTerminalKey = '{ RuleTrace.Run }
-
-    def renderInner(start: Expr[Int], wrapped: Boolean): Expr[Boolean] =
-      body.asTerm.tpe.asType match {
-        case '[Rule[_, _]]                => expand(body, wrapped)
-        case '[t1 => r]                   => expandLambda(body.asTerm, wrapped)
-        case '[(t1, t2) => r]             => expandLambda(body.asTerm, wrapped)
-        case '[(t1, t2, t3) => r]         => expandLambda(body.asTerm, wrapped)
-        case '[(t1, t2, t3, t4) => r]     => expandLambda(body.asTerm, wrapped)
-        case '[(t1, t2, t3, t4, t5) => r] => expandLambda(body.asTerm, wrapped)
-        case '[x]                         => '{ $body; true }
-      }
-  }
-
-  case class SemanticPredicate(flagTree: Expr[Boolean]) extends TerminalOpTree {
-    def ruleTraceTerminal = '{ akka.parboiled2.RuleTrace.SemanticPredicate }
-
-    override def renderInner(wrapped: Boolean): Expr[Boolean] =
-      if (wrapped) '{ $flagTree || $parser.__registerMismatch() }
-      else flagTree
-  }
-
-  case class Capture(op: OpTree) extends DefaultNonTerminalOpTree {
-    def ruleTraceNonTerminalKey = '{ RuleTrace.Capture }
-    def renderInner(start: Expr[Int], wrapped: Boolean): Expr[Boolean] =
-      '{
-        val start1  = ${ if (wrapped) start else '{ $parser.cursor } }
-        val matched = ${ op.render(wrapped) }
-        if (matched) {
-          $parser.valueStack.push($parser.input.sliceString(start1, $parser.cursor))
-          true
-        } else false
-      }
-  }
-
-  private case class PushAction(valueExpr: Expr[_], argType: Type[_]) extends OpTree {
-    def render(wrapped: Boolean): Expr[Boolean] = {
-      val body =
-        argType match {
-          case '[Unit]  => valueExpr
-          case '[HList] => '{ $parser.valueStack.pushAll($valueExpr.asInstanceOf[HList]) }
-          case _        => '{ $parser.valueStack.push($valueExpr) }
-        }
-
-      '{
-        $body
-        true
-      }
-    }
-  }
-  private case class DropAction(tpe: Type[_]) extends OpTree {
-    def render(wrapped: Boolean): Expr[Boolean] = {
-      import support.hlist._
-      val body =
-        tpe match {
-          case '[Unit] => '{}
-          case '[HList] =>
-            @tailrec def rec(t: Type[_], prefix: Expr[Unit]): Expr[Unit] = t match {
-              case '[HNil] => prefix
-              case '[h :: t] =>
-                rec(Type.of[t], '{ $prefix; $parser.valueStack.pop() })
-
-            }
-            rec(tpe, '{})
-
-          case _ => '{ $parser.valueStack.pop() }
-        }
-
-      '{
-        $body
-        true
-      }
-    }
-  }
-
-  private case class RuleCall(call: Either[OpTree, Expr[Rule[_, _]]], calleeNameTree: Expr[String])
-      extends NonTerminalOpTree {
-
-    def bubbleUp(e: Expr[Parser#TracingBubbleException], start: Expr[Int]): Expr[Nothing] =
-      '{ $e.prepend(RuleTrace.RuleCall, $start).bubbleUp(RuleTrace.Named($calleeNameTree), $start) }
-
-    override def render(wrapped: Boolean): Expr[Boolean] = call match {
-      case Left(_)     => super.render(wrapped)
-      case Right(rule) => '{ $rule ne null }
-    }
-    protected def renderInner(start: Expr[Int], wrapped: Boolean): Expr[Boolean] = {
-      val Left(value) = call
-      value.render(wrapped)
-    }
-  }
-
-  case class CharMatch(charTree: Expr[Char]) extends TerminalOpTree {
-    def ruleTraceTerminal = '{ akka.parboiled2.RuleTrace.CharMatch($charTree) }
-    override def renderInner(wrapped: Boolean): Expr[Boolean] = {
-      val unwrappedTree = '{
-        $parser.cursorChar == $charTree && $parser.__advance()
-      }
-      if (wrapped) '{ $unwrappedTree && $parser.__updateMaxCursor() || $parser.__registerMismatch() }
-      else unwrappedTree
-    }
-  }
-
-  case class StringMatch(stringTree: Expr[String]) extends OpTree {
-    final private val autoExpandMaxStringLength = 8
-
-    override def render(wrapped: Boolean): Expr[Boolean] = {
-      def unrollUnwrapped(s: String, ix: Int = 0): Expr[Boolean] =
-        if (ix < s.length)
-          '{
-            if ($parser.cursorChar == ${ Expr(s.charAt(ix)) }) {
-              $parser.__advance()
-              ${ unrollUnwrapped(s, ix + 1) }
-            } else false
-          }
-        else '{ true }
-
-      def unrollWrapped(s: String, ix: Int = 0): Expr[Boolean] =
-        if (ix < s.length) {
-          val ch = Expr(s.charAt(ix))
-          '{
-            if ($parser.cursorChar == $ch) {
-              $parser.__advance()
-              $parser.__updateMaxCursor()
-              ${ unrollWrapped(s, ix + 1) }
-            } else {
-              try $parser.__registerMismatch()
-              catch {
-                case akka.parboiled2.Parser.StartTracingException =>
-                  import akka.parboiled2.RuleTrace._
-                  $parser.__bubbleUp(
-                    NonTerminal(akka.parboiled2.RuleTrace.StringMatch($stringTree), -${ Expr(ix) }) :: Nil,
-                    akka.parboiled2.RuleTrace.CharMatch($ch)
-                  )
-              }
-            }
-          }
-        } else '{ true }
-
-      stringTree.asTerm match {
-        case Literal(StringConstant(s: String)) if s.length <= autoExpandMaxStringLength =>
-          if (s.isEmpty) '{ true }
-          else if (wrapped) unrollWrapped(s)
-          else unrollUnwrapped(s)
-        case _ =>
-          if (wrapped) '{ $parser.__matchStringWrapped($stringTree) }
-          else '{ $parser.__matchString($stringTree) }
-      }
-    }
-  }
-
-  case class MapMatch(mapTree: Expr[Map[String, Any]], ignoreCaseTree: Expr[Boolean]) extends OpTree {
-
-    override def render(wrapped: Boolean): Expr[Boolean] =
-      if (wrapped) '{ $parser.__matchMapWrapped($mapTree, $ignoreCaseTree) }
-      else '{ $parser.__matchMap($mapTree, $ignoreCaseTree) }
-  }
-
-  case class IgnoreCaseChar(charTree: Expr[Char]) extends TerminalOpTree {
-    def ruleTraceTerminal = '{ akka.parboiled2.RuleTrace.IgnoreCaseChar($charTree) }
-
-    override def renderInner(wrapped: Boolean): Expr[Boolean] = {
-      val unwrappedTree = '{
-        _root_.java.lang.Character.toLowerCase($parser.cursorChar) == $charTree && $parser.__advance()
-      }
-      if (wrapped) '{ $unwrappedTree && $parser.__updateMaxCursor() || $parser.__registerMismatch() }
-      else unwrappedTree
-    }
-  }
-
-  case class IgnoreCaseString(stringTree: Expr[String]) extends OpTree {
-    final private val autoExpandMaxStringLength = 8
-
-    override def render(wrapped: Boolean): Expr[Boolean] =
-      def unrollUnwrapped(s: String, ix: Int = 0): Expr[Boolean] =
-        if (ix < s.length)
-          '{
-            if (_root_.java.lang.Character.toLowerCase($parser.cursorChar) == ${ Expr(s.charAt(ix)) }) {
-              $parser.__advance()
-              ${ unrollUnwrapped(s, ix + 1) }
-            } else false
-          }
-        else '{ true }
-
-      def unrollWrapped(s: String, ix: Int = 0): Expr[Boolean] =
-        if (ix < s.length) {
-          val ch = Expr(s.charAt(ix))
-          '{
-            if (_root_.java.lang.Character.toLowerCase($parser.cursorChar) == $ch) {
-              $parser.__advance()
-              $parser.__updateMaxCursor()
-              ${ unrollWrapped(s, ix + 1) }
-            } else {
-              try $parser.__registerMismatch()
-              catch {
-                case akka.parboiled2.Parser.StartTracingException =>
-                  import akka.parboiled2.RuleTrace._
-                  $parser.__bubbleUp(
-                    NonTerminal(akka.parboiled2.RuleTrace.IgnoreCaseString($stringTree), -${ Expr(ix) }) :: Nil,
-                    akka.parboiled2.RuleTrace.IgnoreCaseChar($ch)
-                  )
-              }
-            }
-          }
-        } else '{ true }
-
-      stringTree.asTerm match {
-        case Literal(StringConstant(s: String)) if s.length <= autoExpandMaxStringLength =>
-          if (s.isEmpty) '{ true }
-          else if (wrapped) unrollWrapped(s)
-          else unrollUnwrapped(s)
-        case _ =>
-          if (wrapped) '{ $parser.__matchIgnoreCaseStringWrapped($stringTree) }
-          else '{ $parser.__matchIgnoreCaseString($stringTree) }
-      }
-  }
-
-  private case class CharPredicateMatch(predicateTree: Expr[CharPredicate])
-      extends PotentiallyNamedTerminalOpTree(predicateTree.asTerm) {
-    def ruleTraceTerminal = '{ akka.parboiled2.RuleTrace.CharPredicateMatch($predicateTree) }
-
-    override def renderInner(wrapped: Boolean): Expr[Boolean] = {
-      val unwrappedTree = '{ $predicateTree($parser.cursorChar) && $parser.__advance() }
-      if (wrapped) '{ $unwrappedTree && $parser.__updateMaxCursor() || $parser.__registerMismatch() }
-      else unwrappedTree
-    }
-  }
-
-  case class AnyOf(stringTree: Expr[String]) extends TerminalOpTree {
-    def ruleTraceTerminal = '{ akka.parboiled2.RuleTrace.AnyOf($stringTree) }
-
-    override def renderInner(wrapped: Boolean): Expr[Boolean] = {
-      val unwrappedTree = '{ $parser.__matchAnyOf($stringTree) }
-      if (wrapped) '{ $unwrappedTree && $parser.__updateMaxCursor() || $parser.__registerMismatch() }
-      else unwrappedTree
-    }
-  }
-
-  case class NoneOf(stringTree: Expr[String]) extends TerminalOpTree {
-    def ruleTraceTerminal = '{ akka.parboiled2.RuleTrace.NoneOf($stringTree) }
-
-    override def renderInner(wrapped: Boolean): Expr[Boolean] = {
-      val unwrappedTree = '{ $parser.__matchNoneOf($stringTree) }
-      if (wrapped) '{ $unwrappedTree && $parser.__updateMaxCursor() || $parser.__registerMismatch() }
-      else unwrappedTree
-    }
-  }
-
-  case object ANY extends TerminalOpTree {
-    def ruleTraceTerminal = '{ akka.parboiled2.RuleTrace.ANY }
-
-    override def renderInner(wrapped: Boolean): Expr[Boolean] = {
-      val unwrappedTree = '{ $parser.cursorChar != EOI && $parser.__advance() }
-      if (wrapped) '{ $unwrappedTree && $parser.__updateMaxCursor() || $parser.__registerMismatch() }
-      else unwrappedTree
-    }
-  }
-
-  case class Unknown(syntax: String, tree: String, outerSyntax: String) extends TerminalOpTree {
-    override def ruleTraceTerminal: Expr[RuleTrace.Terminal] =
-      '{ RuleTrace.Fail(s"unknown rule: $$infoExpr") }
-
-    override protected def renderInner(wrapped: Boolean): Expr[Boolean] =
-      '{
-        throw new RuntimeException(
-          s"unknown rule: [${${ Expr(syntax) }}] '${${ Expr(tree) }}' in [${${ Expr(outerSyntax) }}]"
-        )
-      }
-  }
-
-  def CharRange(lowerTree: Expr[String], upperTree: Expr[String]): CharacterRange =
-    (lowerTree.value, upperTree.value) match {
-      case (Some(lower), Some(upper)) =>
-        if (lower.length != 1) reportError("lower bound must be a single char string", lowerTree)
-        if (upper.length != 1) reportError("upper bound must be a single char string", upperTree)
-        val lowerBoundChar = lower.charAt(0)
-        val upperBoundChar = upper.charAt(0)
-        if (lowerBoundChar > upperBoundChar) reportError("lower bound must not be > upper bound", lowerTree)
-        CharacterRange(Expr(lowerBoundChar), Expr(upperBoundChar))
-      case _ => reportError("Character ranges must be specified with string literals", lowerTree)
-    }
-
-  case class CharacterRange(lowerBound: Expr[Char], upperBound: Expr[Char]) extends TerminalOpTree {
-    def ruleTraceTerminal = '{ akka.parboiled2.RuleTrace.CharRange($lowerBound, $upperBound) }
-
-    override def renderInner(wrapped: Boolean): Expr[Boolean] = {
-      val unwrappedTree = '{
-        val char = $parser.cursorChar
-        $lowerBound <= char && char <= $upperBound && $parser.__advance()
-      }
-      if (wrapped) '{ $unwrappedTree && $parser.__updateMaxCursor() || $parser.__registerMismatch() }
-      else unwrappedTree
-    }
-  }
-
-  case class Fail(stringExpr: Expr[String]) extends OpTree {
-    def render(wrapped: Boolean): Expr[Boolean] = '{ throw new akka.parboiled2.Parser.Fail($stringExpr) }
-  }
-  case class Named(op: OpTree, stringExpr: Expr[String]) extends DefaultNonTerminalOpTree {
-    def ruleTraceNonTerminalKey                                        = '{ RuleTrace.Named($stringExpr) }
-    def renderInner(start: Expr[Int], wrapped: Boolean): Expr[Boolean] = op.render(wrapped)
-  }
-  case class Atomic(op: OpTree) extends DefaultNonTerminalOpTree {
-    def ruleTraceNonTerminalKey = '{ RuleTrace.Atomic }
-
-    def renderInner(start: Expr[Int], wrapped: Boolean): Expr[Boolean] =
-      if (wrapped) '{
-        val saved   = $parser.__enterAtomic($start)
-        val matched = ${ op.render(wrapped) }
-        $parser.__exitAtomic(saved)
-        matched
-      }
-      else op.render(wrapped)
-  }
-
-  case class Quiet(op: OpTree) extends DefaultNonTerminalOpTree {
-    def ruleTraceNonTerminalKey = '{ RuleTrace.Quiet }
-
-    def renderInner(start: Expr[Int], wrapped: Boolean): Expr[Boolean] =
-      if (wrapped) '{
-        val saved   = $parser.__enterQuiet()
-        val matched = ${ op.render(wrapped) }
-        $parser.__exitQuiet(saved)
-        matched
-      }
-      else op.render(wrapped)
-  }
-
-  def topLevel(opTree: OpTree, name: Expr[String]): OpTree = RuleCall(Left(opTree), name)
-
-  def deconstruct(outerRule: Expr[Rule[_, _]]): OpTree = deconstructPF(outerRule).get
-  def deconstructPF(outerRule: Expr[Rule[_, _]]): Option[OpTree] = {
-    import quotes.reflect.*
-
-    def collector(lifter: Term): Collector =
-      lifter match {
-        case TypeApply(Ident("forRule0" | "forReduction"), _) => rule0Collector
-        case TypeApply(Ident("forRule1"), _)                  => rule1Collector
-        case x                                                => reportError(s"Unexpected lifter ${lifter.show(using Printer.TreeStructure)}", lifter.asExpr)
-      }
-
-    // a list of names for operations that are not yet implemented but that should not be interpreted as rule calls
-    // FIXME: can be removed when everything is implemented
-    val ruleNameBlacklist =
-      Set(
-        "str",
-        "!",
-        "?",
-        "&",
-        "optional",
-        "run",
-        "zeroOrMore",
-        "times",
-        "oneOrMore",
-        "rule2ActionOperator",
-        "range2NTimes",
-        "rule2WithSeparatedBy"
-      )
-
-    lazy val rules0PF: PartialFunction[Expr[Rule[_, _]], OpTree] = {
-      case '{ ($p: Parser).ch($c) }                                                        => CharMatch(c)
-      case '{ ($p: Parser).str($s) }                                                       => StringMatch(s)
-      case '{ ($p: Parser).valueMap($m: Map[String, Any]) }                                => MapMatch(m, '{ false })
-      case '{ ($p: Parser).valueMap($m: Map[String, Any], $ic) }                           => MapMatch(m, ic)
-      case '{ ($p: Parser).ignoreCase($c: Char) }                                          => IgnoreCaseChar(c)
-      case '{ ($p: Parser).ignoreCase($s: String) }                                        => IgnoreCaseString(s)
-      case '{ ($p: Parser).predicate($pr) }                                                => CharPredicateMatch(pr)
-      case '{ ($p: Parser).anyOf($s) }                                                     => AnyOf(s)
-      case '{ ($p: Parser).noneOf($s) }                                                    => NoneOf(s)
-      case '{ ($p: Parser).ANY }                                                           => ANY
-      case '{ ($p: Parser).str2CharRangeSupport($l).-($r) }                                => CharRange(l, r)
-      case '{ ($p: Parser).test($flag) }                                                   => SemanticPredicate(flag)
-      case '{ ($p: Parser).push[t]($value) }                                               => PushAction(value, Type.of[t])
-      case '{ ($p: Parser).drop[t] }                                                       => DropAction(Type.of[t])
-      case '{ type i <: HList; type o <: HList; ($p: Parser).capture[`i`, `o`]($arg)($l) } => Capture(rec(arg.asTerm))
-      case '{
-            type i1 <: HList; type o1 <: HList
-            type i2 <: HList; type o2 <: HList
-            ($lhs: Rule[`i1`, `o1`]).~[`i2`, `o2`]($rhs)($_, $_)
-          } =>
-        Sequence(Seq(rec(lhs.asTerm), rec(rhs.asTerm)))
-
-      case '{
-            type i1 <: HList; type o1 <: HList
-            type i2 <: `i1`; type o2 >: `o1` <: HList
-            ($lhs: Rule[`i1`, `o1`]).|[`i2`, `o2`]($rhs)
-          } =>
-        FirstOf(rec(lhs.asTerm), rec(rhs.asTerm))
-
-      case '{
-            type i1 <: HList; type o1 <: HList
-            type i2 <: HList; type o2 <: HList
-            ($lhs: Rule[`i1`, `o1`]).~!~[`i2`, `o2`]($rhs)($_, $_)
-          } =>
-        Cut(rec(lhs.asTerm), rec(rhs.asTerm))
-
-      case '{ type i <: HList; type o <: HList; ($p: Parser).zeroOrMore[`i`, `o`]($arg)($l) } =>
-        ZeroOrMore(rec(arg.asTerm), collector(l.asTerm))
-
-      case '{ type i <: HList; type o <: HList; ($base: Rule[`i`, `o`]).*($l: support.Lifter[Seq, `i`, `o`]) } =>
-        ZeroOrMore(rec(base.asTerm), collector(l.asTerm))
-
-      case '{
-            type i <: HList; type o <: HList; ($base: Rule[`i`, `o`]).*($sep: Rule0)($l: support.Lifter[Seq, `i`, `o`])
-          } =>
-        ZeroOrMore(rec(base.asTerm), collector(l.asTerm), Separator(rec(sep.asTerm)))
-
-      case '{ type i <: HList; type o <: HList; ($p: Parser).oneOrMore[`i`, `o`]($arg)($l) } =>
-        OneOrMore(rec(arg.asTerm), collector(l.asTerm))
-
-      case '{ type i <: HList; type o <: HList; ($base: Rule[`i`, `o`]).+($l: support.Lifter[Seq, `i`, `o`]) } =>
-        OneOrMore(rec(base.asTerm), collector(l.asTerm))
-
-      case '{
-            type i <: HList; type o <: HList; ($base: Rule[`i`, `o`]).+($sep: Rule0)($l: support.Lifter[Seq, `i`, `o`])
-          } =>
-        OneOrMore(rec(base.asTerm), collector(l.asTerm), Separator(rec(sep.asTerm)))
-
-      case '{ type i <: HList; type o <: HList; ($p: Parser).optional[`i`, `o`]($arg)($l) } =>
-        Optional(rec(arg.asTerm), collector(l.asTerm))
-
-      case '{ type i <: HList; type o <: HList; ($base: Rule[`i`, `o`]).?($l: support.Lifter[Option, `i`, `o`]) } =>
-        Optional(rec(base.asTerm), collector(l.asTerm))
-
-      case '{ type i <: HList; type o <: HList; ($p: Parser).int2NTimes($n).times[`i`, `o`]($arg)($l) } =>
-        Times(
-          rec(arg.asTerm),
-          MinMaxSupplier.constant(n),
-          collector(l.asTerm),
-          null
-        )
-      case '{ type i <: HList; type o <: HList; ($p: Parser).range2NTimes($r).times[`i`, `o`]($arg)($l) } =>
-        Times(
-          rec(arg.asTerm),
-          MinMaxSupplier.range(r),
-          collector(l.asTerm),
-          null
-        )
-
-      case '{ type i <: HList; type o <: HList; !($arg: Rule[`i`, `o`]) } =>
-        NotPredicate(rec(arg.asTerm))
-
-      case '{ ($p: Parser).&($arg) } =>
-        AndPredicate(rec(arg.asTerm))
-
-      case '{
-            type i <: HList; type o <: HList; ($p: Parser).rule2WithSeparatedBy[`i`, `o`]($base).separatedBy($sep)
-          } =>
-        rec(base.asTerm) match {
-          case ws: WithSeparator => ws.withSeparator(Separator(rec(sep.asTerm)))
-          case _                 => reportError(s"Illegal `separatedBy` base: $base", base)
-        }
-
-      case '{ ($p: Parser).run[t]($e)($l) }                                           => RunAction(e)
-      case '{ type i <: HList; type o <: HList; ($base: Rule[`i`, `o`]).named($str) } => Named(rec(base.asTerm), str)
-      case '{ type i <: HList; type o <: HList; ($p: Parser).atomic[`i`, `o`]($r) }   => Atomic(rec(r.asTerm))
-      case '{ type i <: HList; type o <: HList; ($p: Parser).quiet[`i`, `o`]($r) }    => Quiet(rec(r.asTerm))
-      case '{ ($p: Parser).fail($str) }                                               => Fail(str)
-      case '{ type i <: HList; type o <: HList; ($p: Parser).failX[`i`, `o`]($str) }  => Fail(str)
-    }
-
-    lazy val rules1PF: PartialFunction[Term, OpTree] = {
-      // cannot easily be converted because we would have to list all ActionOps instances
-      case Apply(
-            Apply(
-              TypeApply(
-                Select(
-                  Select(Apply(Apply(TypeApply(Select(_, "rule2ActionOperator"), _), List(base)), _), "~>"),
-                  "apply"
-                ),
-                _
-              ),
-              List(body)
-            ),
-            List(_, TypeApply(Ident("apply"), ts))
-          ) =>
-        Sequence(rec(base), Action(body, ts))
-
-      case call @ (Apply(_, _) | Select(_, _) | Ident(_) | TypeApply(_, _))
-          if !callName(call).exists(ruleNameBlacklist) =>
-        RuleCall(
-          Right(call.asExprOf[Rule[_, _]]),
-          Expr(callName(call) getOrElse reportError("Illegal rule call: " + call, call.asExpr))
-        )
-      //case _ => Unknown(rule.show, rule.show(using Printer.TreeStructure), outerRule.toString)
-    }
-    lazy val allRules = rules0PF.orElse(rules1PF.compose[Expr[Rule[_, _]]] { case x => x.asTerm.underlyingArgument })
-    def rec(rule: Term): OpTree = allRules.applyOrElse(
-      rule.asExprOf[Rule[_, _]],
-      rule => Unknown(rule.show, "" /*rule.show(using Printer.TreeStructure)*/, outerRule.toString)
-    )
-
-    allRules.lift(outerRule)
-  }
-
-  private def reportError(error: String, expr: Expr[Any]): Nothing = {
-    quotes.reflect.report.error(error, expr)
-    throw new scala.quoted.runtime.StopMacroExpansion
-  }
-
-  /////////////////////////////////// helpers ////////////////////////////////////
-
-  trait Collector {
-    def withCollector(f: CollectorInstance => Expr[Boolean]): Expr[Boolean]
-  }
-  trait CollectorInstance {
-    def popToBuilder: Expr[Unit]
-    def pushBuilderResult: Expr[Unit]
-    def pushSomePop: Expr[Unit]
-    def pushNone: Expr[Unit]
-  }
-
-  // no-op collector
-  object rule0Collector extends Collector with CollectorInstance {
-    override def withCollector(f: CollectorInstance => Expr[Boolean]): Expr[Boolean] = f(this)
-    private val unit: Expr[Unit]                                                     = '{}
-    def popToBuilder: Expr[Unit]                                                     = unit
-    def pushBuilderResult: Expr[Unit]                                                = unit
-    def pushSomePop: Expr[Unit]                                                      = unit
-    def pushNone: Expr[Unit]                                                         = unit
-  }
-
-  object rule1Collector extends Collector {
-    override def withCollector(f: CollectorInstance => Expr[Boolean]): Expr[Boolean] = '{
-      val builder = new scala.collection.immutable.VectorBuilder[Any]
-      ${
-        f(new CollectorInstance {
-          def popToBuilder: Expr[Unit]      = '{ builder += $parser.valueStack.pop() }
-          def pushBuilderResult: Expr[Unit] = '{ $parser.valueStack.push(builder.result()) }
-          def pushSomePop: Expr[Unit]       = '{ $parser.valueStack.push(Some($parser.valueStack.pop())) }
-          def pushNone: Expr[Unit]          = '{ $parser.valueStack.push(None) }
-        })
-      }
-    }
-  }
-
-  type Separator = Boolean => Expr[Boolean]
-  private def Separator(op: OpTree): Separator = wrapped => op.render(wrapped)
-
-  @tailrec
-  private def callName(tree: Term): Option[String] =
-    tree match {
-      case Ident(name)       => Some(name)
-      case Select(_, name)   => Some(name)
-      case Apply(fun, _)     => callName(fun)
-      case TypeApply(fun, _) => callName(fun)
-      case _                 => None
-    }
-
-  // tries to match and expand the leaves of the given Tree
-  private def expand(expr: Expr[_], wrapped: Boolean): Expr[Boolean] =
-    expand(expr.asTerm, wrapped).asExprOf[Boolean]
-  private def expand(tree: Tree, wrapped: Boolean): Tree =
-    tree match {
-      case Block(statements, res) => block(statements, expand(res, wrapped).asInstanceOf[Term])
-      case If(cond, thenExp, elseExp) =>
-        If(cond, expand(thenExp, wrapped).asInstanceOf[Term], expand(elseExp, wrapped).asInstanceOf[Term])
-      case Match(selector, cases)    => Match(selector, cases.map(expand(_, wrapped).asInstanceOf[CaseDef]))
-      case CaseDef(pat, guard, body) => CaseDef(pat, guard, expand(body, wrapped).asInstanceOf[Term])
-      case x =>
-        deconstructPF(x.asExprOf[Rule[_, _]])                  // can we pass the body as a rule?
-          .map(_.render(wrapped))                              // then render it
-          .getOrElse('{ ${ x.asExprOf[Rule[_, _]] } ne null }) // otherwise, assume the expression is a rule itself
-          .asTerm
-    }
-
-  private def block(a: Term, b: Term): Term =
-    a match {
-      case Block(a1, a2) =>
-        b match {
-          case Block(b1, b2) => Block(a1 ::: a2 :: b1, b2)
-          case _             => Block(a1 ::: a2 :: Nil, b)
-        }
-      case _ =>
-        b match {
-          case Block(b1, b2) => Block(a :: b1, b2)
-          case _             => Block(a :: Nil, b)
-        }
-    }
-
-  private def block(stmts: List[Statement], expr: Term): Term =
-    expr match {
-      case Block(a, b) => block(stmts ::: a ::: Nil, b)
-      case _           => Block(stmts, expr)
-    }
-}
-
 object ParserMacros {
   import scala.quoted._
   import scala.compiletime._
@@ -1113,7 +132,7 @@ object ParserMacros {
   ): Expr[Rule[I, O]] = {
     import quotes.reflect.*
 
-    val ctx    = new OpTreeContext(parser)
+    val ctx    = new support.OpTreeContext(parser)
     val opTree = ctx.topLevel(ctx.deconstruct(r), name)
 
     '{
diff --git a/akka-parsing/src/main/scala-3/akka/parboiled2/support/HListable.scala b/akka-parsing/src/main/scala-3/akka/parboiled2/support/HListable.scala
index 2440a2f0b..49b28e6c3 100644
--- a/akka-parsing/src/main/scala-3/akka/parboiled2/support/HListable.scala
+++ b/akka-parsing/src/main/scala-3/akka/parboiled2/support/HListable.scala
@@ -16,7 +16,7 @@
 
 package akka.parboiled2.support
 
-import akka.parboiled2.support.hlist._
+import hlist._
 
 trait HListable[T] {
   type Out <: HList
diff --git a/akka-parsing/src/main/scala-3/akka/parboiled2/ParserMacros.scala b/akka-parsing/src/main/scala-3/akka/parboiled2/support/OpTreeContext.scala
similarity index 84%
copy from akka-parsing/src/main/scala-3/akka/parboiled2/ParserMacros.scala
copy to akka-parsing/src/main/scala-3/akka/parboiled2/support/OpTreeContext.scala
index 5654a6bfc..e49bc4984 100644
--- a/akka-parsing/src/main/scala-3/akka/parboiled2/ParserMacros.scala
+++ b/akka-parsing/src/main/scala-3/akka/parboiled2/support/OpTreeContext.scala
@@ -14,38 +14,14 @@
  * limitations under the License.
  */
 
-package akka.parboiled2
+package akka.parboiled2.support
 
+import akka.parboiled2._
 import akka.parboiled2.support.hlist.HList
 
+import scala.quoted._
 import scala.annotation.tailrec
 
-private[parboiled2] trait ParserMacroMethods { parser: Parser =>
-
-  /** Converts a compile-time only rule definition into the corresponding rule method implementation.
-    */
-  inline def rule[I <: HList, O <: HList](inline r: Rule[I, O]): Rule[I, O] = ${ ParserMacros.ruleImpl('parser, 'r) }
-
-  /** Converts a compile-time only rule definition into the corresponding rule method implementation
-    * with an explicitly given name.
-    */
-  inline def namedRule[I <: HList, O <: HList](name: String)(inline r: Rule[I, O]): Rule[I, O] = ${
-    ParserMacros.nameRuleImpl('parser, 'name, 'r)
-  }
-
-}
-
-private[parboiled2] trait RuleRunnable {
-
-  /** THIS IS NOT PUBLIC API and might become hidden in future. Use only if you know what you are doing!
-    */
-  extension [L <: HList](inline rule: RuleN[L]) {
-    inline def run()(using scheme: Parser.DeliveryScheme[L]): scheme.Result =
-      ${ ParserMacros.runImpl[L, scheme.Result]()('rule, 'scheme) }
-  }
-}
-
-import scala.quoted._
 class OpTreeContext(parser: Expr[Parser])(using Quotes) {
   import quotes.reflect.*
 
@@ -268,46 +244,52 @@ class OpTreeContext(parser: Expr[Parser])(using Quotes) {
             ${ f('min, 'max) }
           }
       }
+  }
 
-    /* FIXME: implement optimzations for literal values as shown below
-
-base match {
-  case q"$a.this.int2NTimes($n)" =>
-    n match {
-      case Literal(Constant(i: Int)) =>
-        if (i <= 0) c.abort(base.pos, "`x` in `x.times` must be positive")
-        else if (i == 1) rule
-        else Times(rule, q"val min, max = $n", collector, separator)
-      case x @ (Ident(_) | Select(_, _)) => Times(rule, q"val min = $n; val max = min", collector, separator)
-      case _                             => c.abort(n.pos, "Invalid int base expression for `.times(...)`: " + n)
+  def Int2NTimes(
+      n: Expr[Int],
+      op: OpTree,
+      withMinMax: MinMaxSupplier,
+      collector: Collector,
+      separator: Separator
+  ): OpTree =
+    n.asTerm match {
+      case Literal(IntConstant(i)) =>
+        if (i <= 0) reportError("`x` in `x.times` must be positive", n)
+        else if (i == 1) op
+        else Times(op, withMinMax, collector, separator)
+      case _ =>
+        Times(op, withMinMax, collector, separator)
     }
-  case q"$a.this.range2NTimes($r)" =>
-    r match {
-      case q"${_}.Predef.intWrapper($mn).to($mx)" =>
-        mn match {
-          case Literal(Constant(min: Int)) =>
-            if (min <= 0) c.abort(mn.pos, "`min` in `(min to max).times` must be positive")
-          case (Ident(_) | Select(_, _)) =>
-          case _                         => c.abort(r.pos, "Invalid int range expression for `min` in `.times(...)`: " + r)
+
+  def Range2NTimes(
+      range: Expr[Range],
+      op: OpTree,
+      withMinMax: MinMaxSupplier,
+      collector: Collector,
+      separator: Separator
+  ): OpTree = {
+    range match {
+      case '{ scala.Predef.intWrapper($mn).to($mx) } =>
+        mn.asTerm match {
+          case Literal(IntConstant(min)) if min <= 0 =>
+            reportError("`min` in `(min to max).times` must be positive", mn)
+          case _ => ()
         }
-        mx match {
-          case Literal(Constant(max: Int)) =>
-            if (max <= 0) c.abort(mx.pos, "`max` in `(min to max).times` must be positive")
-          case (Ident(_) | Select(_, _)) =>
-          case _                         => c.abort(r.pos, "Invalid int range expression for `max` in `.times(...)`: " + r)
+        mx.asTerm match {
+          case Literal(IntConstant(max)) if max <= 0 =>
+            reportError("`max` in `(min to max).times` must be positive", mx)
+          case _ => ()
         }
-        (mn, mx) match {
-          case (Literal(Constant(min: Int)), Literal(Constant(max: Int))) =>
-            if (max < min) c.abort(mx.pos, "`max` in `(min to max).times` must be >= `min`")
-          case _ =>
+        (mn.asTerm, mx.asTerm) match {
+          case (Literal(IntConstant(min)), Literal(IntConstant(max))) if max < min =>
+            reportError("`max` in `(min to max).times` must be >= `min`", mx)
+          case _ => ()
         }
-        Times(rule, q"val min = $mn; val max = $mx", collector, separator)
-      case x @ (Ident(_) | Select(_, _)) =>
-        Times(rule, q"val r = $r; val min = r.start; val max = r.end", collector, separator)
-      case _ => c.abort(r.pos, "Invalid range base expression for `.times(...)`: " + r)
+        Times(op, withMinMax, collector, separator)
+      case _ =>
+        reportError("Invalid base expression for `.times(...)`: " + range.show, range)
     }
-  case _ => c.abort(base.pos, "Invalid base expression for `.times(...)`: " + base)
-}*/
   }
 
   case class Times(
@@ -862,14 +844,16 @@ base match {
         Optional(rec(base.asTerm), collector(l.asTerm))
 
       case '{ type i <: HList; type o <: HList; ($p: Parser).int2NTimes($n).times[`i`, `o`]($arg)($l) } =>
-        Times(
+        Int2NTimes(
+          n,
           rec(arg.asTerm),
           MinMaxSupplier.constant(n),
           collector(l.asTerm),
           null
         )
       case '{ type i <: HList; type o <: HList; ($p: Parser).range2NTimes($r).times[`i`, `o`]($arg)($l) } =>
-        Times(
+        Range2NTimes(
+          r,
           rec(arg.asTerm),
           MinMaxSupplier.range(r),
           collector(l.asTerm),
@@ -1023,105 +1007,3 @@ base match {
       case _           => Block(stmts, expr)
     }
 }
-
-object ParserMacros {
-  import scala.quoted._
-  import scala.compiletime._
-
-  // TODO: the `R` type parameter is a workaround for https://github.com/lampepfl/dotty/issues/13376
-  // Discussion at https://github.com/sirthias/parboiled2/pull/274#issuecomment-904926294
-  def runImpl[L <: HList: Type, R: Type]()(ruleExpr: Expr[RuleN[L]], schemeExpr: Expr[Parser.DeliveryScheme[L]])(using
-      Quotes
-  ): Expr[R] = {
-    import quotes.reflect.*
-
-    /*
-    the `rule.run()` macro supports two scenarios (`rule` has type `RuleN[L]`):
-
-    1. someParserExpression.rule[targs](args).run()(deliveryScheme)
-       is re-written to
-       { val p = someParserExpression
-         p.__run[L](p.rule[targs](args))(deliveryScheme) }
-
-    2. Within a Parser subclass:
-         rule(...).run()(deliveryScheme)
-       is re-written to
-         this.__run[L](rule(...))(deliveryScheme)
-       Note that `rule` is also a macro, we work with the macro expansion of the `rule` call.
-     */
-
-    case class RuleFromParser(parser: Term, rule: Symbol, targs: List[TypeTree], argss: List[List[Term]]) {
-      def ruleCall[P](localParser: Expr[P]): Expr[RuleN[L]] = {
-        val r = Select(localParser.asTerm, rule)
-        argss.foldLeft(if (targs.isEmpty) r else TypeApply(r, targs))((t, args) => Apply(t, args)).asExprOf[RuleN[L]]
-      }
-    }
-
-    object RuleFromParser {
-      def dissect(t: Term, targs: List[TypeTree], argss: List[List[Term]]): (Term, List[TypeTree], List[List[Term]]) =
-        t.underlyingArgument match {
-          case Apply(f, args)      => dissect(f, targs, args :: argss)
-          case TypeApply(f, targs) => dissect(f, targs, argss)
-          case t                   => (t, targs, argss)
-        }
-
-      def unapply(t: Term): Option[RuleFromParser] = dissect(t, Nil, Nil) match {
-        case (rule @ Select(parser, _), targs, argss) if parser.tpe <:< TypeRepr.of[Parser] =>
-          Some(RuleFromParser(parser, rule.symbol, targs, argss))
-        case _ => None
-      }
-    }
-
-    def isRuleMacro(sym: Symbol) =
-      sym.owner == TypeRepr.of[ParserMacroMethods].typeSymbol &&
-        (sym.name == "rule" || sym.name == "namedRule")
-
-    ruleExpr.asTerm match {
-      case RuleFromParser(rule) =>
-        rule.parser.tpe.asType match {
-          case '[pT] =>
-            // TODO: the parser type `pT` is not bounded by `<: Parser`, not sure how to do that.
-            // This is why `asInstanceOf[Parser]` is needed below
-            val parserExpr = rule.parser.asExprOf[pT]
-            '{
-              val p: pT = $parserExpr
-              p.asInstanceOf[Parser].__run[L](${ rule.ruleCall('p) })($schemeExpr).asInstanceOf[R]
-            }
-        }
-      case Inlined(_, _, Inlined(Some(ruleMacro), List(ValDef(_, _, Some(parserThis))), rule))
-          if rule.tpe <:< TypeRepr.of[RuleX] && isRuleMacro(ruleMacro.symbol) =>
-        // The `Inlined` tree for the `rule` macro has a binding for the parser instance.
-        // TODO: we re-use the rhs of that binding (parserThis), I didn't manage to create the right This() tree.
-        '{ ${ parserThis.asExprOf[Parser] }.__run[L]($ruleExpr)($schemeExpr).asInstanceOf[R] }
-      case r =>
-        report.error(s"""Cannot rewrite `myRule.run()` call for rule: ${ruleExpr.show}
-                        |`myRule` needs to be either of the form `someParser.someRule[targs](args)`
-                        |or it needs to be a `rule(...)` definition within a Parser subclass.""".stripMargin)
-        throw new MatchError(r)
-    }
-  }
-
-  def ruleImpl[I <: HList: Type, O <: HList: Type](parser: Expr[Parser], r: Expr[Rule[I, O]])(using
-      Quotes
-  ): Expr[Rule[I, O]] = {
-    import quotes.reflect.*
-    nameRuleImpl(parser, Expr(Symbol.spliceOwner.owner.name), r)
-  }
-
-  def nameRuleImpl[I <: HList: Type, O <: HList: Type](parser: Expr[Parser], name: Expr[String], r: Expr[Rule[I, O]])(
-      using Quotes
-  ): Expr[Rule[I, O]] = {
-    import quotes.reflect.*
-
-    val ctx    = new OpTreeContext(parser)
-    val opTree = ctx.topLevel(ctx.deconstruct(r), name)
-
-    '{
-      def wrapped: Boolean = ${ opTree.render(wrapped = true) }
-      val matched =
-        if ($parser.__inErrorAnalysis) wrapped
-        else ${ opTree.render(wrapped = false) }
-      if (matched) akka.parboiled2.Rule.asInstanceOf[Rule[I, O]] else null
-    }
-  }
-}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pekko.apache.org
For additional commands, e-mail: commits-help@pekko.apache.org