moonrockz/krueger/scanner does not have a README file
impl Scanner for DefaultScannertest {
let scanner = @scanner.DefaultScanner::new()
let source = @scanner.SourceText::new(
"module Main exposing (main)\n\nmain = 1 + 2\n",
)
guard scanner.tokenize(source) is Ok(stream) else { fail("scan failed") }
debug_inspect(
stream.tokens.map(t => (t.kind, t.lexeme)),
content=(
#|[
#| (Keyword(Module), "module"),
#| (Identifier, "Main"),
#| (Keyword(Exposing), "exposing"),
#| (LParen, "("),
#| (Identifier, "main"),
#| (RParen, ")"),
#| (Identifier, "main"),
#| (Equals, "="),
#| (IntLiteral, "1"),
#| (Operator("+"), "+"),
#| (IntLiteral, "2"),
#|]
),
)
}fn DefaultScanner::tokenize(self : DefaultScanner, _source : SourceText) -> Result[TokenStream, ScanErrorList]test {
let source = @scanner.SourceText::new("x = \"abc\n")
guard @scanner.DefaultScanner::new().tokenize(source) is Err(errors) else {
fail("expected a scan error")
}
let d = errors.diagnostics[0]
inspect(d.code, content="KR-SCAN-004")
debug_inspect(d.severity, content="Error")
inspect(d.title, content="ENDLESS STRING")
inspect(d.message, content="Unterminated string literal")
debug_inspect((d.span.start.column, d.span.end.column), content="(5, 9)")
}test {
let source = @scanner.SourceText::new("x = \"😀😀\" ++ y\n")
guard @scanner.DefaultScanner::new().tokenize(source) is Ok(stream) else {
fail("scan failed")
}
// The string literal: 6 UTF-16 units (two surrogate pairs and two
// quotes), but 4 columns.
let string = stream.tokens[2].span
debug_inspect((string.start.offset, string.end.offset), content="(4, 10)")
debug_inspect((string.start.column, string.end.column), content="(5, 9)")
// The `++` after it.
let plus = stream.tokens[3].span.start
debug_inspect((plus.offset, plus.line, plus.column), content="(11, 1, 10)")
}test {
let source = @scanner.SourceText::new("module Main exposing (..)\n")
debug_inspect(source.module_name, content="None")
let named = @scanner.SourceText::new("x = 1\n", module_name="Main")
debug_inspect(named.module_name, content="Some(\"Main\")")
}test {
fn trivia_text(t : @scanner.Trivia) -> String {
match t {
Whitespace(text, _) | Newline(text, _) => text
Comment(comment) => comment.text
}
}
let text = "module Main exposing (..)\n\n-- The answer.\nanswer = 42 {- end -}\n"
guard @scanner.DefaultScanner::new().tokenize(@scanner.SourceText::new(text))
is Ok(stream) else {
fail("scan failed")
}
let out = StringBuilder()
for t in stream.trivia {
out.write_string(trivia_text(t))
}
for token in stream.tokens {
for t in token.trivia_before {
out.write_string(trivia_text(t))
}
out.write_string(token.lexeme)
for t in token.trivia_after {
out.write_string(trivia_text(t))
}
}
inspect(out.to_string() == text, content="true")
// The line comment is trivia before `answer`.
let answer = stream.tokens[6]
inspect(answer.lexeme, content="answer")
debug_inspect(
answer.trivia_before.map(trivia_text),
content=(
#|["\n", "\n", "-- The answer.", "\n"]
),
)
}pub(all) enum TokenKind {
Keyword(KeywordKind)
Identifier
IntLiteral
FloatLiteral
StringLiteral
CharLiteral
Glsl
LParen
RParen
LBracket
RBracket
LBrace
RBrace
Comma
Equals
Dot
DotDot
Colon
Pipe
Arrow
Backslash
Underscore
Operator(String)
} derive(Eq, Debug)fn is_lower_start(c : Char) -> Booltest {
inspect(@scanner.is_lower_start('a'), content="true")
inspect(@scanner.is_lower_start('é'), content="true")
inspect(@scanner.is_lower_start('A'), content="false")
inspect(@scanner.is_lower_start('_'), content="false")
}fn is_name_part(c : Char) -> Booltest {
inspect(@scanner.is_name_part('x'), content="true")
inspect(@scanner.is_name_part('_'), content="true")
inspect(@scanner.is_name_part('7'), content="true")
inspect(@scanner.is_name_part('ß'), content="true")
inspect(@scanner.is_name_part('-'), content="false")
inspect(@scanner.is_name_part('\''), content="false")
}fn is_upper_start(c : Char) -> Booltest {
inspect(@scanner.is_upper_start('M'), content="true")
inspect(@scanner.is_upper_start('Ä'), content="true")
inspect(@scanner.is_upper_start('Ç…'), content="true")
inspect(@scanner.is_upper_start('m'), content="false")
}test {
let source = @scanner.SourceText::new("x = 1 -- one\n")
guard @scanner.lex_raw(source) is Ok(raw) else { fail("scan failed") }
debug_inspect(
raw.map(r => (r.kind, r.lexeme)),
content=(
#|[
#| (Significant(Identifier), "x"),
#| (Whitespace, " "),
#| (Significant(Equals), "="),
#| (Whitespace, " "),
#| (Significant(IntLiteral), "1"),
#| (Whitespace, " "),
#| (LineComment, "-- one"),
#| (Newline, "\n"),
#|]
),
)
}Install
Download zipParser and parsing utilities for Elm and Elm-like dialects (e.g. Morphir) in MoonBit
Dependencies