Unnamed repository; edit this file 'description' to name the repository.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#![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));
        }
    }
}