-
Notifications
You must be signed in to change notification settings - Fork 15
/
DefaultErrorBuilder.scala
133 lines (121 loc) · 5.27 KB
/
DefaultErrorBuilder.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/* SPDX-FileCopyrightText: © 2021 Parsley Contributors <https://github.com/j-mie6/Parsley/graphs/contributors>
* SPDX-License-Identifier: BSD-3-Clause
*/
package parsley.errors
// Turn coverage off, because the tests have their own error builder
// We might want to test this on its own though
// $COVERAGE-OFF$
/** This class us used to build Parsley's default error messages.
*
* While it compiles with the `ErrorBuilder` typeclass, it should not
* be considered a stable contract: the formatting can be changed at any
* time and without notice. The API, however, will remain stable.
*
* @since 3.0.0
* @note this class is abstract as it does not implement `unexpectedToken`: when creating an instance mix-in an appropriate
* token extractor from `parsley.errors.tokenextractors`.
* @group formatting
*/
abstract class DefaultErrorBuilder extends ErrorBuilder[String] {
/** @inheritdoc */
override def format(pos: Position, source: Source, lines: ErrorInfoLines): String = {
s"${source.fold("")(name => s"In $name ")}$pos:\n${lines.mkString(" ", "\n ", "")}"
}
//override def format(pos: Position, source: Source, ctxs: NestedContexts, lines: ErrorInfoLines): String = {
// s"${mergeScopes(source, ctxs)}$pos:\n${lines.mkString(" ", "\n ", "")}"
//}
/*protected def mergeScopes(source: Source, ctxs: NestedContexts): String = (source, ctxs) match {
case (None, None) => ""
case (Some(name), None) => s"In $name "
case (None, Some(ctxs)) => s"In $ctxs "
case (Some(name), Some(ctxs)) => s"In $name, $ctxs "
}*/
/** @inheritdoc */
type Position = String
/** @inheritdoc */
type Source = Option[String]
//type Context = Option[String]
/** @inheritdoc */
override def pos(line: Int, col: Int): Position = s"(line ${Integer.toUnsignedString(line)}, column ${Integer.toUnsignedString(col)})"
/** @inheritdoc */
override def source(sourceName: Option[String]): Source = sourceName.map(name => s"file '$name'")
//override def contexualScope(context: String): Context = Some(context)
//type NestedContexts = Option[String]
/*override def nestContexts(contexts: List[Context]): NestedContexts = {
val nonEmptyContexts = contexts.flatten
if (nonEmptyContexts.nonEmpty) Some(nonEmptyContexts.mkString(", "))
else None
}*/
/** @inheritdoc */
type ErrorInfoLines = Seq[String]
/** @inheritdoc */
override def vanillaError(unexpected: UnexpectedLine, expected: ExpectedLine, reasons: Messages, lines: LineInfo): ErrorInfoLines = {
val reasons_ = reasons.collect {
case reason if reason.nonEmpty => Some(reason)
}
combineOrUnknown((unexpected +: expected +: reasons_).flatten, lines)
}
/** @inheritdoc */
override def specialisedError(msgs: Messages, lines: LineInfo): ErrorInfoLines = combineOrUnknown(msgs, lines)
/** @inheritdoc */
private def combineOrUnknown(info: Seq[String], lines: Seq[String]): ErrorInfoLines = {
if (info.isEmpty) DefaultErrorBuilder.Unknown +: lines
else info ++: lines
}
/** @inheritdoc */
type ExpectedItems = Option[String]
/** @inheritdoc */
type Messages = Seq[Message]
/** @inheritdoc */
override def combineExpectedItems(alts: Set[Item]): ExpectedItems = {
helpers.combineAsList(alts.toList.filter(_.nonEmpty))
}
/** @inheritdoc */
override def combineMessages(alts: Seq[Message]): Messages = alts.filter(_.nonEmpty)
/** @inheritdoc */
type UnexpectedLine = Option[String]
/** @inheritdoc */
type ExpectedLine = Option[String]
/** @inheritdoc */
type Message = String
/** @inheritdoc */
type LineInfo = Seq[String]
/** @inheritdoc */
override def unexpected(item: Option[Item]): UnexpectedLine = item.map("unexpected " + _)
/** @inheritdoc */
override def expected(alts: ExpectedItems): ExpectedLine = alts.map("expected " + _)
/** @inheritdoc */
override def reason(reason: String): Message = reason
/** @inheritdoc */
override def message(msg: String): Message = msg
/** @inheritdoc */
override val numLinesBefore = 1
/** @inheritdoc */
override val numLinesAfter = 1
/** @inheritdoc */
override def lineInfo(line: String, linesBefore: Seq[String], linesAfter: Seq[String], errorPointsAt: Int, errorWidth: Int): LineInfo = {
linesBefore.map(line => s"$errorLineStart$line") ++:
Seq(s"$errorLineStart$line", s"${" " * errorLineStart.length}${errorPointer(errorPointsAt, errorWidth)}") ++:
linesAfter.map(line => s"$errorLineStart$line")
}
private val errorLineStart = ">"
private def errorPointer(caretAt: Int, caretWidth: Int) = s"${" " * caretAt}${"^" * caretWidth}"
/** @inheritdoc */
type Item = String
/** @inheritdoc */
type Raw = String
/** @inheritdoc */
type Named = String
/** @inheritdoc */
type EndOfInput = String
/** @inheritdoc */
override def raw(item: String): Raw = helpers.renderRawString(item)
/** @inheritdoc */
override def named(item: String): Named = item
/** @inheritdoc */
override val endOfInput: EndOfInput = "end of input"
}
private object DefaultErrorBuilder {
private val Unknown = "unknown parse error"
}
// $COVERAGE-ON$