diff --git a/core/shared/src/main/scala/org/virtuslab/yaml/YamlError.scala b/core/shared/src/main/scala/org/virtuslab/yaml/YamlError.scala index fa5eb43c..e008ba96 100644 --- a/core/shared/src/main/scala/org/virtuslab/yaml/YamlError.scala +++ b/core/shared/src/main/scala/org/virtuslab/yaml/YamlError.scala @@ -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. @@ -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 diff --git a/core/shared/src/main/scala/org/virtuslab/yaml/internal/load/parse/ParserImpl.scala b/core/shared/src/main/scala/org/virtuslab/yaml/internal/load/parse/ParserImpl.scala index 03d26348..fb45ec3a 100644 --- a/core/shared/src/main/scala/org/virtuslab/yaml/internal/load/parse/ParserImpl.scala +++ b/core/shared/src/main/scala/org/virtuslab/yaml/internal/load/parse/ParserImpl.scala @@ -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) diff --git a/core/shared/src/test/scala/org/virtuslab/yaml/parser/ParserSuite.scala b/core/shared/src/test/scala/org/virtuslab/yaml/parser/ParserSuite.scala index 91e23c7f..12c63b06 100644 --- a/core/shared/src/test/scala/org/virtuslab/yaml/parser/ParserSuite.scala +++ b/core/shared/src/test/scala/org/virtuslab/yaml/parser/ParserSuite.scala @@ -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 { @@ -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)) + } }