///|
fn show_field(
tree : @abnf.InputTree,
input : Bytes,
root : Int32,
name : String,
) -> Unit {
for id in tree.rule_nodes_in(name, root).unwrap() {
let (start, end) = tree.span(id).unwrap()
println(
" \{name}=[\{start},\{end}) raw=\{tree.extract(input, id).unwrap()}",
)
}
}
///|
fn outcome(status : @abnf.MatchStatus) -> String {
match status {
@abnf.Matched => "matched"
@abnf.NoMatch => "no-match"
@abnf.BudgetExceeded(reason) => "indeterminate (\{reason})"
@abnf.UnknownRule => "unknown-rule"
@abnf.InvalidLimits => "invalid-limits"
}
}
///|
fn show_grammar(grammar : Bytes) -> Unit raise {
let ast = @abnf.parse(grammar).unwrap()
let mut end = 0
while end < grammar.length() && grammar[end] != b'\r' {
end = end + 1
}
println("Grammar AST: \{ast.rules.length()} rules; first source rule:")
println(" \{@utf8.decode(grammar[0:end])}")
}
///|
fn node_label(kind : @abnf.InputNodeKind) -> String {
match kind {
@abnf.RuleNode(name) => "Rule(\{name})"
@abnf.LiteralNode => "Literal"
@abnf.RangeNode => "Range"
@abnf.SequenceNode => "Sequence"
@abnf.ChoiceNode(branch) => "Choice(\{branch})"
@abnf.RepeatNode(count) => "Repeat(\{count})"
}
}
///|
fn show_node(tree : @abnf.InputTree, id : Int32, indent : String) -> Unit {
let node = tree.nodes[id]
println("\{indent}\{node_label(node.kind)} [\{node.start},\{node.end})")
}
///|
fn show_tree(tree : @abnf.InputTree) -> Unit {
println("Input derivation tree (first 3 levels):")
show_node(tree, tree.root, " ")
for child in tree.nodes[tree.root].children {
show_node(tree, child, " ")
for grandchild in tree.nodes[child].children {
show_node(tree, grandchild, " ")
}
}
}
///|
fn main raise {
let grammar = @protocols.uri_grammar()
show_grammar(grammar)
let uri = @abnf.compile(grammar).unwrap()
let input = b"https://[2001:db8::1]:8443/a%20b?q=1#top"
let tree = uri.parse_input("URI", input).tree.unwrap()
show_tree(tree)
println("URI components (syntax only, no percent decoding):")
for name in ["scheme", "host", "port", "path-abempty", "query", "fragment"] {
show_field(tree, input, tree.root, name)
}
let grammar = @protocols.cookie_grammar()
show_grammar(grammar)
let cookie = @abnf.compile(grammar).unwrap()
let input = b"session=abc; theme=\"dark\"; empty=; session=second"
let tree = cookie.parse_input("cookie-string", input).tree.unwrap()
show_tree(tree)
println("Cookie pairs (duplicates and quotes preserved):")
for pair in tree.rule_nodes_in("cookie-pair", tree.root).unwrap() {
show_field(tree, input, pair, "cookie-name")
show_field(tree, input, pair, "cookie-value")
}
let rejected = cookie.parse_input("cookie-string", b"session=bad value")
println(
"Invalid Cookie: \{outcome(rejected.status)} at byte \{rejected.offset}",
)
let limited = cookie.parse_input("cookie-string", input, limits={
..@abnf.default_input_tree_limits(),
max_nodes: 1,
})
println(
"Limited Cookie: \{outcome(limited.status)}, tree absent=\{limited.tree is None}",
)
}