Skip to content

Commit

Permalink
Improve YamlError ADT
Browse files Browse the repository at this point in the history
By providing the `ParseError` the original information that caused the error, an end user can use it for better diagnostics down the line.
  • Loading branch information
misherpal committed Mar 13, 2024
1 parent 71dba91 commit 8a4d9f6
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 6 deletions.
18 changes: 13 additions & 5 deletions core/shared/src/main/scala/org/virtuslab/yaml/YamlError.scala
Expand Up @@ -5,6 +5,7 @@ import scala.util.control.NoStackTrace

import org.virtuslab.yaml.internal.load.reader.token.Token
import org.virtuslab.yaml.internal.load.reader.token.TokenKind
import org.virtuslab.yaml.internal.load.TagValue

/**
* An ADT representing a decoding failure.
Expand All @@ -13,14 +14,21 @@ sealed trait YamlError {
def msg: String
}

final case class ParseError(msg: String) extends YamlError
sealed trait ParseError extends YamlError
object ParseError {
def from(expected: String, got: Token): ParseError = ParseError(
s"""|Expected
def from(expected: String, got: Token): ParseError = ExpectedTokenKind(expected, got)
def from(expected: TokenKind, got: Token): ParseError = ParseError.from(expected.toString, got)

final case class ExpectedTokenKind(expected: String, got: Token) extends ParseError {
def msg: String =
s"""|Expected
|$expected but instead got ${got.kind}
|${got.range.errorMsg}""".stripMargin
)
def from(expected: TokenKind, got: Token): ParseError = ParseError.from(expected.toString, got)
}

final case class NoRegisteredTagDirective(handleKey: String, tokenTag: Token) extends ParseError {
def msg: String = s"There is no registered tag directive for handle $handleKey"
}
}

final case class ComposerError(msg: String) extends YamlError
Expand Down
Expand Up @@ -456,7 +456,7 @@ final class ParserImpl private (in: Tokenizer) extends Parser {
else CustomTag(tagValue)
parseNodeAttributes(in.peekToken(), metadata.withTag(tag))
case None =>
Left(ParseError(s"There is no registered tag directive for handle $handleKey"))
Left(ParseError.NoRegisteredTagDirective(handleKey, token))
}
}
case _ => Right(metadata, token)
Expand Down
Expand Up @@ -3,6 +3,9 @@ package parser

import org.virtuslab.yaml.internal.load.parse.EventKind._
import org.virtuslab.yaml.internal.load.reader.token.ScalarStyle
import org.virtuslab.yaml.StringOps
import org.virtuslab.yaml.internal.load.reader.token.Token
import org.virtuslab.yaml.internal.load.reader.token.TokenKind.MappingKey

class ParserSuite extends BaseYamlSuite {

Expand Down Expand Up @@ -89,4 +92,36 @@ class ParserSuite extends BaseYamlSuite {

assertEquals(yaml.events, Right(expectedEvents))
}

test("Parsing error") {
val errorMessage = """Expected
|BlockEnd but instead got MappingKey
| -- zipcode: 12-345
| ^""".stripMargin

val yaml =
"""name: John Wick
|age: 40
|address:
| - city: Anywhere
| -- zipcode: 12-345
|""".stripMargin

val yamlLines = yaml.split("\n", -1).toVector

assertEquals(
yaml.asNode,
Left(
ParseError.ExpectedTokenKind(
"BlockEnd",
Token(
MappingKey,
Range(Position(65, 4, 13), yamlLines, None)
)
)
)
)

assertEquals(yaml.asNode.left.map(_.msg), Left(errorMessage))
}
}

0 comments on commit 8a4d9f6

Please sign in to comment.