add program into edge

This commit is contained in:
Paul R. Tagliamonte
2024-12-19 11:14:53 -05:00
parent 82ab3e9ba9
commit 5d04dd4ef8
4 changed files with 56 additions and 38 deletions

View File

@ -0,0 +1,6 @@
mod walk;
// use crate::{
// parsing::ast::types,
// walk::{Node, Visitable, Visitor},
// };

View File

@ -0,0 +1 @@

View File

@ -57,6 +57,7 @@ macro_rules! eprint {
static ALLOC: dhat::Alloc = dhat::Alloc; static ALLOC: dhat::Alloc = dhat::Alloc;
mod coredump; mod coredump;
mod diff;
mod docs; mod docs;
mod engine; mod engine;
mod errors; mod errors;

View File

@ -7,10 +7,18 @@ use crate::{
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
/// ///
type Declaration<'tree> = (Node<'tree>, &'tree types::Identifier); type Declaration<'tree> = (
types::NodeRef<'tree, types::Program>,
Node<'tree>,
&'tree types::Identifier,
);
/// ///
type Reference<'tree> = (Node<'tree>, &'tree types::Identifier); type Reference<'tree> = (
types::NodeRef<'tree, types::Program>,
Node<'tree>,
&'tree types::Identifier,
);
/// ///
type RefEdge<'tree> = (Option<Declaration<'tree>>, Reference<'tree>); type RefEdge<'tree> = (Option<Declaration<'tree>>, Reference<'tree>);
@ -18,6 +26,9 @@ type RefEdge<'tree> = (Option<Declaration<'tree>>, Reference<'tree>);
/// ///
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Scope<'tree> { pub struct Scope<'tree> {
///
pub program: types::NodeRef<'tree, types::Program>,
/// ///
pub declarations: Vec<Declaration<'tree>>, pub declarations: Vec<Declaration<'tree>>,
@ -29,8 +40,9 @@ pub struct Scope<'tree> {
} }
impl<'tree> Scope<'tree> { impl<'tree> Scope<'tree> {
pub fn new() -> Self { pub fn new(program: types::NodeRef<'tree, types::Program>) -> Self {
Scope { Scope {
program,
declarations: vec![], declarations: vec![],
references: vec![], references: vec![],
children: vec![], children: vec![],
@ -42,26 +54,29 @@ impl<'tree> Scope<'tree> {
let mut unmatched_refs = self.references.clone(); let mut unmatched_refs = self.references.clone();
for child in &self.children { for child in &self.children {
for (declaration, (ref_node, ref_id)) in child.edges() { for (declaration, (ref_program, ref_node, ref_id)) in child.edges() {
match declaration { match declaration {
Some((decl_node, decl_id)) => { Some((decl_program, decl_node, decl_id)) => {
edges.push((Some((decl_node.clone(), decl_id)), (ref_node.clone(), ref_id))); edges.push((
Some((decl_program, decl_node.clone(), decl_id)),
(ref_program, ref_node.clone(), ref_id),
));
} }
None => { None => {
unmatched_refs.push((ref_node.clone(), ref_id)); unmatched_refs.push((ref_program, ref_node.clone(), ref_id));
} }
} }
} }
} }
for (ref_node, ref_id) in unmatched_refs.into_iter() { for (ref_program, ref_node, ref_id) in unmatched_refs.into_iter() {
edges.push(( edges.push((
self.declarations self.declarations
.iter() .iter()
.filter(|(_, decl_id)| decl_id.name == ref_id.name) .filter(|(_, _, decl_id)| decl_id.name == ref_id.name)
.cloned() .cloned()
.next(), .next(),
(ref_node.clone(), ref_id), (ref_program, ref_node.clone(), ref_id),
)); ));
} }
@ -76,9 +91,9 @@ pub struct ScopeVisitor<'tree> {
} }
impl<'tree> ScopeVisitor<'tree> { impl<'tree> ScopeVisitor<'tree> {
pub fn new() -> Self { pub fn new(program: types::NodeRef<'tree, types::Program>) -> Self {
Self { Self {
scope: Arc::new(Mutex::new(Scope::new())), scope: Arc::new(Mutex::new(Scope::new(program))),
} }
} }
} }
@ -87,8 +102,8 @@ impl<'tree> Visitor<'tree> for ScopeVisitor<'tree> {
type Error = std::convert::Infallible; type Error = std::convert::Infallible;
fn visit_node(&self, node: Node<'tree>) -> Result<bool, Self::Error> { fn visit_node(&self, node: Node<'tree>) -> Result<bool, Self::Error> {
if let Node::Program(_program) = node { if let Node::Program(program) = node {
let csv = ScopeVisitor::new(); let csv = ScopeVisitor::new(program);
for child in node.children() { for child in node.children() {
child.visit(csv.clone())?; child.visit(csv.clone())?;
} }
@ -103,18 +118,19 @@ impl<'tree> Visitor<'tree> for ScopeVisitor<'tree> {
match node { match node {
Node::VariableDeclaration(vd) => { Node::VariableDeclaration(vd) => {
// process and return let program = self.scope.lock().unwrap().program;
self.scope self.scope
.lock() .lock()
.unwrap() .unwrap()
.declarations .declarations
.push((node.clone(), &vd.declaration.id)); .push((program, node.clone(), &vd.declaration.id));
let node: Node = (&vd.declaration.init).into(); let node: Node = (&vd.declaration.init).into();
node.visit(self.clone())?; node.visit(self.clone())?;
} }
Node::Identifier(id) => { Node::Identifier(id) => {
self.scope.lock().unwrap().references.push((node.clone(), &id)); let program = self.scope.lock().unwrap().program;
self.scope.lock().unwrap().references.push((program, node.clone(), &id));
} }
_ => { _ => {
for child in node.children() { for child in node.children() {
@ -127,21 +143,15 @@ impl<'tree> Visitor<'tree> for ScopeVisitor<'tree> {
} }
} }
pub fn extract_refgraph<'a, 'tree>(node: Node<'tree>) -> Result<Scope<'tree>, std::convert::Infallible> { pub fn extract_refgraph<'a, 'tree>(
let sv = ScopeVisitor::new(); program: types::NodeRef<'tree, types::Program>,
) -> Result<Scope<'tree>, std::convert::Infallible> {
let sv = ScopeVisitor::new(program);
let node: Node = (program).into();
match node {
Node::Program(_) => {
// here we can avoid walking the root since that's going to create
// a new scope.
for child in node.children() { for child in node.children() {
child.visit(sv.clone())?; child.visit(sv.clone())?;
} }
}
_ => {
node.visit(sv.clone())?;
}
}
let x = sv.scope.lock().unwrap().clone(); let x = sv.scope.lock().unwrap().clone();
Ok(x) Ok(x)
@ -171,18 +181,18 @@ fn myfn = () => {
" "
); );
let refgraph = extract_refgraph((&program).into()).unwrap(); let refgraph = extract_refgraph(&program).unwrap();
let edges = refgraph.edges().into_iter().collect::<Vec<_>>(); let edges = refgraph.edges().into_iter().collect::<Vec<_>>();
assert_eq!(edges.len(), 3); assert_eq!(edges.len(), 3);
// sin is a global so we are chilin // sin is a global so we are chilin
let (decl, (_ref_node, ref_id)) = edges.get(2).unwrap(); let (decl, (_ref_prog, _ref_node, ref_id)) = edges.get(2).unwrap();
assert_eq!("sin", ref_id.name); assert_eq!("sin", ref_id.name);
assert!(decl.is_none()); assert!(decl.is_none());
// myfn's foo // myfn's foo
let (decl, (_ref_node, ref_id)) = edges.get(1).unwrap(); let (decl, (_ref_prog, _ref_node, ref_id)) = edges.get(1).unwrap();
assert_eq!("foo", ref_id.name); assert_eq!("foo", ref_id.name);
assert!(decl.is_some()); assert!(decl.is_some());
// todo: check this is actually refering to the parent scope foo // todo: check this is actually refering to the parent scope foo
@ -202,7 +212,7 @@ fn myfn = () => {
" "
); );
let refgraph = extract_refgraph((&program).into()).unwrap(); let refgraph = extract_refgraph(&program).unwrap();
assert_eq!(3, refgraph.declarations.len()); assert_eq!(3, refgraph.declarations.len());
assert_eq!( assert_eq!(
@ -210,7 +220,7 @@ fn myfn = () => {
refgraph refgraph
.declarations .declarations
.iter() .iter()
.map(|(_, id)| id.name.as_str()) .map(|(_, _, id)| id.name.as_str())
.collect::<Vec<_>>() .collect::<Vec<_>>()
.as_slice() .as_slice()
); );
@ -221,7 +231,7 @@ fn myfn = () => {
refgraph refgraph
.references .references
.iter() .iter()
.map(|(_, id)| id.name.as_str()) .map(|(_, _, id)| id.name.as_str())
.collect::<Vec<_>>() .collect::<Vec<_>>()
.as_slice() .as_slice()
); );
@ -234,7 +244,7 @@ fn myfn = () => {
&["foo"], &["foo"],
myfn.declarations myfn.declarations
.iter() .iter()
.map(|(_, id)| id.name.as_str()) .map(|(_, _, id)| id.name.as_str())
.collect::<Vec<_>>() .collect::<Vec<_>>()
.as_slice() .as_slice()
); );
@ -244,7 +254,7 @@ fn myfn = () => {
&["sin", "foo"], &["sin", "foo"],
myfn.references myfn.references
.iter() .iter()
.map(|(_, id)| id.name.as_str()) .map(|(_, _, id)| id.name.as_str())
.collect::<Vec<_>>() .collect::<Vec<_>>()
.as_slice() .as_slice()
); );