use std::io;
use std::io::Write;
use std::collections::HashMap;
use std::str::FromStr;
extern crate bex;
use bex::*;
use bex::nid::NID;
use bex::ast::ASTBase;
use bex::solve;
use bex::anf::ANFBase;
use bex::bdd::BddBase;
use bex::ops;
fn readln()->String {
let mut buf = String::new();
print!("> ");
io::stdout().flush() .expect("couldn't flush stdout.");
io::stdin().read_line(&mut buf) .expect("failed to read line.");
buf}
fn swap(data: &mut [NID]) {
let p = data.len()-1;
if p > 0 { data.swap(p-1,p) }}
fn pop<T>(data: &mut Vec<T>)->T {
data.pop().expect("underflow")}
fn pop2<T>(data: &mut Vec<T>)->(T,T){
let y=pop(data); let x=pop(data); (x,y) }
fn repl(base:&mut ASTBase) {
let mut scope = HashMap::new();
let mut data: Vec<NID> = Vec::new();
let mut bdds = BddBase::new();
let mut anfs = ANFBase::new();
'main: loop {
print!("[ "); for x in &data { print!("{} ", *x); } println!("]");
let line = readln();
for word in line.split_whitespace() {
match word {
"~"|"not"|"!" => { let x = pop(&mut data); data.push(!x) }
"and" => { let (x,y)=pop2(&mut data); data.push(base.and(x,y)) }
"xor" => { let (x,y)=pop2(&mut data); data.push(base.xor(x,y)) }
"or" => { let (x,y)=pop2(&mut data); data.push(base.or(x,y)) }
"'and" => { data.push(ops::AND.to_nid()) }
"'or" |
"'vel" => { data.push(ops::VEL.to_nid()) }
"'xor" => { data.push(ops::XOR.to_nid()) }
"'imp" => { data.push(ops::IMP.to_nid()) }
"'nor" => { data.push(ops::NOR.to_nid()) }
"dot" => { let mut s=String::new(); base.dot(pop(&mut data),&mut s); print!("{}", s); }
"sho" => base.show(pop(&mut data)),
"bdd" => { let top=pop(&mut data); let n = solve::solve(&mut bdds,base.raw_ast(),top).n; bdds.show(n); data.push(n); }
"bdd-dot" => { let mut s=String::new(); bdds.dot(pop(&mut data),&mut s); print!("{}", s); }
"anf" => { let top=pop(&mut data); let n = solve::solve(&mut anfs,base.raw_ast(),top).n; anfs.show(n); data.push(n); }
"anf-dot" => { let mut s=String::new(); anfs.dot(pop(&mut data),&mut s); print!("{}", s); }
"q" => break 'main,
"." => { let nid = data.pop().expect("underflow"); println!("{}", nid); }
"drop" => { let _ = pop(&mut data); }
"dup" => { let x = pop(&mut data); data.push(x); data.push(x); }
"swap" => swap(&mut data),
"reset" => data = Vec::new(),
"i"|"I" => data.push(nid::I),
"o"|"O" => data.push(nid::O),
_ => {
if word.starts_with(':') {
let var = word.to_string().split_off(1);
let val = pop(&mut data);
scope.insert(var,val); }
else if let Some(&val) = scope.get(word) { data.push(val); }
else { match NID::from_str(word) {
Ok(nid) => data.push(nid),
Err(err) => println!("{}", err)}}}}}}}
include!(concat!(env!("OUT_DIR"), "/bex-build-info.rs"));
fn main() {
println!("bex {BEX_VERSION} | compile flags: -O{BEX_OPT_LEVEL} | type 'q' to quit");
let mut base = ASTBase::empty();
repl(&mut base) }