use clap::Parser;
use std::{num::NonZeroU64, path::PathBuf, process::exit};
#[allow(unused_imports)]
use graphlang::{
match_subgraph, Edge, Graph, GraphGrammar, Isomorphism, Node, Production, QuitCondition,
};
#[derive(Parser, Debug)]
#[clap(author, version, about)]
struct Args {
input: PathBuf,
#[clap(short, long)]
output: Option<PathBuf>,
#[clap(short, long)]
max: Option<NonZeroU64>,
#[clap(short, long)]
timeout: Option<String>,
#[clap(short, long)]
asap: bool,
#[clap(short, long)]
verbose: bool,
}
fn error(errormsg: &str) -> ! {
eprintln!("{}", errormsg);
exit(1);
}
fn main() {
pretty_env_logger::init_timed();
eprintln!(
r"NOTE: This application is far from finished or even usable.
Currently it always applies 5x a production called 'extend' and
after that 'finalize'. It also only supports graph grammars without
edge labels and edges are assumed to be bidirectional.
"
);
let args = Args::parse();
#[allow(unused_assignments)]
let mut file_contents = String::new();
let gg = {
use graphlang::predefined;
if args.input.starts_with("Ladder") {
let s = args
.input
.to_str()
.unwrap_or_else(|| error("Ladder{integer} contains invalid unicode symbols"));
let n = s[6..].parse().expect("Invalid integer after Ladder");
predefined::ladder_grammar(n)
} else if args.input == PathBuf::from("String") {
predefined::string_grammar()
} else {
file_contents = std::fs::read_to_string(&args.input)
.unwrap_or_else(|_| error("Input file can't be opened"));
serde_json::from_str(&file_contents) .unwrap_or_else(|_| error("Deserialize json"))
}
};
let quitcondition = {
let mut cond = QuitCondition::new();
if args.asap {
cond = cond.on_first_valid_graph();
}
if let Some(timeout) = args.timeout {
let timeout = timeout
.parse::<humantime::Duration>()
.expect("Invalid duration given");
cond = cond.add_timeout(timeout.into());
}
if let Some(max) = args.max {
cond = cond.add_max_productions(max);
}
if !cond.is_valid() {
error("At least one of the starred options has to be used!");
}
cond
};
let g = {
let _ = quitcondition;
let mut g = gg.start_graph.clone();
println!("----> {:?}", &g);
for n in 0..5 {
gg.productions["extend"].apply_inplace(&mut g).unwrap();
println!("{n:4}: {:?}", &g.nodes);
println!(" {:?}", &g.edges);
}
gg.productions["finalize"].apply_inplace(&mut g).unwrap();
println!(" fin: {:?}", &g.nodes);
println!(" {:?}", &g.edges);
g
};
if let Some(ref out) = &args.output {
let mut out = out.clone();
out.set_extension("dot");
println!("\nWriting graph to {}", out.to_string_lossy());
let mut f = std::fs::File::create(out) .expect("Output path is accesible");
g.write_dot_to(&mut f)
.expect("Output path can be written to");
}
}