use engine::Name;
use macros::ProgPt;
use std::fmt::Debug;
use std::rc::Rc;
use std::collections::HashMap;
pub use engine::reflect_dcg::*;
pub trait Reflect<T> : Debug {
fn reflect (&self) -> T;
}
impl<S,T:Reflect<S>+Debug> Reflect<Option<S>> for Option<T> {
fn reflect (&self) -> Option<S> {
match *self {
None => None,
Some(ref x) => Some(x.reflect())
}
}
}
impl<'a,S,T:Reflect<S>+Debug> Reflect<S> for &'a Rc<T> {
fn reflect (&self) -> S {
(**self).reflect()
}
}
impl<'a,S,T:Reflect<S>+Debug> Reflect<S> for Rc<T> {
fn reflect (&self) -> S {
(**self).reflect()
}
}
#[derive(Debug,Clone,Hash,Eq,PartialEq)]
pub enum Val {
Constr(Name,Vec<Val>),
Tuple(Vec<Val>),
Vec(Vec<Val>),
Struct(Name,Vec<(Name,Val)>),
Art(Loc,ArtContent),
Name(Name),
Const(Const),
ValTODO,
}
#[derive(Debug,Clone,Hash,Eq,PartialEq)]
pub enum Const {
Num(isize),
Nat(usize),
String(String),
}
#[derive(Debug,Clone,Hash,Eq,PartialEq)]
pub enum ArtContent {
Val(Rc<Val>),
Comp(Option<Rc<Val>>),
Unknown,
}
#[derive(PartialEq,Eq,Debug,Hash,Clone)]
pub struct Loc {
pub path: Path,
pub name: Name,
}
pub type Path = Vec<Name>;
#[derive(Debug,Clone,Eq,PartialEq,Hash)]
pub enum Effect {
Force,
Alloc,
}
#[derive(Debug,Clone,Eq,PartialEq,Hash)]
pub struct Succ {
pub dirty: bool,
pub loc: Loc,
pub effect: Effect,
pub value: Val,
pub is_dup: bool,
}
impl Reflect<Succ> for Succ {
fn reflect (&self) -> Succ {
self.clone()
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Pred {
pub loc: Loc,
pub effect: Effect,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct CompNode {
pub preds: Vec<Pred>,
pub succs: Vec<Succ>,
pub prog_pt: ProgPt,
pub value: Option<Val>,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct RefNode {
pub preds: Vec<Pred>,
pub value: Val,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct PureNode {
pub value: Val,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum Node {
Comp(CompNode),
Ref(RefNode),
Pure(PureNode),
}
pub fn succs_of_node (nd:&Node) -> Option<&Vec<Succ>> {
match *nd {
Node::Comp(ref nd) => Some(&nd.succs),
Node::Ref(ref _nd) => None,
Node::Pure(ref _nd) => None,
}
}
pub fn preds_of_node (nd:&Node) -> Option<&Vec<Pred>> {
match *nd {
Node::Comp(ref nd) => Some(&nd.preds),
Node::Ref(ref nd) => Some(&nd.preds),
Node::Pure(ref _nd) => None,
}
}
#[derive(Debug, Clone)]
pub struct Frame {
pub loc: Loc,
pub succs: Vec<Succ>,
}
#[derive(Debug, Clone)]
pub struct DCG {
pub table: HashMap<Loc, Node>,
pub stack: Vec<Frame>,
pub path: Vec<Name>,
}
pub fn reflect_val <V:Debug> (v:&V) -> Val {
use parse_val::parse_val;
parse_val(v)
}
pub mod trace {
use std::fmt;
use engine;
#[derive(Clone,Debug)]
pub enum AllocCase {
LocFresh,
LocExists(ChangeFlag),
}
#[derive(Clone,Debug)]
pub enum ChangeFlag {
ContentDiff,
ContentSame,
}
#[derive(Clone,Debug)]
pub enum AllocKind {
RefCell,
Thunk,
}
#[derive(Clone,Debug)]
pub enum ForceCase {
CompCacheMiss,
CompCacheHit,
RefGet,
}
#[derive(Clone,Debug)]
pub struct Cost {
pub work:usize,
pub depth:usize,
}
#[derive(Clone,Debug)]
pub enum Effect {
UserEffect(Cost, String),
DebugLabel(Option<engine::Name>, String),
Alloc (AllocCase, AllocKind),
Force (ForceCase),
Dirty,
CleanRec,
CleanEdge,
CleanEval,
Remove,
}
#[derive(Clone,Debug)]
pub struct Edge {
pub loc: Option<super::Loc>,
pub succ: super::Succ,
}
#[derive(Clone,Debug)]
pub struct Trace {
pub effect:Effect,
pub edge: EffectEdge,
pub extent:Box<Vec<Trace>>,
}
#[derive(Clone,Debug)]
pub enum EffectEdge {
Fwd(Edge),
Bwd(Edge),
None,
}
#[derive(Clone,Copy)]
pub enum Role { Editor, Archivist }
#[derive(Clone)]
pub struct TraceCount {
pub total_updates: usize,
pub total_archivist: usize,
pub reeval_nochange: usize,
pub reeval_change: usize,
pub clean_rec: usize,
pub dirty: (usize, usize),
pub alloc_fresh: (usize, usize),
pub alloc_nochange: (usize, usize),
pub alloc_change: (usize, usize),
}
pub fn trace_count_zero() -> TraceCount {
TraceCount{ alloc_fresh:(0,0),
alloc_change:(0,0),
alloc_nochange:(0,0),
reeval_change:0,
reeval_nochange:0,
dirty:(0,0),
clean_rec:0,
total_updates:0,
total_archivist:0,
}
}
impl fmt::Debug for TraceCount {
fn fmt(&self, f:&mut fmt::Formatter) -> fmt::Result {
write!(f,"\
Trace counts: {:>12} {:>12}
------------------------------------------------
editor:
alloc_fresh: {:>12} {:>12.2}
alloc_nochange: {:>12} {:>12.2}
alloc_change: {:>12} {:>12.2}
dirty: {:>12} {:>12.2}
archivist:
alloc_fresh: {:>12} {:>12.2}
alloc_nochange: {:>12} {:>12.2}
alloc_change: {:>12} {:>12.2}
dirty: {:>12} {:>12.2}
reeval:
clean_rec: {:>12} {:>12.2}
reeval_nochange: {:>12} {:>12.2}
reeval_change: {:>12} {:>12.2}
",
format!("sum"), format!("ave"),
self.alloc_fresh.0, self.alloc_fresh.0 as f32 / self.total_updates as f32,
self.alloc_nochange.0, self.alloc_nochange.0 as f32 / self.total_updates as f32,
self.alloc_change.0, self.alloc_change.0 as f32 / self.total_updates as f32,
self.dirty.0, self.dirty.0 as f32 / self.total_updates as f32,
self.alloc_fresh.1, self.alloc_fresh.1 as f32 / self.total_updates as f32,
self.alloc_nochange.1, self.alloc_nochange.1 as f32 / self.total_updates as f32,
self.alloc_change.1, self.alloc_change.1 as f32 / self.total_updates as f32,
self.dirty.1, self.dirty.1 as f32 / self.total_updates as f32,
self.clean_rec, self.clean_rec as f32 / self.total_updates as f32,
self.reeval_nochange, self.reeval_nochange as f32 / self.total_updates as f32,
self.reeval_change, self.reeval_change as f32 / self.total_updates as f32,
)
}
}
pub fn trace_count(trs:&Vec<Trace>, total_updates:Option<usize>) -> TraceCount {
let mut trace_count = trace_count_zero();
match total_updates {
Some(x) => trace_count.total_updates = x,
None => trace_count.total_updates = 1,
}
for tr in trs {
trace_count_rec(Role::Editor, tr, &mut trace_count)
}
return trace_count
}
fn trace_count_dirty(role:Role, tr:&Trace, c:&mut TraceCount) {
match tr.effect {
Effect::Dirty => match role {
Role::Editor => c.dirty.0 += 1,
Role::Archivist => c.dirty.1 += 1,
},
_ => panic!("unexpected effect: {:?}", tr),
}
for sub_tr in tr.extent.iter() {
trace_count_dirty(role, sub_tr, c)
}
}
pub fn trace_count_rec(role:Role, tr:&Trace, c:&mut TraceCount) {
match role {
Role::Editor =>
match tr.effect {
Effect::DebugLabel(_,_) |
Effect::UserEffect(_,_) => {
for sub_tr in tr.extent.iter() {
trace_count_rec(Role::Editor, sub_tr, c);
}
},
Effect::Dirty => trace_count_dirty(role, tr, c),
Effect::Remove => unreachable!(),
Effect::CleanEdge => unreachable!(),
Effect::CleanEval => unreachable!(),
Effect::CleanRec => unreachable!(),
Effect::Alloc(AllocCase::LocFresh, _) => {
c.alloc_fresh.0 += 1;
assert!(tr.extent.len() == 0)
}
Effect::Alloc(AllocCase::LocExists(ChangeFlag::ContentSame), _) => {
c.alloc_nochange.0 += 1;
for sub_tr in tr.extent.iter() { trace_count_dirty(role, sub_tr, c) }
}
Effect::Alloc(AllocCase::LocExists(ChangeFlag::ContentDiff), _) => {
c.alloc_change.0 += 1;
for sub_tr in tr.extent.iter() { trace_count_dirty(role, sub_tr, c) }
}
Effect::Force(ForceCase::RefGet) => assert!(tr.extent.len() == 0),
Effect::Force(ForceCase::CompCacheHit) |
Effect::Force(ForceCase::CompCacheMiss) => {
c.total_archivist += 1;
for sub_tr in tr.extent.iter() {
trace_count_rec(Role::Archivist, sub_tr, c);
}
}
},
Role::Archivist =>
match tr.effect {
Effect::DebugLabel(_,_) |
Effect::UserEffect(_,_) => {
for sub_tr in tr.extent.iter() {
trace_count_rec(Role::Archivist, sub_tr, c);
}
},
Effect::Dirty => trace_count_dirty(role, tr, c),
Effect::Remove => assert!(tr.extent.len() == 0),
Effect::CleanEdge => assert!(tr.extent.len() == 0),
Effect::CleanEval => {
let mut change = false;
for subtr in tr.extent.iter() {
match subtr.effect {
Effect::DebugLabel(_,_) |
Effect::UserEffect(_,_) => unreachable!(),
Effect::Remove => (),
Effect::CleanEdge => (),
Effect::CleanEval => (),
Effect::CleanRec => (),
Effect::Alloc(AllocCase::LocExists(ChangeFlag::ContentSame), _) => (),
Effect::Alloc(AllocCase::LocFresh, _) => change = true,
Effect::Alloc(AllocCase::LocExists(ChangeFlag::ContentDiff), _) => change = true,
Effect::Force(ForceCase::RefGet) => (),
Effect::Force(ForceCase::CompCacheHit) => (),
Effect::Force(ForceCase::CompCacheMiss) => change = true,
Effect::Dirty => change = true,
}
}
if change { c.reeval_change += 1 }
else { c.reeval_nochange += 1 };
for sub_tr in tr.extent.iter() {
trace_count_rec(Role::Archivist, sub_tr, c);
}
},
Effect::CleanRec => {
c.clean_rec += 1;
for sub_tr in tr.extent.iter() {
trace_count_rec(Role::Archivist, sub_tr, c);
}
}
Effect::Alloc(AllocCase::LocFresh, _) => {
c.alloc_fresh.1 += 1;
assert!(tr.extent.len() == 0);
}
Effect::Alloc(AllocCase::LocExists(ChangeFlag::ContentSame), _) => {
c.alloc_nochange.1 += 1;
for sub_tr in tr.extent.iter() {
trace_count_rec(Role::Archivist, sub_tr, c);
}
}
Effect::Alloc(AllocCase::LocExists(ChangeFlag::ContentDiff), _) => {
c.alloc_change.1 += 1;
for sub_tr in tr.extent.iter() {
trace_count_rec(Role::Archivist, sub_tr, c);
}
}
Effect::Force(ForceCase::RefGet) => {
assert!(tr.extent.len() == 0);
},
Effect::Force(ForceCase::CompCacheHit) => {
for sub_tr in tr.extent.iter() {
trace_count_rec(Role::Archivist, sub_tr, c);
}
}
Effect::Force(ForceCase::CompCacheMiss) => {
for sub_tr in tr.extent.iter() {
trace_count_rec(Role::Archivist, sub_tr, c);
}
}
}
}
}
}