use std::cell::RefCell;
use crate::{prelude::*, selection::ast::{Evaluate, SelectionParserError}};
#[derive(Debug)]
pub struct SelectionExpr {
ast: RefCell<super::ast::LogicalNode>,
sel_str: String,
}
impl SelectionExpr {
pub fn get_str(&self) -> &str {
&self.sel_str
}
}
impl SelectionExpr {
pub fn new(s: impl AsRef<str>) -> Result<Self, SelectionParserError> {
let s = s.as_ref().trim();
Ok(Self {
ast: RefCell::new(
super::grammar::selection_parser::logical_expr(s).map_err(|e| {
let err_str = format!(
"\n{s}\n{}^\nExpected {}",
"-".repeat(e.location.column - 1),
e.expected
);
SelectionParserError::SyntaxError(err_str)
})?,
),
sel_str: s.to_owned(),
})
}
pub(super) fn apply_whole (
&self,
sys: &(impl AtomPosAnalysis + BoxProvider)
) -> Result<SVec, SelectionParserError> {
let data = super::ast::EvalContext::new(sys, None)?;
let mut ast = self.ast.borrow_mut();
let ind = ast.apply(&data)?.into_owned();
Ok(SVec::from_unsorted(ind))
}
pub(super) fn apply_subset (
&self,
sys: &(impl AtomPosAnalysis + BoxProvider),
subset: &[usize],
) -> Result<SVec, SelectionParserError> {
let data = super::ast::EvalContext::new(sys, Some(subset))?;
let mut ast = self.ast.borrow_mut();
let ind = ast.apply(&data)?.into_owned();
Ok(SVec::from_unsorted(ind))
}
}
#[cfg(test)]
mod tests {
use super::SelectionExpr;
use crate::System;
use std::sync::LazyLock;
static SYS: LazyLock<System> = LazyLock::new(|| {
System::from_file("tests/albumin.pdb").unwrap()
});
#[test]
fn within_syntax_test() {
let _ast = SelectionExpr::new("within 0.5 pbc yyy of resid 555").unwrap();
}
fn get_selection_index(sel_str: &str) -> Vec<usize> {
let ast = SelectionExpr::new(sel_str).expect("Error generating AST");
ast.apply_whole(&*SYS)
.expect("Error applying AST")
.to_vec()
}
fn get_selection_index2(sel_str: &str) -> Vec<usize> {
let ast = SelectionExpr::new(sel_str).expect("Error generating AST");
ast.apply_whole(&*SYS)
.expect("Error applying AST")
.to_vec()
}
#[test]
#[should_panic]
fn test_invalid_syntax() {
let _ast = SelectionExpr::new("resname A B C D and resid a:6").unwrap();
}
#[test]
fn test_sqrt() {
let ast = SelectionExpr::new("within 0.3 of x>2+2*3").expect("Error generating AST");
let _vec1 = ast
.apply_whole(&*SYS)
.expect("Error applying AST");
let ast = SelectionExpr::new("x<25").expect("Error generating AST");
let _vec2 = ast
.apply_whole(&*SYS)
.expect("Error applying AST");
}
#[test]
fn test_dist_syntax() {
let _ast =
SelectionExpr::new("dist point 1.9 2.9 3.8 > 0.4").expect("Error generating AST");
}
#[test]
fn test_leading_space() {
let _ast =
SelectionExpr::new(" dist point 1.9 2.9 3.8 > 0.4").expect("Error generating AST");
}
#[test]
fn test_trainling_space() {
let _ast =
SelectionExpr::new("dist point 1.9 2.9 3.8 > 0.4 ").expect("Error generating AST");
}
#[test]
fn within_from_point() {
let _ast = SelectionExpr::new("within 0.5 of com pbc 101 of protein")
.expect("Error generating AST");
}
#[test]
fn test_x_of() {
let _ast = SelectionExpr::new("x < x of com of name CA")
.expect("Error generating AST");
}
#[test]
fn test_nth_pos_of() {
let _ast = SelectionExpr::new("x < x of pos 3 of name CA")
.expect("Error generating AST");
}
#[test]
fn debug_print() {
let ast = SelectionExpr::new("within 0.5 of com pbc 101 of protein")
.expect("Error generating AST");
println!("{:?}", ast);
}
include!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/tests/generated_vmd_tests.in"
));
include!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/tests/generated_pteros_tests.in"
));
}