use tree_sitter::Node;
use crate::{ast::Ident, spans::Span, styles::ComputeStyle, utils::tree_sitter_helpers::NodeExt};
use super::{
from_node::{FromNode, FromNodeError},
Argument, Word,
};
#[derive(Debug, Default, PartialEq, Clone)]
pub struct ComputeDef {
pub compute_id: Ident, pub group_id: Word, pub compute_style: ComputeStyle,
pub args: Vec<Argument>,
pub span: Span,
}
impl ComputeDef {
pub fn range(&self) -> Span {
self.span
}
}
impl FromNode for ComputeDef {
type Error = FromNodeError;
fn from_node(node: &Node, text: &str) -> Result<Self, Self::Error> {
let span = node.range().into();
let mut cursor = node.walk();
let mut children = node.children(&mut cursor);
children.next();
let compute_id = children
.next()
.ok_or(Self::Error::PartialNode("missing compute ID".to_string()))?;
let compute_id = Ident::new(&compute_id, text)?;
let group_id = Word::from_node(
&children
.next()
.ok_or(Self::Error::PartialNode("missing group ID".to_string()))?,
text,
)?;
let compute_style = children
.next()
.ok_or(Self::Error::PartialNode(
"missing compute style".to_string(),
))?
.str_text(text)
.into();
let args = if let Some(args) = children.next() {
drop(children);
args.children(&mut cursor)
.map(|x| Argument::from_node(&x, text))
.collect::<Result<Vec<_>, _>>()?
} else {
vec![]
};
Ok(ComputeDef {
compute_id,
group_id,
compute_style,
args,
span,
})
}
}
#[cfg(test)]
mod test {
#![allow(clippy::unwrap_used)]
#![allow(clippy::expect_used)]
use pretty_assertions::assert_eq;
use super::*;
use crate::ast;
use crate::utils::testing::parse;
#[test]
fn parse_compute_with_args() {
let source = "compute T_hot water temp/region hot_region\n";
let tree = parse(source);
let root_node = tree.root_node();
dbg!(root_node.to_sexp());
let compute_node = dbg!(root_node.child(0)).unwrap();
dbg!(compute_node.to_sexp());
assert_eq!(
ComputeDef::from_node(&compute_node, source).unwrap(),
ComputeDef {
compute_id: ast::Ident {
name: "T_hot".into(),
ident_type: ast::IdentType::Compute,
span: ((0, 8), (0, 13)).into()
},
group_id: Word {
contents: "water".into(),
span: ((0, 14), (0, 19)).into()
},
compute_style: ComputeStyle::TempRegion,
args: vec![ast::Argument::new(
ast::ArgumentKind::Word("hot_region".into()),
((0, 32), (0, 42))
),],
span: ((0, 0), (0, 42)).into()
}
);
}
#[test]
fn parse_incomplete_compute_def() {
let source = "compute a ";
let tree = parse(source);
let root_node = tree.root_node();
dbg!(root_node.to_sexp());
assert!(!root_node.is_missing());
let ast = ast::ts_to_ast(&tree, source);
assert!(ast.is_err());
let compute_node = root_node.child(0).expect("Should find child node.");
let parsed = ComputeDef::from_node(&compute_node, source);
use crate::ast::from_node::FromNodeError;
assert_eq!(
parsed,
Err(FromNodeError::PartialNode("missing group ID".to_string()))
);
}
}