#![allow(clippy::print_stderr, clippy::print_stdout)]
use std::{
env,
io::{self, Read},
process,
};
use ungrammar::{Grammar, Rule};
fn main() {
if let Err(err) = try_main() {
eprintln!("{}", err);
process::exit(101);
}
}
fn try_main() -> io::Result<()> {
if env::args().count() != 1 {
eprintln!("Usage: ungrammar2json < grammar.ungram > grammar.json");
return Ok(());
}
let grammar = read_stdin()?;
let grammar = grammar
.parse::<Grammar>()
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
let mut buf = String::new();
grammar_to_json(&grammar, write_json::object(&mut buf));
println!("{}", buf);
Ok(())
}
fn read_stdin() -> io::Result<String> {
let mut buf = String::new();
io::stdin().lock().read_to_string(&mut buf)?;
Ok(buf)
}
fn grammar_to_json(grammar: &Grammar, mut obj: write_json::Object<'_>) {
for node in grammar.iter() {
let node = &grammar[node];
rule_to_json(grammar, &node.rule, obj.object(&node.name));
}
}
fn rule_to_json(grammar: &Grammar, rule: &Rule, mut obj: write_json::Object<'_>) {
match rule {
Rule::Labeled { label, rule } => {
obj.string("label", label);
rule_to_json(grammar, rule, obj.object("rule"))
}
Rule::Node(node) => {
obj.string("node", &grammar[*node].name);
}
Rule::Token(token) => {
obj.string("token", &grammar[*token].name);
}
Rule::Seq(rules) | Rule::Alt(rules) => {
let tag = match rule {
Rule::Seq(_) => "seq",
Rule::Alt(_) => "alt",
_ => unreachable!(),
};
let mut array = obj.array(tag);
for rule in rules {
rule_to_json(grammar, rule, array.object());
}
}
Rule::Opt(arg) | Rule::Rep(arg) => {
let tag = match rule {
Rule::Opt(_) => "opt",
Rule::Rep(_) => "rep",
_ => unreachable!(),
};
rule_to_json(grammar, arg, obj.object(tag));
}
}
}