Skip to content

Commit 9fe1b5b

Browse files
MF42-DZHj-mie6
andauthoredJun 29, 2023
Add indexed Visitor classes for LazyParsley (#206)
* feat: add visitor for LazyParsley used for matching and processing while carrying context without having to pattern match or type match must be extended every time a new internal parser class is added * refactor: marked visitors as visible only to parsley.internal * test: add tests for laziness preservation and for testing if the visitors are running properly. also fixed Lift3's missing laziness in the visitor class. * style: shortened lines for visit implementations within LazyParsley classes * fix: strengthened GenericLazyParsleyIVisitor's private bound to frontend, also explicitly declared Any type parameter for *> and <*'s default implementations in that generic visitor * fix: explicitly declared ManyUntil and SkipManyUntil's default overrides' type arguments to visitUnary due to Any inference * fix: LazyParsleyIVisitor's private bound weakened further to parsley to match LazyParsley's private upper bound * fix: subbed functions for partial case analyses where appropriate --------- Co-authored-by: Jamie Willis <j.willis19@imperial.ac.uk>
1 parent 5c81ecb commit 9fe1b5b

18 files changed

+620
-2
lines changed
 

‎parsley/shared/src/main/scala/parsley/internal/deepembedding/frontend/AlternativeEmbedding.scala

+2
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,6 @@ private [parsley] final class <|>[A](p: LazyParsley[A], q: LazyParsley[A]) exten
1515
p <- suspend(p.optimised[M, R, A])
1616
q <- suspend(q.optimised[M, R, A])
1717
} yield backend.<|>(p, q)
18+
19+
final override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[A] = visitor.visit(this)(context, p, q)
1820
}

‎parsley/shared/src/main/scala/parsley/internal/deepembedding/frontend/ErrorEmbedding.scala

+14
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,39 @@ import parsley.internal.deepembedding.backend, backend.StrictParsley
77

88
private [parsley] final class ErrorLabel[A](p: LazyParsley[A], private [ErrorLabel] val labels: Seq[String]) extends Unary[A, A](p) {
99
override def make(p: StrictParsley[A]): StrictParsley[A] = new backend.ErrorLabel(p, labels)
10+
11+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[A] = visitor.visit(this, context)(p, labels)
1012
}
1113
private [parsley] final class ErrorExplain[A](p: LazyParsley[A], reason: String) extends Unary[A, A](p) {
1214
override def make(p: StrictParsley[A]): StrictParsley[A] = new backend.ErrorExplain(p, reason)
15+
16+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[A] = visitor.visit(this, context)(p, reason)
1317
}
1418

1519
private [parsley] final class ErrorAmend[A](p: LazyParsley[A], partial: Boolean) extends Unary[A, A](p) {
1620
override def make(p: StrictParsley[A]): StrictParsley[A] = new backend.ErrorAmend(p, partial)
21+
22+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[A] = visitor.visit(this, context)(p, partial)
1723
}
1824
private [parsley] final class ErrorEntrench[A](p: LazyParsley[A]) extends Unary[A, A](p) {
1925
override def make(p: StrictParsley[A]): StrictParsley[A] = new backend.ErrorEntrench(p)
26+
27+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[A] = visitor.visit(this, context)(p)
2028
}
2129
private [parsley] final class ErrorDislodge[A](n: Int, p: LazyParsley[A]) extends Unary[A, A](p) {
2230
override def make(p: StrictParsley[A]): StrictParsley[A] = new backend.ErrorDislodge(n, p)
31+
32+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[A] = visitor.visit(this, context)(n, p)
2333
}
2434

2535
private [parsley] final class ErrorLexical[A](p: LazyParsley[A]) extends Unary[A, A](p) {
2636
override def make(p: StrictParsley[A]): StrictParsley[A] = new backend.ErrorLexical(p)
37+
38+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[A] = visitor.visit(this, context)(p)
2739
}
2840

2941
private [parsley] final class VerifiedError[A](p: LazyParsley[A], msggen: Either[A => Seq[String], Option[A => String]]) extends Unary[A, Nothing](p) {
3042
override def make(p: StrictParsley[A]): StrictParsley[Nothing] = new backend.VerifiedError(p, msggen)
43+
44+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[Nothing] = visitor.visit(this, context)(p, msggen)
3145
}

‎parsley/shared/src/main/scala/parsley/internal/deepembedding/frontend/IntrinsicEmbedding.scala

+6
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,17 @@ import parsley.internal.deepembedding.backend, backend.StrictParsley
99

1010
private [parsley] final class Lift2[A, B, C](private [Lift2] val f: (A, B) => C, p: LazyParsley[A], q: =>LazyParsley[B]) extends Binary[A, B, C](p, q) {
1111
override def make(p: StrictParsley[A], q: StrictParsley[B]): StrictParsley[C] = new backend.Lift2(f, p, q)
12+
13+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[C] = visitor.visit(this, context)(f, p, q)
1214
}
1315
private [parsley] final class Lift3[A, B, C, D](private [Lift3] val f: (A, B, C) => D, p: LazyParsley[A], q: =>LazyParsley[B], r: =>LazyParsley[C])
1416
extends Ternary[A, B, C, D](p, q, r) {
1517
override def make(p: StrictParsley[A], q: StrictParsley[B], r: StrictParsley[C]): StrictParsley[D] = new backend.Lift3(f, p, q, r)
18+
19+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[D] = visitor.visit(this, context)(f, p, q, r)
1620
}
1721
private [parsley] final class Local[S, A](val reg: Reg[S], p: LazyParsley[S], q: =>LazyParsley[A]) extends Binary[S, A, A](p, q) with UsesRegister {
1822
override def make(p: StrictParsley[S], q: StrictParsley[A]): StrictParsley[A] = new backend.Local(reg, p, q)
23+
24+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[A] = visitor.visit(this, context)(reg, p, q)
1925
}

