///|
fn scanner_error(
code : String,
message : String,
span : Span,
title~ : String,
report~ : Array[Block],
) -> Diagnostic {
Diagnostic::{ code, severity: Severity::Error, message, span, title, report, }
}
///|
/// An excerpt of the line of `highlight`, marking `highlight`.
fn line_excerpt(highlight : Span) -> Block {
Excerpt(context={ start: highlight.start, end: highlight.start, }, highlight~)
}
///|
/// `span` moved `columns` code units to the right on the same line.
fn shift(p : Position, columns : Int) -> Position {
{ offset: p.offset + columns, line: p.line, column: p.column + columns, }
}
///|
fn text(s : String) -> Block {
Text([Plain(s)])
}
///|
/// A block comment with no end. `span` runs from `{-` to the end of the input.
pub fn unterminated_block_comment(span : Span) -> Diagnostic {
scanner_error(
"KR-SCAN-001",
"Unterminated block comment",
span,
title="ENDLESS COMMENT",
report=endless_comment_report(span),
)
}
///|
fn endless_comment_report(span : Span) -> Array[Block] {
[
text("I cannot find the end of this multi-line comment:"),
line_excerpt({ start: span.start, end: shift(span.start, 2), }),
Text([
Plain("Add a "),
Chunk::code("-}"),
Plain(" somewhere after this to end the comment."),
]),
Hint([
Plain("Multi-line comments can be nested in Elm, so "),
Chunk::code("{- {- -} -}"),
Plain(
" is a comment that happens to contain another comment. The start and end markers must always be balanced.",
),
]),
]
}
///|
/// A doc comment with no end. `span` runs from `{-|` to the end of the input.
pub fn malformed_doc_comment(span : Span) -> Diagnostic {
scanner_error(
"KR-SCAN-002",
"Malformed doc comment",
span,
title="ENDLESS COMMENT",
report=endless_comment_report(span),
)
}
///|
/// A character Elm does not allow here.
pub fn invalid_sequence(span : Span) -> Diagnostic {
scanner_error(
"KR-SCAN-003",
"Invalid or unknown character sequence",
span,
title="UNEXPECTED SYMBOL",
report=[
text("I got stuck on this symbol:"),
line_excerpt(span),
text("It is not used for anything in Elm syntax. Try removing it?"),
],
)
}
///|
/// A tab character.
pub fn tab_character(span : Span) -> Diagnostic {
scanner_error("KR-SCAN-003", "Tab character", span, title="NO TABS", report=[
text("I ran into a tab, but tabs are not allowed in Elm files."),
line_excerpt({ start: span.start, end: span.start, }),
text("Replace the tab with spaces."),
])
}
///|
/// A semicolon.
pub fn unexpected_semicolon(span : Span) -> Diagnostic {
scanner_error(
"KR-SCAN-003",
"Unexpected semicolon",
span,
title="UNEXPECTED SEMICOLON",
report=[
text("I got stuck on this semicolon:"),
line_excerpt(span),
text("Try removing it? Elm does not use semicolons to end statements."),
],
)
}
///|
/// A character that is not a symbol and is not used in Elm, such as a backtick
/// or a non-ASCII letter outside a string.
pub fn unexpected_character(span : Span) -> Diagnostic {
scanner_error(
"KR-SCAN-003",
"Unexpected character",
span,
title="UNEXPECTED CHARACTER",
report=[
text("I got stuck on this character:"),
line_excerpt(span),
text("It is not used for anything in Elm syntax. Try removing it?"),
],
)
}
///|
/// A string with no closing quote. `span` runs from the opening quote to where
/// the scanner stopped (the end of the line, or of the input).
pub fn unterminated_string(span : Span) -> Diagnostic {
scanner_error(
"KR-SCAN-004",
"Unterminated string literal",
span,
title="ENDLESS STRING",
report=[
text(
"I got to the end of the line without seeing the closing double quote:",
),
line_excerpt({ start: span.end, end: span.end, }),
Text([
Plain("Strings look like "),
Chunk::code("\"this\""),
Plain(
" with double quotes on each end. Is the closing double quote missing in your code?",
),
]),
],
)
}
///|
/// A multi-line string with no closing `"""`.
pub fn unterminated_multiline_string(span : Span) -> Diagnostic {
scanner_error(
"KR-SCAN-004",
"Unterminated multi-line string literal",
span,
title="ENDLESS STRING",
report=[
text("I cannot find the end of this multi-line string:"),
line_excerpt({ start: span.start, end: shift(span.start, 3), }),
Text([
Plain("Add a "),
Chunk::code("\"\"\""),
Plain(" somewhere after this to end the string."),
]),
],
)
}
///|
/// A character literal with no closing quote.
pub fn unterminated_char(span : Span) -> Diagnostic {
scanner_error(
"KR-SCAN-004",
"Unterminated char literal",
span,
title="MISSING SINGLE QUOTE",
report=[
text(
"I thought I was parsing a character, but I got to the end of the line without seeing the closing single quote:",
),
line_excerpt({ start: span.end, end: span.end, }),
text("Add a closing single quote here!"),
],
)
}
///|
/// A GLSL block with no closing `|]`.
pub fn unterminated_glsl(span : Span) -> Diagnostic {
scanner_error(
"KR-SCAN-004",
"Unterminated GLSL literal",
span,
title="ENDLESS SHADER",
report=[
text("I cannot find the end of this shader:"),
line_excerpt({ start: span.start, end: shift(span.start, 6), }),
Text([
Plain("Add a "),
Chunk::code("|]"),
Plain(" somewhere after this to end the shader."),
]),
],
)
}