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