use std::rc::Rc;
use std::fs::File;
use std::io::Write;
use adapton::reflect;
use adapton::engine::manage;
use crate::shared::Shared;
use crate::ast::{Name, Exp, Val, PrimApp, UseAllModule, Module, Decls};
use crate::bitype;
use crate::dynamics;
pub fn label_exp(e: Exp, ct: &mut usize) -> Exp {
rewrite_exp(&e, ct)
}
fn rewrite_exp_rec(e: &Rc<Exp>, ct: &mut usize) -> Rc<Exp> {
Rc::new(rewrite_exp(&**e, ct))
}
fn rewrite_val_rec(v: &Rc<Val>, ct: &mut usize) -> Rc<Val> {
Rc::new(rewrite_val(&**v, ct))
}
fn rewrite_decls_rec(d: &Rc<Decls>, ct: &mut usize) -> Rc<Decls> {
Rc::new(rewrite_decls(&**d, ct))
}
fn rewrite_useall(useall: &UseAllModule, ct: &mut usize) -> UseAllModule {
let mut u = useall.clone();
u.module = Shared::new(rewrite_module(&*u.module, ct));
u
}
fn rewrite_module(module: &Module, ct: &mut usize) -> Module {
let mut m = module.clone();
m.decls = rewrite_decls(&m.decls, ct);
m
}
fn rewrite_decls(decls: &Decls, ct: &mut usize) -> Decls {
match *decls {
Decls::UseAll(ref u, ref d) => Decls::UseAll(rewrite_useall(u, ct), rewrite_decls_rec(d, ct)),
Decls::Doc(ref s, ref d) => Decls::Doc(s.clone(), rewrite_decls_rec(d, ct)),
Decls::NmTm(ref s, ref n, ref d) => Decls::NmTm(s.clone(), n.clone(), rewrite_decls_rec(d, ct)),
Decls::IdxTm(ref s, ref i, ref d) => Decls::IdxTm(s.clone(), i.clone(), rewrite_decls_rec(d, ct)),
Decls::Type(ref s, ref t, ref d) => Decls::Type(s.clone(), t.clone(), rewrite_decls_rec(d, ct)),
Decls::Val(ref s, ref ot, ref v, ref d) => Decls::Val(s.clone(), ot.clone(), rewrite_val(v, ct), rewrite_decls_rec(d, ct)),
Decls::Fn(ref s, ref t, ref e, ref d) => Decls::Fn(s.clone(), t.clone(), rewrite_exp(e, ct), rewrite_decls_rec(d, ct)),
Decls::End => Decls::End,
Decls::NoParse(ref s) => Decls::NoParse(s.clone()),
}
}
fn rewrite_exp(exp: &Exp, ct: &mut usize) -> Exp {
let new_exp = match *exp {
Exp::AnnoC(ref e, ref t) => Exp::AnnoC(rewrite_exp_rec(e, ct), t.clone()),
Exp::AnnoE(ref e, ref t) => Exp::AnnoE(rewrite_exp_rec(e, ct), t.clone()),
Exp::Force(ref v) => Exp::Force(rewrite_val(v, ct)),
Exp::Thunk(ref v, ref e) => Exp::Thunk(rewrite_val(v, ct), rewrite_exp_rec(e, ct)),
Exp::Unroll(ref v, ref s, ref e) => Exp::Unroll(rewrite_val(v, ct), s.clone(), rewrite_exp_rec(e, ct)),
Exp::Fix(ref s, ref e) => Exp::Fix(s.clone(), rewrite_exp_rec(e, ct)),
Exp::Ret(ref v) => Exp::Ret(rewrite_val(v, ct)),
Exp::DefType(ref s, ref t, ref e) => Exp::DefType(s.clone(), t.clone(), rewrite_exp_rec(e, ct)),
Exp::Let(ref s, ref e1, ref e2) => Exp::Let(s.clone(), rewrite_exp_rec(e1, ct), rewrite_exp_rec(e2, ct)),
Exp::Lam(ref s, ref e) => Exp::Lam(s.clone(), rewrite_exp_rec(e, ct)),
Exp::HostFn(ref hef) => Exp::HostFn(hef.clone()), Exp::App(ref e, ref v) => Exp::App(rewrite_exp_rec(e, ct), rewrite_val(v, ct)),
Exp::Split(ref v, ref s1, ref s2, ref e) => Exp::Split(rewrite_val(v, ct), s1.clone(), s2.clone(), rewrite_exp_rec(e, ct)),
Exp::Case(ref v, ref s1, ref e1, ref s2, ref e2) => Exp::Case(rewrite_val(v, ct), s1.clone(), rewrite_exp_rec(e1, ct), s2.clone(), rewrite_exp_rec(e2, ct)),
Exp::IfThenElse(ref v, ref e1, ref e2) => Exp::IfThenElse(rewrite_val(v, ct), rewrite_exp_rec(e1, ct), rewrite_exp_rec(e2, ct)),
Exp::RefAnon(ref v) => Exp::RefAnon(rewrite_val(v, ct)),
Exp::Ref(ref v1, ref v2) => Exp::Ref(rewrite_val(v1, ct), rewrite_val(v2, ct)),
Exp::Get(ref v) => Exp::Get(rewrite_val(v, ct)),
Exp::WriteScope(ref v, ref e) => Exp::WriteScope(rewrite_val(v, ct), rewrite_exp_rec(e, ct)),
Exp::NameFnApp(ref v1, ref v2) => Exp::NameFnApp(rewrite_val(v1, ct), rewrite_val(v2, ct)),
Exp::PrimApp(ref p) => Exp::PrimApp(rewrite_prim_app(p, ct)),
Exp::Doc(ref s, ref e) => Exp::Doc(s.clone(), rewrite_exp_rec(e, ct)),
Exp::DebugLabel(ref on, ref s, ref e) => Exp::DebugLabel(on.clone(), s.clone(), rewrite_exp_rec(e, ct)),
Exp::UseAll(ref u, ref e) => Exp::UseAll(rewrite_useall(u, ct), rewrite_exp_rec(e, ct)),
Exp::Decls(ref d, ref e) => Exp::Decls(Rc::new(rewrite_decls(&*d, ct)), rewrite_exp_rec(e, ct)),
Exp::Unpack(ref x, ref y, ref v, ref e) => Exp::Unpack(x.clone(), y.clone(), rewrite_val(v, ct), rewrite_exp_rec(e, ct)),
Exp::IdxApp(ref e, ref i) => Exp::IdxApp(rewrite_exp_rec(e, ct), i.clone()),
Exp::Unimp => Exp::Unimp,
Exp::NoParse(ref s) => Exp::NoParse(s.clone()),
};
*ct += 1;
Exp::DebugLabel(Some(Name::Num(*ct)), None, Rc::new(new_exp))
}
fn rewrite_val(val: &Val, ct: &mut usize) -> Val {
match *val {
Val::Pair(ref v1, ref v2) => Val::Pair(rewrite_val_rec(v1, ct), rewrite_val_rec(v2, ct)),
Val::Inj1(ref v) => Val::Inj1(rewrite_val_rec(v, ct)),
Val::Inj2(ref v) => Val::Inj2(rewrite_val_rec(v, ct)),
Val::Roll(ref v) => Val::Roll(rewrite_val_rec(v, ct)),
Val::Anno(ref v, ref t) => Val::Anno(rewrite_val_rec(v, ct), t.clone()),
Val::ThunkAnon(ref e) => Val::ThunkAnon(rewrite_exp_rec(e, ct)),
ref v => v.clone(),
}
}
fn rewrite_prim_app(prim: &PrimApp, ct: &mut usize) -> PrimApp {
match *prim {
PrimApp::NatLte(ref v1, ref v2) => PrimApp::NatLte(rewrite_val(v1, ct), rewrite_val(v2, ct)),
PrimApp::NatLt(ref v1, ref v2) => PrimApp::NatLt(rewrite_val(v1, ct), rewrite_val(v2, ct)),
PrimApp::NatEq(ref v1, ref v2) => PrimApp::NatEq(rewrite_val(v1, ct), rewrite_val(v2, ct)),
PrimApp::NatPlus(ref v1, ref v2) => PrimApp::NatPlus(rewrite_val(v1, ct), rewrite_val(v2, ct)),
PrimApp::NameBin(ref v1, ref v2) => PrimApp::NameBin(rewrite_val(v1, ct), rewrite_val(v2, ct)),
PrimApp::RefThunk(ref v) => PrimApp::RefThunk(rewrite_val(v, ct)),
}
}
#[derive(Clone,Debug)]
pub enum Expect {
Failure, FailureXXX,
Success, SuccessXXX,
}
#[derive(Clone,Debug,Serialize)]
pub struct Bundle {
pub input: String,
pub program: bitype::ExpDer,
#[serde(skip_serializing)]
pub traces: Vec<reflect::trace::Trace>,
}
impl Bundle {
pub fn exp_rule(&self) -> bitype::ExpRule {
(*self.program.rule).clone()
}
}
#[macro_export]
macro_rules! fgi_bundle {
[$($e:tt)+] => {{
let exp = if false {
label_exp(fgi_exp![$($e)+], &mut 0)
} else {
fgi_exp![$($e)+]
};
let string = stringify!($($e)+);
fgi_db!("");
db_region_open!();
let program = synth_exp(&Ext::empty(), &Ctx::Empty, &exp);
db_region_close!();
Bundle {
input: string.to_owned(),
program: program,
traces: vec![],
}
}}
}
#[macro_export]
macro_rules! fgi_listing_expect {
[ [ $($outcome:tt)+ ] $($e:tt)+ ] => {{
fn help() -> Result<(),String> {
use std::rc::Rc;
use $crate::ast::*;
use $crate::bitype::*;
use $crate::vis::*;
let _ = Rc::new(());
let bundle : Bundle = fgi_bundle![
$($e)+
];
let filename = format!("target/{}.{}.fgb", filename_of_module_path!(), line!());
write_bundle(filename.as_str(), &bundle);
match ($($outcome)+, bundle.program.clas) {
(Expect::Success, Ok(_)) => { return Ok(()) },
(Expect::FailureXXX, Ok(_)) => { return Ok(()) },
(Expect::Success, Err(err)) => { return Err(format!("{:?}", err)) }
(Expect::FailureXXX, Err(err)) => { return Err(format!("Fixed?: {:?}", err)) }
(Expect::Failure, Ok(_)) => { return Err(format!("Expected a failure, but did _not_ observe one.")) },
(Expect::SuccessXXX, Ok(_)) => { return Err(format!("Fixed?")) }
(Expect::SuccessXXX, Err(_err)) => { return Ok(()) }
(Expect::Failure, Err(_err)) => { return Ok(()) },
}
};
use std::thread;
let child =
thread::Builder::new().stack_size(64 * 1024 * 1024).spawn(move || {
help()
});
let res = child.unwrap().join();
println!("Thread join result: {:?}", &res);
let res = res.unwrap();
println!(" thread result: {:?}", &res);
assert!(res.is_ok());
}}
}
#[macro_export]
macro_rules! fgi_listing_test {
[ $($e:tt)+ ] => {{
{
fgi_listing_expect![ [ Expect::Success ] $($e)+ ]
}
}}
}
pub fn capture_traces<F>(f: F) -> (dynamics::ExpTerm, Vec<reflect::trace::Trace>)
where F: FnOnce() -> dynamics::ExpTerm {
manage::init_dcg();
reflect::dcg_reflect_begin();
let term = f();
let traces = reflect::dcg_reflect_end();
(term, traces)
}
pub fn write_bundle(filename: &str, bundle: &Bundle) {
let data = format!("{:?}", bundle);
let mut f = File::create(filename).expect("Could not create bundle file");
f.write_all(data.as_bytes()).expect("Could not write bundle data");
f.flush().expect("Could not flush bundle output");
}
#[macro_export]
macro_rules! fgi_dynamic_trace {
{ [ $($expect:tt)+ ] $($e:tt)+ } => {{
use $crate::reduce;
use $crate::dynamics;
use std::rc::Rc;
use $crate::ast::*;
use adapton::engine;
let _ = Rc::new(());
let e = fgi_exp![ $($e)+ ];
use $crate::html;
use $crate::vis;
use adapton::reflect;
use adapton::reflect::trace;
use std::fs::File;
use std::io::BufWriter;
use std::io::Write;
use $crate::html::WriteHTML;
engine::manage::init_dcg();
reflect::dcg_reflect_begin();
let result = {
let mut lab = 0;
let e = if false { vis::label_exp(e, &mut lab) } else { e };
reduce::reduce_db(vec![], dynamics::env_emp(), e)
};
println!("{}:{}: result: {:?}", module_path!(), line!(), result);
let traces = reflect::dcg_reflect_end();
let count = trace::trace_count(&traces, None);
println!("{:?}", count);
let f = File::create(format!("target/{}.{}.html", filename_of_module_path!(), line!())).unwrap();
let mut writer = BufWriter::new(f);
writeln!(writer, "{}", html::style_string()).unwrap();
writeln!(writer, "<div class=\"traces\">").unwrap();
for tr in traces {
html::div_of_trace(&tr).write_html(&mut writer);
};
writeln!(writer, "</div>").unwrap();
}}
}