// Copyright 2026 Leo Cheng
// SPDX-License-Identifier: Apache-2.0
///|
/// One pattern, three spellings, one answer.
///
/// `[A-Z](\d)-(\d+)` is written in Python's grammar, in the `lexmatch` grammar
/// the core library speaks, and assembled from the combinators. All three are
/// the same kind of value and match alike; the first is then lowered onto the
/// core engine, and it answers the same again.
fn main raise {
let text = "see L1-42 and L2-7"
let py = @moonregex.compile("[A-Z](\\d)-(\\d+)")
// The `lexmatch` grammar has no `\d`; its classes are spelled the POSIX way.
let core = @moonregex.compile(
"[A-Z]([0-9])-([0-9]+)",
dialect=@moonregex.lexmatch_dialect,
)
// `Pattern::string` is a literal, so the assembled one spells its letters
// and digs and leaves the classes to the written forms.
let built = @moonregex.Pattern::string("L").capture("key") +
@moonregex.Pattern::string("1").capture("page") +
@moonregex.Pattern::string("-") +
@moonregex.Pattern::string("42").capture("line")
println("python: " + walk(py, text))
println("lexmatch: " + walk(core, text))
println("combinators: " + walk(built, "L1-42"))
println(
"python and lexmatch agree: " +
(walk(py, text) == walk(core, text)).to_string(),
)
match py.lower() {
None => println("lower: outside the core engine")
Some(regex) =>
match regex.execute(text) {
None => println("lower: no match")
Some(m) => println("lower: " + m.content().to_owned())
}
}
println(
"a backreference lowers: " +
(@moonregex.compile("(a)\\1").lower() is Some(_)).to_string(),
)
}
///|
/// Every match with its groups, as one line.
fn walk(pattern : @moonregex.Pattern, text : String) -> String raise {
let parts : Array[String] = []
for m in pattern.finditer(text) {
let groups : Array[String] = []
let mut slot = 1
while slot <= pattern.groups() {
groups.push(m.group(slot).unwrap_or("?"))
slot += 1
}
parts.push(groups.join("/"))
}
" [" + parts.join(" ") + "]"
}