Skip to content

Commit

Permalink
Changed error hierarchy
Browse files Browse the repository at this point in the history
  • Loading branch information
j-mie6 committed Jan 12, 2024
1 parent a6f7cf7 commit eb97062
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import org.typelevel.scalaccompat.annotation.unused
* @since 4.1.0
* @group filters
*/
trait FilterConfig[A] {
sealed trait FilterConfig[A] {
private [parsley] def filter(p: Parsley[A])(f: A => Boolean): Parsley[A]
private [parsley] def mkError(offset: Int, line: Int, col: Int, caretWidth: Int, x: A): DefuncError
// $COVERAGE-OFF$
Expand All @@ -32,19 +32,19 @@ trait FilterConfig[A] {
* @since 4.1.0
* @group filters
*/
trait SpecialisedFilterConfig[A] extends FilterConfig[A]
sealed trait SpecialisedFilterConfig[A] extends FilterConfig[A]
/** This subtrait of `FilterConfig` specifies that only filters generating ''vanilla'' errors may be used.
* @since 4.1.0
* @group filters
*/
trait VanillaFilterConfig[A] extends FilterConfig[A]
sealed trait VanillaFilterConfig[A] extends FilterConfig[A]

/** This class ensures that the filter will generate ''specialised'' messages for the given failing parse.
* @since 4.1.0
* @group filters
*/
abstract class SpecialisedMessage[A] extends SpecialisedFilterConfig[A] { self =>
@deprecated("filters do not have partial amend semantics, so this does nothing", "4.1.0") def this(@unused fullAmend: Boolean) = this()
private def this(@unused fullAmend: Boolean) = this()
/** This method produces the messages for the given value.
* @since 4.1.0
* @group badchar
Expand Down Expand Up @@ -83,7 +83,7 @@ abstract class SpecialisedMessage[A] extends SpecialisedFilterConfig[A] { self =
* @group filters
*/
abstract class Unexpected[A] extends VanillaFilterConfig[A] { self =>
@deprecated("filters do not have partial amend semantics, so this does nothing", "4.1.0") def this(@unused fullAmend: Boolean) = this()
private def this(@unused fullAmend: Boolean) = this()
/** This method produces the unexpected label for the given value.
* @since 4.1.0
* @group badchar
Expand Down Expand Up @@ -121,7 +121,7 @@ abstract class Unexpected[A] extends VanillaFilterConfig[A] { self =>
* @group filters
*/
abstract class Because[A] extends VanillaFilterConfig[A] { self =>
@deprecated("filters do not have partial amend semantics, so this does nothing", "4.1.0") def this(@unused fullAmend: Boolean) = this()
private def this(@unused fullAmend: Boolean) = this()
/** This method produces the reason for the given value.
* @since 4.1.0
* @group badchar
Expand Down Expand Up @@ -159,7 +159,7 @@ abstract class Because[A] extends VanillaFilterConfig[A] { self =>
* @group filters
*/
abstract class UnexpectedBecause[A] extends VanillaFilterConfig[A] { self =>
@deprecated("filters do not have partial amend semantics, so this does nothing", "4.1.0") def this(@unused fullAmend: Boolean) = this()
private def this(@unused fullAmend: Boolean) = this()
/** This method produces the unexpected label for the given value.
* @since 4.1.0
* @group badchar
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,39 +20,42 @@ private [parsley] sealed trait ConfigImplUntyped {

// TODO: move into internal?
// Relaxing Types
private [parsley] trait LabelOps {
private [parsley] sealed trait LabelOps {
private [parsley] def asExpectDescs: Iterable[ExpectDesc]
private [parsley] def asExpectDescs(otherwise: String): Iterable[ExpectDesc]
private [parsley] def asExpectItems(raw: String): Iterable[ExpectItem]
private [parsley] final def asExpectItems(raw: Char): Iterable[ExpectItem] = asExpectItems(s"$raw")
}

// TODO: reason extraction, maybe tie into errors?
private [parsley] trait ExplainOps

private [parsley] sealed trait ExplainOps

// Constraining Types
/** This type can be used to configure ''both'' errors that make labels and those that make reasons.
* @since 4.1.0
* @group labels
*/
trait LabelWithExplainConfig extends ConfigImplUntyped with LabelOps with ExplainOps {
sealed trait LabelWithExplainConfig extends ConfigImplUntyped with LabelOps with ExplainOps {
private [parsley] def orElse(other: LabelWithExplainConfig): LabelWithExplainConfig
}
/** This type can be used to configure errors that make labels.
* @since 4.1.0
* @group labels
*/
trait LabelConfig extends LabelWithExplainConfig {
sealed trait LabelConfig extends LabelWithExplainConfig {
private [parsley] def orElse(other: LabelConfig): LabelConfig
}
/** This type can be used to configure errors that make reasons.
* @since 4.1.0
* @group labels
*/
trait ExplainConfig extends LabelWithExplainConfig
sealed trait ExplainConfig extends LabelWithExplainConfig

private [errors] final class Label private[errors] (val label: String, val labels: String*) extends LabelConfig {
/** This class represents configurations producing labels: labels may not be empty.
* @since 4.1.0
* @group labels
*/
final class Label(val label: String, val labels: String*) extends LabelConfig {
require(label.nonEmpty && labels.forall(_.nonEmpty), "labels cannot be empty strings")
private [parsley] final override def apply[A](p: Parsley[A]) = p.label(label, labels: _*)
private [parsley] final override def asExpectDescs: Iterable[ExpectDesc] = (label +: labels).map(new ExpectDesc(_))
Expand All @@ -65,8 +68,7 @@ private [errors] final class Label private[errors] (val label: String, val label
}
private [parsley] final override def orElse(config: LabelConfig) = this
}
/** This object has a factory for configurations producing labels: labels may not be empty.
* @since 4.1.0
/** @since 4.1.0
* @group labels
*/
object Label {
Expand All @@ -86,7 +88,11 @@ object Hidden extends LabelConfig {
private [parsley] final override def orElse(config: LabelConfig) = this
}

private [errors] final class Reason private[errors] (val reason: String) extends ExplainConfig {
/** This object has a factory for configurations producing reasons: if the empty string is provided, this equivalent to [[NotConfigured `NotConfigured`]].
* @since 4.1.0
* @group labels
*/
final class Reason(val reason: String) extends ExplainConfig {
require(reason.nonEmpty, "reasons cannot be empty strings")
private [parsley] final override def apply[A](p: Parsley[A]) = p.explain(reason)
private [parsley] final override def asExpectDescs = None
Expand All @@ -98,15 +104,18 @@ private [errors] final class Reason private[errors] (val reason: String) extends
case _ => this
}
}
/** This object has a factory for configurations producing reasons: if the empty string is provided, this equivalent to [[NotConfigured `NotConfigured`]].
* @since 4.1.0
/** @since 4.1.0
* @group labels
*/
object Reason {
def apply(reason: String): ExplainConfig = if (reason.nonEmpty) new Reason(reason) else NotConfigured
def apply(reason: String): ExplainConfig = new Reason(reason)
}

private [errors] final class LabelAndReason private[errors] (val reason: String, val label: String, val labels: String*) extends LabelWithExplainConfig {
/** This object has a factory for configurations producing labels and reasons: the reason and labels cannot be empty.
* @since 4.1.0
* @group labels
*/
final class LabelAndReason(val reason: String, val label: String, val labels: String*) extends LabelWithExplainConfig {
require(reason.nonEmpty, "reason cannot be empty strings, use `Label` instead")
require(label.nonEmpty && labels.forall(_.nonEmpty), "labels cannot be empty strings")
private [parsley] final override def apply[A](p: Parsley[A]) = p.label(label, labels: _*).explain(reason)
Expand All @@ -115,17 +124,11 @@ private [errors] final class LabelAndReason private[errors] (val reason: String,
private [parsley] final override def asExpectItems(@unused raw: String) = asExpectDescs
private [parsley] final override def orElse(config: LabelWithExplainConfig) = this
}
/** This object has a factory for configurations producing labels and reasons: if the empty label is provided, this equivalent to [[Hidden `Hidden`]] with no
* reason; if the empty reason is provided this is equivalent to [[Label$ `Label`]].
* @since 4.1.0
/** @since 4.1.0
* @group labels
*/
object LabelAndReason {
def apply(label: String, reason: String): LabelWithExplainConfig = {
if (label.isEmpty) Hidden
else if (reason.nonEmpty) new LabelAndReason(reason, label)
else new Label(label)
}
def apply(label: String, reason: String): LabelWithExplainConfig = new LabelAndReason(reason, label)
}

/** This object specifies that no special labels or reasons should be generated, and default errors should be used instead.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -847,6 +847,7 @@ class ErrorConfig {

/** Some possible defaults for the `ErrorConfig`.
*
* @group errconfig
* @since 4.5.0
*/
object ErrorConfig {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ import parsley.internal.deepembedding.{ContOps, Sign}
import parsley.internal.deepembedding.backend.StrictParsley
import parsley.internal.deepembedding.singletons.*
import parsley.internal.deepembedding.singletons.token.*
import parsley.internal.errors.{CaretWidth, ExpectDesc, ExpectItem, FlexibleCaret}
import parsley.internal.machine.errors.DefuncError
import parsley.internal.errors.{CaretWidth, FlexibleCaret}
import parsley.state.Ref
import parsley.token.descriptions.SpaceDesc
import parsley.token.descriptions.numeric.PlusSignPresence
import parsley.token.errors.{ErrorConfig, FilterConfig, LabelConfig, LabelWithExplainConfig, SpecialisedFilterConfig}
import parsley.token.errors.{ErrorConfig, BasicFilter, LabelConfig, SpecialisedFilterConfig}
import parsley.token.predicate.Basic
import parsley.token.errors.NotConfigured

class VisitorTests extends ParsleyTest {
sealed trait ConstUnit[+A]
Expand Down Expand Up @@ -65,25 +65,7 @@ class VisitorTests extends ParsleyTest {
}


private val dummyLabelConfig: LabelConfig = new LabelConfig {
override private[parsley] def orElse(other: LabelConfig): LabelConfig =
dontExecute()

override private[parsley] def orElse(other: LabelWithExplainConfig): LabelWithExplainConfig =
dontExecute()

override private[parsley] def asExpectDescs: Iterable[ExpectDesc] =
dontExecute()

override private[parsley] def asExpectDescs(otherwise: String): Iterable[ExpectDesc] =
dontExecute()

override private[parsley] def asExpectItems(raw: String): Iterable[ExpectItem] =
dontExecute()

override private[parsley] def apply[A](p: Parsley[A]): Parsley[A] =
dontExecute()
}
private val dummyLabelConfig: LabelConfig = NotConfigured

private val dummyCaretWidth: CaretWidth = new FlexibleCaret(0)

Expand All @@ -92,22 +74,7 @@ class VisitorTests extends ParsleyTest {
dontExecute()
}

private def dummySFConfig[A](): SpecialisedFilterConfig[A] = new SpecialisedFilterConfig[A] {
override private[parsley] def filter(p: Parsley[A])(f: A => Boolean): Parsley[A] =
dontExecute()

override private[parsley] def mkError(offset: Int, line: Int, col: Int, caretWidth: Int, x: A): DefuncError =
dontExecute()

override private[parsley] def injectLeft[B]: FilterConfig[Either[A, B]] =
dontExecute()

override private[parsley] def injectRight[B]: FilterConfig[Either[B, A]] =
dontExecute()

override private[parsley] def injectSnd[B]: FilterConfig[(B, A)] =
dontExecute()
}
private def dummySFConfig[A](): SpecialisedFilterConfig[A] = new BasicFilter[A]

implicit private class TestVisitorOps[A](p: LazyParsley[A]) {
def testV: Assertion = p.visit(testVisitor, ()) shouldBe CUnit
Expand Down
4 changes: 2 additions & 2 deletions project/ParsleySitePlugin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -190,13 +190,13 @@ object redirects {

private def redirects(latest: String) = {
// TODO: this can be made less brittle, surely can be derived from the above configuration?
val versions = List("latest", "stable", "4.4.x", "4.4", "4.5.x", "4.5", "5.0.x", "5.0")
val versions = List("latest", "stable", "4.4.x", "4.4", "4.5.x", "4.5", /*"5.0.x",*/ "5.0")
val versionMappings = List(
"latest" -> latest,
"stable" -> "4.5",
"4.4.x" -> "4.4",
"4.5.x" -> "4.5",
"5.0.x" -> "5.0",
//"5.0.x" -> "5.0",
)

val versioned = (
Expand Down

0 comments on commit eb97062

Please sign in to comment.