‎parsley/shared/src/main/scala/parsley/internal/deepembedding/frontend/IterativeEmbedding.scala

+18
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,18 @@ import parsley.internal.deepembedding.backend, backend.StrictParsley
88

99
private [parsley] final class Many[A](p: LazyParsley[A]) extends Unary[A, List[A]](p) {
1010
override def make(p: StrictParsley[A]): StrictParsley[List[A]] = new backend.Many(p)
11+
12+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[List[A]] = visitor.visit(this, context)(p)
1113
}
1214
private [parsley] final class SkipMany[A](p: LazyParsley[A]) extends Unary[A, Unit](p) {
1315
override def make(p: StrictParsley[A]): StrictParsley[Unit] = new backend.SkipMany(p)
16+
17+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[Unit] = visitor.visit(this, context)(p)
1418
}
1519
private [parsley] final class ChainPost[A](p: LazyParsley[A], _op: =>LazyParsley[A => A]) extends Binary[A, A => A, A](p, _op) {
1620
override def make(p: StrictParsley[A], op: StrictParsley[A => A]): StrictParsley[A] = new backend.ChainPost(p, op)
21+
22+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[A] = visitor.visit(this, context)(p, _op)
1723
}
1824
private [parsley] final class ChainPre[A](p: LazyParsley[A], op: LazyParsley[A => A]) extends LazyParsley[A] {
1925
final override def findLetsAux[M[_, _]: ContOps, R](seen: Set[LazyParsley[_]])(implicit state: LetFinderState): M[R, Unit] = {
@@ -24,21 +30,33 @@ private [parsley] final class ChainPre[A](p: LazyParsley[A], op: LazyParsley[A =
2430
p <- suspend(p.optimised[M, R, A])
2531
op <- suspend(op.optimised[M, R, A => A])
2632
} yield new backend.ChainPre(p, op)
33+
34+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[A] = visitor.visit(this, context)(p, op)
2735
}
2836
private [parsley] final class Chainl[A, B](init: LazyParsley[B], p: =>LazyParsley[A], op: =>LazyParsley[(B, A) => B])
2937
extends Ternary[B, A, (B, A) => B, B](init, p, op) {
3038
override def make(init: StrictParsley[B], p: StrictParsley[A], op: StrictParsley[(B, A) => B]): StrictParsley[B] = new backend.Chainl(init, p, op)
39+
40+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[B] = visitor.visit(this, context)(init, p, op)
3141
}
3242
private [parsley] final class Chainr[A, B](p: LazyParsley[A], op: =>LazyParsley[(A, B) => B], private [Chainr] val wrap: A => B)
3343
extends Binary[A, (A, B) => B, B](p, op) {
3444
override def make(p: StrictParsley[A], op: StrictParsley[(A, B) => B]): StrictParsley[B] = new backend.Chainr(p, op, wrap)
45+
46+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[B] = visitor.visit(this, context)(p, op, wrap)
3547
}
3648
private [parsley] final class SepEndBy1[A, B](p: LazyParsley[A], sep: =>LazyParsley[B]) extends Binary[A, B, List[A]](p, sep) {
3749
override def make(p: StrictParsley[A], sep: StrictParsley[B]): StrictParsley[List[A]] = new backend.SepEndBy1(p, sep)
50+
51+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[List[A]] = visitor.visit(this, context)(p, sep)
3852
}
3953
private [parsley] final class ManyUntil[A](body: LazyParsley[Any]) extends Unary[Any, List[A]](body) {
4054
override def make(p: StrictParsley[Any]): StrictParsley[List[A]] = new backend.ManyUntil(p)
55+
56+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[List[A]] = visitor.visit(this, context)(body)
4157
}
4258
private [parsley] final class SkipManyUntil(body: LazyParsley[Any]) extends Unary[Any, Unit](body) {
4359
override def make(p: StrictParsley[Any]): StrictParsley[Unit] = new backend.SkipManyUntil(p)
60+
61+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[Unit] = visitor.visit(this, context)(body)
4462
}

‎parsley/shared/src/main/scala/parsley/internal/deepembedding/frontend/LazyParsley.scala

+4
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,10 @@ private [parsley] abstract class LazyParsley[+A] private [deepembedding] {
188188
}
189189
}
190190

191+
// Processing with visitors.
192+
/** Use a visitor implementation to process this internal lazy parser. */
193+
def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[A]
194+
191195
// $COVERAGE-OFF$
192196
/** Pretty-prints a combinator tree, for internal debugging purposes only. */
193197
final private [internal] def prettyAST: String = {

‎parsley/shared/src/main/scala/parsley/internal/deepembedding/frontend/PrimitiveEmbedding.scala

+14
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,39 @@ import parsley.internal.deepembedding.backend, backend.StrictParsley
1111

1212
private [parsley] final class Attempt[A](p: LazyParsley[A]) extends Unary[A, A](p) {
1313
override def make(p: StrictParsley[A]): StrictParsley[A] = new backend.Attempt(p)
14+
15+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[A] = visitor.visit(this, context)(p)
1416
}
1517
private [parsley] final class Look[A](p: LazyParsley[A]) extends Unary[A, A](p) {
1618
override def make(p: StrictParsley[A]): StrictParsley[A] = new backend.Look(p)
19+
20+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[A] = visitor.visit(this, context)(p)
1721
}
1822
private [parsley] final class NotFollowedBy[A](p: LazyParsley[A]) extends Unary[A, Unit](p) {
1923
override def make(p: StrictParsley[A]): StrictParsley[Unit] = new backend.NotFollowedBy(p)
24+
25+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[Unit] = visitor.visit(this, context)(p)
2026
}
2127
private [parsley] final class Put[S](val reg: Reg[S], _p: LazyParsley[S]) extends Unary[S, Unit](_p) with UsesRegister {
2228
override def make(p: StrictParsley[S]): StrictParsley[Unit] = new backend.Put(reg, p)
29+
30+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[Unit] = visitor.visit(this, context)(reg, _p)
2331
}
2432
private [parsley] final class NewReg[S, A](val reg: Reg[S], init: LazyParsley[S], body: =>LazyParsley[A])
2533
extends Binary[S, A, A](init, body) with UsesRegister {
2634
override def make(init: StrictParsley[S], body: StrictParsley[A]): StrictParsley[A] = new backend.NewReg(reg, init, body)
35+
36+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[A] = visitor.visit(this, context)(reg, init, body)
2737
}
2838
// $COVERAGE-OFF$
2939
private [parsley] final class Debug[A](p: LazyParsley[A], name: String, ascii: Boolean, break: Breakpoint) extends Unary[A, A](p) {
3040
override def make(p: StrictParsley[A]): StrictParsley[A] = new backend.Debug(p, name, ascii, break)
41+
42+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[A] = visitor.visit(this, context)(p, name, ascii, break)
3143
}
3244
private [parsley] final class DebugError[A](p: LazyParsley[A], name: String, ascii: Boolean, errBuilder: ErrorBuilder[_]) extends Unary[A, A](p) {
3345
override def make(p: StrictParsley[A]): StrictParsley[A] = new backend.DebugError(p, name, ascii, errBuilder)
46+
47+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[A] = visitor.visit(this, context)(p, name, ascii, errBuilder)
3448
}
3549
// $COVERAGE-ON$

‎parsley/shared/src/main/scala/parsley/internal/deepembedding/frontend/SelectiveEmbedding.scala

+14
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,38 @@ import parsley.internal.deepembedding.backend, backend.StrictParsley
88
private [parsley] final class Branch[A, B, C](b: LazyParsley[Either[A, B]], p: =>LazyParsley[A => C], q: =>LazyParsley[B => C])
99
extends Ternary[Either[A, B], A => C, B => C, C](b, p, q) {
1010
override def make(b: StrictParsley[Either[A, B]], p: StrictParsley[A => C], q: StrictParsley[B => C]): StrictParsley[C] = new backend.Branch(b, p, q)
11+
12+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[C] = visitor.visit(this, context)(b, p, q)
1113
}
1214

1315
private [parsley] final class If[A](b: LazyParsley[Boolean], p: =>LazyParsley[A], q: =>LazyParsley[A]) extends Ternary[Boolean, A, A, A](b, p, q) {
1416
override def make(b: StrictParsley[Boolean], p: StrictParsley[A], q: StrictParsley[A]): StrictParsley[A] = new backend.If(b, p, q)
17+
18+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[A] = visitor.visit(this, context)(b, p, q)
1519
}
1620

1721
private [parsley] final class Filter[A](p: LazyParsley[A], pred: A => Boolean) extends Unary[A, A](p) {
1822
override def make(p: StrictParsley[A]): StrictParsley[A] = new backend.Filter(p, pred)
23+
24+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[A] = visitor.visit(this, context)(p, pred)
1925
}
2026
private [parsley] final class MapFilter[A, B](p: LazyParsley[A], f: A => Option[B]) extends Unary[A, B](p) {
2127
override def make(p: StrictParsley[A]): StrictParsley[B] = new backend.MapFilter(p, f)
28+
29+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[B] = visitor.visit(this, context)(p, f)
2230
}
2331
private [parsley] final class FilterOut[A](p: LazyParsley[A], pred: PartialFunction[A, String]) extends Unary[A, A](p) {
2432
override def make(p: StrictParsley[A]): StrictParsley[A] = new backend.FilterOut(p, pred)
33+
34+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[A] = visitor.visit(this, context)(p, pred)
2535
}
2636
private [parsley] final class GuardAgainst[A](p: LazyParsley[A], pred: PartialFunction[A, Seq[String]]) extends Unary[A, A](p) {
2737
override def make(p: StrictParsley[A]): StrictParsley[A] = new backend.GuardAgainst(p, pred)
38+
39+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[A] = visitor.visit(this, context)(p, pred)
2840
}
2941
private [parsley] final class UnexpectedWhen[A](p: LazyParsley[A], pred: PartialFunction[A, (String, Option[String])]) extends Unary[A, A](p) {
3042
override def make(p: StrictParsley[A]): StrictParsley[A] = new backend.UnexpectedWhen(p, pred)
43+
44+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[A] = visitor.visit(this, context)(p, pred)
3145
}

‎parsley/shared/src/main/scala/parsley/internal/deepembedding/frontend/SequenceEmbedding.scala

+8
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,23 @@ import parsley.internal.deepembedding.backend, backend.StrictParsley
77

88
private [parsley] final class <*>[A, B](pf: LazyParsley[A => B], px: =>LazyParsley[A]) extends Binary[A => B, A, B](pf, px) {
99
override def make(pf: StrictParsley[A => B], px: StrictParsley[A]): StrictParsley[B] = new backend.<*>(pf, px)
10+
11+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[B] = visitor.visit(this, context)(pf, px)
1012
}
1113

1214
private [parsley] final class >>=[A, B](p: LazyParsley[A], private [>>=] val f: A => LazyParsley[B]) extends Unary[A, B](p) {
1315
override def make(p: StrictParsley[A]): StrictParsley[B] = new backend.>>=(p, f)
16+
17+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[B] = visitor.visit(this, context)(p, f)
1418
}
1519

1620
private [parsley] final class *>[A](_p: LazyParsley[_], _q: =>LazyParsley[A]) extends Binary[Any, A, A](_p, _q) {
1721
override def make(p: StrictParsley[Any], q: StrictParsley[A]): StrictParsley[A] = backend.*>(p, q)
22+
23+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[A] = visitor.visit(this, context)(_p, _q)
1824
}
1925
private [parsley] final class <*[A](_p: LazyParsley[A], _q: =>LazyParsley[_]) extends Binary[A, Any, A](_p, _q) {
2026
override def make(p: StrictParsley[A], q: StrictParsley[Any]): StrictParsley[A] = backend.<*(p, q)
27+
28+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[A] = visitor.visit(this, context)(_p, _q)
2129
}

‎parsley/shared/src/main/scala/parsley/internal/deepembedding/frontend/Visitors.scala

+289
Large diffs are not rendered by default.

‎parsley/shared/src/main/scala/parsley/internal/deepembedding/singletons/ErrorEmbedding.scala

+7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package parsley.internal.deepembedding.singletons
55

66
import parsley.internal.deepembedding.backend.MZero
7+
import parsley.internal.deepembedding.frontend.LazyParsleyIVisitor
78
import parsley.internal.errors.CaretWidth
89
import parsley.internal.machine.instructions
910

@@ -13,20 +14,26 @@ private [parsley] final class Empty private (val width: Int) extends Singleton[N
1314
override val pretty: String = "empty"
1415
// $COVERAGE-ON$
1516
override val instr: instructions.Instr = new instructions.Empty(width)
17+
18+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[Nothing] = visitor.visit(this, context)(width)
1619
}
1720

1821
private [parsley] final class Fail(width: CaretWidth, msgs: String*) extends Singleton[Nothing] with MZero {
1922
// $COVERAGE-OFF$
2023
override def pretty: String = s"fail(${msgs.mkString(", ")})"
2124
// $COVERAGE-ON$
2225
override def instr: instructions.Instr = new instructions.Fail(width, msgs: _*)
26+
27+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[Nothing] = visitor.visit(this, context)(width, msgs)
2328
}
2429

2530
private [parsley] final class Unexpected(msg: String, width: CaretWidth) extends Singleton[Nothing] with MZero {
2631
// $COVERAGE-OFF$
2732
override def pretty: String = s"unexpected($msg)"
2833
// $COVERAGE-ON$
2934
override def instr: instructions.Instr = new instructions.Unexpected(msg, width)
35+
36+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[Nothing] = visitor.visit(this, context)(msg, width)
3037
}
3138

3239
private [parsley] object Empty {

‎parsley/shared/src/main/scala/parsley/internal/deepembedding/singletons/IntrinsicEmbedding.scala

+13-1
Original file line numberDiff line numberDiff line change
@@ -6,49 +6,61 @@ package parsley.internal.deepembedding.singletons
66
import parsley.registers.Reg
77
import parsley.token.errors.LabelConfig
88

9-
import parsley.internal.deepembedding.frontend.UsesRegister
9+
import parsley.internal.deepembedding.frontend.{LazyParsleyIVisitor, UsesRegister}
1010
import parsley.internal.machine.instructions
1111

1212
private [parsley] final class CharTok(private [CharTok] val c: Char, val expected: LabelConfig) extends Singleton[Char] {
1313
// $COVERAGE-OFF$
1414
override def pretty: String = s"char($c)"
1515
// $COVERAGE-ON$
1616
override def instr: instructions.Instr = new instructions.CharTok(c, expected)
17+
18+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[Char] = visitor.visit(this, context)(c, expected)
1719
}
1820

1921
private [parsley] final class SupplementaryCharTok(private [SupplementaryCharTok] val codepoint: Int, val expected: LabelConfig) extends Singleton[Int] {
2022
// $COVERAGE-OFF$
2123
override def pretty: String = s"char(${Character.toChars(codepoint).mkString})"
2224
// $COVERAGE-ON$
2325
override def instr: instructions.Instr = new instructions.SupplementaryCharTok(codepoint, expected)
26+
27+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[Int] = visitor.visit(this, context)(codepoint, expected)
2428
}
2529

2630
private [parsley] final class StringTok(private [StringTok] val s: String, val expected: LabelConfig) extends Singleton[String] {
2731
// $COVERAGE-OFF$
2832
override def pretty: String = s"string($s)"
2933
// $COVERAGE-ON$
3034
override def instr: instructions.Instr = new instructions.StringTok(s, expected)
35+
36+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[String] = visitor.visit(this, context)(s, expected)
3137
}
3238

3339
private [parsley] object Eof extends Singleton[Unit] {
3440
// $COVERAGE-OFF$
3541
override val pretty: String = "eof"
3642
// $COVERAGE-ON$
3743
override val instr: instructions.Instr = instructions.Eof
44+
45+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[Unit] = visitor.visit(this, context)
3846
}
3947

4048
private [parsley] final class UniSatisfy(private [UniSatisfy] val f: Int => Boolean, val expected: LabelConfig) extends Singleton[Int] {
4149
// $COVERAGE-OFF$
4250
override def pretty: String = "satisfyUnicode(?)"
4351
// $COVERAGE-ON$
4452
override def instr: instructions.Instr = new instructions.UniSat(f, expected)
53+
54+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[Int] = visitor.visit(this, context)(f, expected)
4555
}
4656

4757
private [parsley] final class Modify[S](val reg: Reg[S], f: S => S) extends Singleton[Unit] with UsesRegister {
4858
// $COVERAGE-OFF$
4959
override def pretty: String = s"modify($reg, ?)"
5060
// $COVERAGE-ON$
5161
override def instr: instructions.Instr = instructions.Modify(reg.addr, f)
62+
63+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[Unit] = visitor.visit(this, context)(reg, f)
5264
}
5365

5466
private [deepembedding] object CharTok {

‎parsley/shared/src/main/scala/parsley/internal/deepembedding/singletons/PrimitiveEmbedding.scala

+11
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,41 @@ package parsley.internal.deepembedding.singletons
66
import parsley.registers.Reg
77
import parsley.token.errors.LabelConfig
88

9+
import parsley.internal.deepembedding.frontend.LazyParsleyIVisitor
910
import parsley.internal.machine.instructions
1011

1112
private [parsley] final class Satisfy(private [Satisfy] val f: Char => Boolean, val expected: LabelConfig) extends Singleton[Char] {
1213
// $COVERAGE-OFF$
1314
override val pretty: String = "satisfy(f)"
1415
// $COVERAGE-ON$
1516
override def instr: instructions.Instr = new instructions.Satisfies(f, expected)
17+
18+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[Char] = visitor.visit(this, context)(f, expected)
1619
}
1720

1821
private [parsley] object Line extends Singleton[Int] {
1922
// $COVERAGE-OFF$
2023
override val pretty: String = "line"
2124
// $COVERAGE-ON$
2225
override val instr: instructions.Instr = instructions.Line
26+
27+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[Int] = visitor.visit(this, context)
2328
}
2429
private [parsley] object Col extends Singleton[Int] {
2530
// $COVERAGE-OFF$
2631
override val pretty: String = "col"
2732
// $COVERAGE-ON$
2833
override val instr: instructions.Instr = instructions.Col
34+
35+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[Int] = visitor.visit(this, context)
2936
}
3037
private [parsley] object Offset extends Singleton[Int] {
3138
// $COVERAGE-OFF$
3239
override val pretty: String = "offset"
3340
// $COVERAGE-ON$
3441
override val instr: instructions.Instr = instructions.Offset
42+
43+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[Int] = visitor.visit(this, context)
3544
}
3645

3746
// This should really have UsesRegister, however, if it doesn't, this has the nice effect of catching
@@ -41,6 +50,8 @@ private [parsley] final class Get[S](reg: Reg[S]) extends Singleton[S] {
4150
override def pretty: String = s"get($reg)"
4251
// $COVERAGE-ON$
4352
override def instr: instructions.Instr = new instructions.Get(reg.addr)
53+
54+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[S] = visitor.visit(this, context)(reg)
4455
}
4556

4657
private [deepembedding] object Satisfy {

‎parsley/shared/src/main/scala/parsley/internal/deepembedding/singletons/SequenceEmbedding.scala

+5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*/
44
package parsley.internal.deepembedding.singletons
55

6+
import parsley.internal.deepembedding.frontend.LazyParsleyIVisitor
67
import parsley.internal.machine.instructions
78

89
// Core Embedding
@@ -11,13 +12,17 @@ private [parsley] final class Pure[A](private [Pure] val x: A) extends Singleton
1112
override def pretty: String = s"pure($x)"
1213
// $COVERAGE-ON$
1314
override def instr: instructions.Instr = new instructions.Push(x)
15+
16+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[A] = visitor.visit(this, context)(x)
1417
}
1518

1619
private [parsley] final class Fresh[A](x: =>A) extends Singleton[A] {
1720
// $COVERAGE-OFF$
1821
override def pretty: String = s"fresh($x)"
1922
// $COVERAGE-ON$
2023
override def instr: instructions.Instr = new instructions.Fresh(x)
24+
25+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[A] = visitor.visit(this, context)(x)
2126
}
2227

2328
private [deepembedding] object Pure {

‎parsley/shared/src/main/scala/parsley/internal/deepembedding/singletons/Singletons.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import parsley.internal.machine.instructions
1919
* @note due to the fact these appear in the frontend, they must not be mutable, for the same
2020
* reasons as detailed in `LazyParsley`
2121
*/
22-
private [singletons] abstract class Singleton[A] extends LazyParsley[A] with StrictParsley[A] {
22+
private [deepembedding] abstract class Singleton[A] extends LazyParsley[A] with StrictParsley[A] {
2323
/** The instruction that should be generated during the code generation for this combinator */
2424
def instr: instructions.Instr
2525

‎parsley/shared/src/main/scala/parsley/internal/deepembedding/singletons/TokenEmbedding.scala

+13
Original file line numberDiff line numberDiff line change
@@ -8,31 +8,40 @@ import parsley.token.descriptions.numeric.PlusSignPresence
88
import parsley.token.errors.ErrorConfig
99

1010
import parsley.internal.deepembedding.Sign.SignType
11+
import parsley.internal.deepembedding.frontend.LazyParsleyIVisitor
1112
import parsley.internal.machine.instructions
1213

1314
private [parsley] final class WhiteSpace(ws: Char => Boolean, desc: SpaceDesc, errConfig: ErrorConfig)
1415
extends Singleton[Unit] {
1516
// $COVERAGE-OFF$
1617
override val pretty: String = "whiteSpace"
1718
override def instr: instructions.Instr = new instructions.TokenWhiteSpace(ws, desc, errConfig)
19+
20+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[Unit] = visitor.visit(this, context)(ws, desc, errConfig)
1821
}
1922

2023
private [parsley] final class SkipComments(desc: SpaceDesc, errConfig: ErrorConfig) extends Singleton[Unit] {
2124
// $COVERAGE-OFF$
2225
override val pretty: String = "skipComments"
2326
override def instr: instructions.Instr = new instructions.TokenSkipComments(desc, errConfig)
27+
28+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[Unit] = visitor.visit(this, context)(desc, errConfig)
2429
}
2530

2631
private [parsley] final class Comment(desc: SpaceDesc, errConfig: ErrorConfig) extends Singleton[Unit] {
2732
// $COVERAGE-OFF$
2833
override val pretty: String = "comment"
2934
override def instr: instructions.Instr = new instructions.TokenComment(desc, errConfig)
35+
36+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[Unit] = visitor.visit(this, context)(desc, errConfig)
3037
}
3138

3239
private [parsley] final class Sign[A](ty: SignType, signPresence: PlusSignPresence) extends Singleton[A => A] {
3340
// $COVERAGE-OFF$
3441
override val pretty: String = "sign"
3542
override def instr: instructions.Instr = new instructions.TokenSign(ty, signPresence)
43+
44+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[A => A] = visitor.visit(this, context)(ty, signPresence)
3645
}
3746

3847
private [parsley] class NonSpecific(name: String, unexpectedIllegal: String => String,
@@ -41,4 +50,8 @@ private [parsley] class NonSpecific(name: String, unexpectedIllegal: String => S
4150
override def pretty: String = "nonspecificName"
4251
// $COVERAGE-ON$
4352
override def instr: instructions.Instr = new instructions.TokenNonSpecific(name, unexpectedIllegal)(start, letter, illegal)
53+
54+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[String] = {
55+
visitor.visit(this, context)(name, unexpectedIllegal, start, letter, illegal)
56+
}
4457
}

‎parsley/shared/src/main/scala/parsley/internal/deepembedding/singletons/token/SymbolEmbedding.scala

+9
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import parsley.token.errors.LabelConfig
77
import parsley.token.predicate.CharPredicate
88

99
import parsley.internal.collection.immutable.Trie
10+
import parsley.internal.deepembedding.frontend.LazyParsleyIVisitor
1011
import parsley.internal.deepembedding.singletons.Singleton
1112
import parsley.internal.machine.instructions
1213

@@ -16,6 +17,10 @@ private [parsley] final class SoftKeyword(private [SoftKeyword] val specific: St
1617
override def pretty: String = s"softKeyword($specific)"
1718
// $COVERAGE-ON$
1819
override def instr: instructions.Instr = new instructions.token.SoftKeyword(specific, letter, caseSensitive, expected, expectedEnd)
20+
21+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[Unit] = {
22+
visitor.visit(this, context)(specific, letter, caseSensitive, expected, expectedEnd)
23+
}
1924
}
2025

2126
private [parsley] final class SoftOperator(private [SoftOperator] val specific: String, letter: CharPredicate, ops: Trie[Unit],
@@ -24,6 +29,10 @@ private [parsley] final class SoftOperator(private [SoftOperator] val specific:
2429
override def pretty: String = s"softOperator($specific)"
2530
// $COVERAGE-ON$
2631
override def instr: instructions.Instr = new instructions.token.SoftOperator(specific, letter, ops, expected, expectedEnd)
32+
33+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[Unit] = {
34+
visitor.visit(this, context)(specific, letter, ops, expected, expectedEnd)
35+
}
2736
}
2837

2938
// $COVERAGE-OFF$

‎parsley/shared/src/main/scala/parsley/internal/deepembedding/singletons/token/TextEmbedding.scala

+5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package parsley.internal.deepembedding.singletons.token
66
import parsley.token.errors.SpecialisedFilterConfig
77

88
import parsley.internal.collection.immutable.Trie
9+
import parsley.internal.deepembedding.frontend.LazyParsleyIVisitor
910
import parsley.internal.deepembedding.singletons.Singleton
1011
import parsley.internal.machine.instructions
1112

@@ -14,18 +15,22 @@ private [parsley] final class EscapeMapped(escTrie: Trie[Int], escs: Set[String]
1415
override def pretty: String = "escapeMapped"
1516
// $COVERAGE-ON$
1617
override def instr: instructions.Instr = new instructions.token.EscapeMapped(escTrie, escs)
18+
19+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[Int] = visitor.visit(this, context)(escTrie, escs)
1720
}
1821

1922
private [parsley] final class EscapeAtMost(n: Int, radix: Int) extends Singleton[BigInt] {
2023
override def instr: instructions.Instr = new instructions.token.EscapeAtMost(n, radix)
2124
// $COVERAGE-OFF$
2225
override def pretty: String = "escapeAtMost"
2326
// $COVERAGE-ON$
27+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[BigInt] = visitor.visit(this, context)(n, radix)
2428
}
2529

2630
private [parsley] final class EscapeOneOfExactly(radix: Int, ns: List[Int], inexactErr: SpecialisedFilterConfig[Int]) extends Singleton[BigInt] {
2731
override def instr: instructions.Instr = new instructions.token.EscapeOneOfExactly(radix, ns, inexactErr)
2832
// $COVERAGE-OFF$
2933
override def pretty: String = "escapeOneOfExactly"
3034
// $COVERAGE-ON$
35+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[BigInt] = visitor.visit(this, context)(radix, ns, inexactErr)
3136
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
package parsley.internal.deepembedding.frontend
2+
3+
import org.scalatest.Assertion
4+
import org.typelevel.scalaccompat.annotation.unused
5+
import parsley.{Parsley, ParsleyTest}
6+
import parsley.debug.FullBreak
7+
import parsley.errors.{DefaultErrorBuilder, ErrorBuilder, Token}
8+
import parsley.internal.collection.immutable.Trie
9+
import parsley.internal.deepembedding.ContOps
10+
import parsley.internal.deepembedding.Sign
11+
import parsley.internal.deepembedding.backend.StrictParsley
12+
import parsley.internal.deepembedding.singletons.*
13+
import parsley.internal.deepembedding.singletons.token.*
14+
import parsley.internal.errors.{CaretWidth, ExpectDesc, ExpectItem, FlexibleCaret}
15+
import parsley.internal.machine.errors.DefuncError
16+
import parsley.registers.Reg
17+
import parsley.token.descriptions.SpaceDesc
18+
import parsley.token.descriptions.numeric.PlusSignPresence
19+
import parsley.token.errors.{ErrorConfig, FilterConfig, LabelConfig, LabelWithExplainConfig, SpecialisedFilterConfig}
20+
import parsley.token.predicate.Basic
21+
22+
class VisitorTests extends ParsleyTest {
23+
sealed trait ConstUnit[+A]
24+
object CUnit extends ConstUnit[Nothing]
25+
26+
private val testVisitor: LazyParsleyIVisitor[Unit, ConstUnit] =
27+
new GenericLazyParsleyIVisitor[Unit, ConstUnit] {
28+
override def visitSingleton[A](self: Singleton[A], context: Unit): ConstUnit[A] = CUnit
29+
30+
override def visitUnary[A, B](self: Unary[A, B], context: Unit)(p: LazyParsley[A]): ConstUnit[B] = CUnit
31+
32+
override def visitBinary[A, B, C](self: Binary[A, B, C], context: Unit)(l: LazyParsley[A], r: => LazyParsley[B]): ConstUnit[C] = CUnit
33+
34+
override def visitTernary[A, B, C, D](self: Ternary[A, B, C, D], context: Unit)(f: LazyParsley[A],
35+
s: => LazyParsley[B],
36+
t: => LazyParsley[C]): ConstUnit[D] = CUnit
37+
38+
override def visit[A](self: <|>[A])(context: Unit, p: LazyParsley[A], q: LazyParsley[A]): ConstUnit[A] = CUnit
39+
40+
override def visit[A](self: ChainPre[A], context: Unit)(p: LazyParsley[A], op: => LazyParsley[A => A]): ConstUnit[A] = CUnit
41+
}
42+
43+
private def dontExecute(): Nothing =
44+
fail("Should not execute.")
45+
46+
private val dummyParser: LazyParsley[Nothing] =
47+
new LazyParsley[Nothing] {
48+
override protected def findLetsAux[M[_, _] : ContOps, R](seen: Set[LazyParsley[_]])(implicit state: LetFinderState): M[R, Unit] =
49+
dontExecute()
50+
51+
override protected def preprocess[M[_, _] : ContOps, R, A_ >: Nothing](implicit lets: LetMap, recs: RecMap): M[R, StrictParsley[A_]] =
52+
dontExecute()
53+
54+
override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[Nothing] =
55+
dontExecute()
56+
}
57+
58+
59+
private val dummyLabelConfig: LabelConfig = new LabelConfig {
60+
override private[parsley] def orElse(other: LabelConfig): LabelConfig =
61+
dontExecute()
62+
63+
override private[parsley] def orElse(other: LabelWithExplainConfig): LabelWithExplainConfig =
64+
dontExecute()
65+
66+
override private[parsley] def asExpectDescs: Iterable[ExpectDesc] =
67+
dontExecute()
68+
69+
override private[parsley] def asExpectDescs(otherwise: String): Iterable[ExpectDesc] =
70+
dontExecute()
71+
72+
override private[parsley] def asExpectItems(raw: String): Iterable[ExpectItem] =
73+
dontExecute()
74+
75+
override private[parsley] def apply[A](p: Parsley[A]): Parsley[A] =
76+
dontExecute()
77+
}
78+
79+
private val dummyCaretWidth: CaretWidth = new FlexibleCaret(0)
80+
81+
private val dummyErrorBuilder: ErrorBuilder[String] = new DefaultErrorBuilder {
82+
override def unexpectedToken(cs: Iterable[Char], amountOfInputParserWanted: Int, lexicalError: Boolean): Token =
83+
dontExecute()
84+
}
85+
86+
private def dummySFConfig[A](): SpecialisedFilterConfig[A] = new SpecialisedFilterConfig[A] {
87+
override private[parsley] def filter(p: Parsley[A])(f: A => Boolean): Parsley[A] =
88+
dontExecute()
89+
90+
override private[parsley] def mkError(offset: Int, line: Int, col: Int, caretWidth: Int, x: A): DefuncError =
91+
dontExecute()
92+
93+
override private[parsley] def injectLeft[B]: FilterConfig[Either[A, B]] =
94+
dontExecute()
95+
96+
override private[parsley] def injectRight[B]: FilterConfig[Either[B, A]] =
97+
dontExecute()
98+
99+
override private[parsley] def injectSnd[B]: FilterConfig[(B, A)] =
100+
dontExecute()
101+
}
102+
103+
implicit private class TestVisitorOps[A](p: LazyParsley[A]) {
104+
def testV: Assertion = p.visit(testVisitor, ()) shouldBe CUnit
105+
}
106+
107+
private def dummyRegister(): Reg[Unit] =
108+
Reg.make[Unit]
109+
110+
def dontEval: Nothing = fail("Laziness was not maintained.")
111+
val crash = new PartialFunction[Any, Nothing] {
112+
def apply(@unused x: Any) = dontEval
113+
def isDefinedAt(x: Any): Boolean = false
114+
}
115+
def crash(@unused x: Any, @unused y: Any): Nothing = dontEval
116+
def crash(@unused x: Any, @unused y: Any, @unused z: Any): Nothing = dontEval
117+
118+
they should "maintain laziness of the parsers visited" in {
119+
new NewReg(dummyRegister(), dummyParser, dontEval).testV
120+
new Branch(dummyParser, dontEval, dontEval).testV
121+
new If(dummyParser, dontEval, dontEval).testV
122+
new Lift2[Nothing, Nothing, Nothing](crash, dummyParser, dontEval).testV
123+
new Lift3[Nothing, Nothing, Nothing, Nothing](crash, dummyParser, dontEval, dontEval).testV
124+
new Local(dummyRegister(), dummyParser, dontEval).testV
125+
new <*>(dummyParser, dontEval).testV
126+
new *>(dummyParser, dontEval).testV
127+
new <*(dummyParser, dontEval).testV
128+
new ChainPost(dummyParser, dontEval).testV
129+
new Chainl(dummyParser, dontEval, dontEval).testV
130+
new Chainr[Nothing, Nothing](dummyParser, dontEval, crash).testV
131+
new SepEndBy1(dummyParser, dontEval).testV
132+
}
133+
134+
they should "all return the constant unit object from the test visitor" in {
135+
// The lazy parsers have been tested for this in the laziness preservation test.
136+
new Pure(()).testV
137+
new Fresh(()).testV
138+
new Satisfy(_ => true, dummyLabelConfig).testV
139+
Line.testV
140+
Col.testV
141+
Offset.testV
142+
new Get(dummyRegister()).testV
143+
new WhiteSpace(_ => true, SpaceDesc.plain, new ErrorConfig).testV
144+
new SkipComments(SpaceDesc.plain, new ErrorConfig).testV
145+
new Comment(SpaceDesc.plain, new ErrorConfig).testV
146+
new Sign(Sign.CombinedType, PlusSignPresence.Optional).testV
147+
new NonSpecific("foo", identity[String], _ => true, _ => true, _ => false).testV
148+
new CharTok(' ', dummyLabelConfig).testV
149+
new SupplementaryCharTok(0, dummyLabelConfig).testV
150+
new StringTok("bar", dummyLabelConfig).testV
151+
Eof.testV
152+
new UniSatisfy(_ => true, dummyLabelConfig).testV
153+
new Modify(dummyRegister(), identity[Unit]).testV
154+
Parsley.empty.internal.testV
155+
new Fail(dummyCaretWidth).testV
156+
new Unexpected("qux", dummyCaretWidth).testV
157+
new EscapeMapped(Trie.empty[Int], Set("quux")).testV
158+
new EscapeAtMost(0, 0).testV
159+
new EscapeOneOfExactly(0, Nil, dummySFConfig[Int]()).testV
160+
new SoftKeyword("corge", Basic(_ => true), false, dummyLabelConfig, "grault").testV
161+
new SoftOperator("garply", Basic(_ => true), Trie.empty[Unit], dummyLabelConfig, "waldo").testV
162+
new Attempt(dummyParser).testV
163+
new Look(dummyParser).testV
164+
new NotFollowedBy(dummyParser).testV
165+
new Put(dummyRegister(), dummyParser).testV
166+
new Debug(dummyParser, "fred", false, FullBreak).testV
167+
new DebugError(dummyParser, "plugh", false, dummyErrorBuilder).testV
168+
new Filter[Nothing](dummyParser, crash).testV
169+
new MapFilter[Nothing, Nothing](dummyParser, crash).testV
170+
new FilterOut[Nothing](dummyParser, crash).testV
171+
new GuardAgainst[Nothing](dummyParser, crash).testV
172+
new UnexpectedWhen[Nothing](dummyParser, crash)
173+
new <|>(dummyParser, dummyParser).testV
174+
new >>=[Nothing, Nothing](dummyParser, crash).testV
175+
new Many(dummyParser).testV
176+
new SkipMany(dummyParser).testV
177+
new ManyUntil(dummyParser).testV
178+
new SkipManyUntil(dummyParser).testV
179+
new ErrorLabel(dummyParser, Seq("bazola")).testV
180+
new ErrorExplain(dummyParser, "ztesch").testV
181+
new ErrorAmend(dummyParser, false).testV
182+
new ErrorEntrench(dummyParser).testV
183+
new ErrorDislodge(0, dummyParser).testV
184+
new ErrorLexical(dummyParser).testV
185+
new VerifiedError[Nothing](dummyParser, Left(crash))
186+
}
187+
}

0 commit comments

Comments
 (0)
Please sign in to comment.