Shrubbery notation for MoonBit: parser, source-faithful and reformatting printers, and structured diagnostics
Dependencies
moon add marianoguerra/shrubberyimport {
"marianoguerra/shrubbery" @shrub,
"marianoguerra/shrubbery/ast",
}///|
test {
let parsed = @shrub.parse("def pi = 3.14\n")
inspect(
parsed.root().canonical(),
content="(multi (group |def| |pi| (op |=|) #f64:40091eb851eb851f))",
)
}///|
test {
let parsed = @shrub.parse("if x\n| yes\n| no\n")
inspect(
parsed.root().canonical(),
content="(multi (group |if| |x| (alts (block (group |yes|)) (block (group |no|)))))",
)
}///|
test {
let src =
#|f(1, /* two */ 2):
#| body // trailing
#|
let parsed = @shrub.parse(src)
assert_eq(@shrub.to_source(parsed.root()), src)
}///|
test {
let parsed = @shrub.parse("hello:\n world\n universe\n")
// Line- and column-insensitive: safe to re-indent, wrap, or paste anywhere.
inspect(@shrub.write(parsed.root()), content="hello:« world; universe »")
// Or laid out to a width.
inspect(
@shrub.write(parsed.root(), style=Pretty, width=Some(0)),
content=(
#|hello:
#| world
#| universe
),
)
}///|
test {
let src = "hello:\n world\n universe\n"
let kind = try {
let _ = @shrub.parse(src)
None
} catch {
ShrubberyError(d) => Some(d.kind)
}
assert_true(kind is Some(WrongIndentation(_)))
}///|
test {
let parsed = @shrub.parse("a:\n b\n c\nd:\n e\n f\n", recover=true)
assert_eq(parsed.diagnostics().length(), 2)
}///|
test {
let src = "hello:\n world\n universe\n"
let sources = @report.Sources::new()
let id = sources.add("greeting.shrub", src)
let out = try {
let _ = @shrub.parse(src)
""
} catch {
ShrubberyError(d) =>
@render.render_string(@shrub.to_report(d, id), sources, {
..@render.default_config,
theme: @style.mono_theme,
color: Never,
})
}
inspect(
out,
content=(
#|error[shrubbery::wrong_indentation]: this group is not indented like the ones around it
#| ╭─[ greeting.shrub:3:2 ]
#| │
#|2 │ world
#|3 │ universe
#| │ ───┬────
#| │ ╰─ this column does not line up
#| │
#| ├─ help: every group in a sequence starts at the same column
#| ╰─
#|
),
)
}///|
test {
let toks = @shrub.tokens("x + y\n")
inspect(toks.length(), content="7")
let buf = StringBuilder()
for t in toks {
buf.write_string(t.text)
}
assert_eq(buf.to_string(), "x + y\n")
}Install
Download zipShrubbery notation for MoonBit: parser, source-faithful and reformatting printers, and structured diagnostics
Dependencies