use cure_engine::kind::{EventKind, NodeKind, RegionEvent};
use cure_engine::Lang;
#[derive(Debug)]
pub struct EventStore<Id, NameKey> {
events: Vec<Vec<RegionEvent<Id, NameKey>>>,
clean: bool,
}
impl<Id, NameKey> Default for EventStore<Id, NameKey> {
fn default() -> Self {
Self { events: Vec::new(), clean: false }
}
}
impl<Id: Clone, NameKey: Clone> EventStore<Id, NameKey> {
pub fn new() -> Self {
Self::default()
}
pub fn resize(&mut self, count: usize) {
if self.events.len() < count {
self.events.resize(count, Vec::new());
}
}
pub fn slot(&self, idx: usize) -> &[RegionEvent<Id, NameKey>] {
self.events.get(idx).map(|v| v.as_slice()).unwrap_or(&[])
}
pub fn put(&mut self, idx: usize, events: Vec<RegionEvent<Id, NameKey>>) {
if self.events.len() <= idx {
self.events.resize(idx + 1, Vec::new());
}
self.events[idx] = events;
}
pub fn is_clean(&self) -> bool {
self.clean
}
pub fn mark_clean(&mut self) {
self.clean = true;
}
pub fn invalidate(&mut self, idx: usize) {
self.clean = false;
if let Some(slot) = self.events.get_mut(idx) {
slot.clear();
}
}
}
pub fn stmt_roots<L: Lang>(lang: &L, root: L::Id) -> Vec<L::Id> {
let mut stack = vec![root];
let mut stmt_roots: Vec<L::Id> = Vec::new();
while let Some(n) = stack.pop() {
if lang.kind(n) == NodeKind::Block {
for &c in lang.children(n) {
stmt_roots.push(c);
}
}
for &c in lang.children(n) {
stack.push(c);
}
}
stmt_roots
}
pub fn collect_region_events<L: Lang>(
lang: &L,
node: L::Id,
) -> Vec<RegionEvent<L::Id, L::NameKey>> {
let mut out = Vec::new();
let opaque = collect_events_into(lang, node, &mut out);
if opaque {
return Vec::new();
}
out.sort_by_key(|e| e.key);
out
}
fn collect_events_into<L: Lang>(
lang: &L,
node: L::Id,
out: &mut Vec<RegionEvent<L::Id, L::NameKey>>,
) -> bool {
if lang.is_opaque(node) {
return true;
}
match lang.kind(node) {
NodeKind::Assign => {
let ch = lang.children(node);
if let Some(&t) = ch.first() {
if lang.kind(t) == NodeKind::VarRef {
if let Some(k) = lang.var_key(t) {
out.push(RegionEvent { kind: EventKind::Write, node: t, key: k });
}
}
}
match ch.get(1) {
Some(&v) => collect_events_into(lang, v, out),
None => false,
}
}
NodeKind::Unary if lang.un_op(node).is_some_and(|o| o.is_incdec()) => {
if let Some(&t) = lang.children(node).first() {
if lang.kind(t) == NodeKind::VarRef {
if let Some(k) = lang.var_key(t) {
out.push(RegionEvent { kind: EventKind::Write, node: t, key: k });
}
}
}
false
}
NodeKind::VarDecl | NodeKind::ForEach => {
if let Some(k) = lang.var_key(node) {
out.push(RegionEvent { kind: EventKind::Write, node, key: k });
out.push(RegionEvent { kind: EventKind::Shadow, node, key: k });
}
let mut opaque = false;
for &c in lang.children(node) {
opaque |= collect_events_into(lang, c, out);
}
opaque
}
NodeKind::Catch => {
if let Some(k) = lang.var_key(node) {
out.push(RegionEvent { kind: EventKind::Shadow, node, key: k });
}
let mut opaque = false;
for &c in lang.children(node) {
opaque |= collect_events_into(lang, c, out);
}
opaque
}
NodeKind::VarRef => {
if let Some(k) = lang.var_key(node) {
out.push(RegionEvent { kind: EventKind::Use, node, key: k });
}
false
}
_ => {
let mut opaque = false;
for &c in lang.children(node) {
opaque |= collect_events_into(lang, c, out);
}
opaque
}
}
}