impl DapServer {
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn current_language(&self) -> Option<Language> {
let lang = self
.current_language
.lock()
.expect("Mutex should not be poisoned");
*lang
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn has_ast_for(&self, path: &str) -> bool {
let cache = self.ast_cache.lock().expect("Mutex should not be poisoned");
cache.contains_key(Path::new(path))
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn get_variables_at_line(&self, path: &str, line: usize) -> Result<Vec<Variable>, String> {
let source = std::fs::read_to_string(path)
.map_err(|e| format!("Failed to read file {}: {}", path, e))?;
let language = self
.detect_language_from_path(Path::new(path))
.ok_or_else(|| format!("Could not detect language for {}", path))?;
match language {
Language::Rust => self.variable_inspector.inspect_rust(&source, line),
Language::TypeScript | Language::JavaScript => {
self.variable_inspector.inspect_typescript(&source, line)
}
Language::Python => self.variable_inspector.inspect_python(&source, line),
_ => Err(format!(
"Language {:?} not supported for variable inspection",
language
)),
}
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn simulate_stop_at_line(&mut self, path: &str, line: usize) {
let mut stopped_file = self
.current_stopped_file
.lock()
.expect("Mutex should not be poisoned");
*stopped_file = Some(path.to_string());
drop(stopped_file);
let mut stopped_line = self
.current_stopped_line
.lock()
.expect("Mutex should not be poisoned");
*stopped_line = Some(line);
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn current_stopped_file(&self) -> Option<String> {
self.current_stopped_file
.lock()
.expect("Mutex should not be poisoned")
.clone()
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn current_stopped_line(&self) -> Option<usize> {
*self
.current_stopped_line
.lock()
.expect("Mutex should not be poisoned")
}
fn detect_language_from_path(&self, path: &Path) -> Option<Language> {
let extension = path.extension()?.to_str()?;
match extension {
"rs" => Some(Language::Rust),
"py" => Some(Language::Python),
"ts" | "tsx" => Some(Language::TypeScript),
"js" | "jsx" => Some(Language::JavaScript),
_ => None,
}
}
fn parse_and_cache_ast(&self, path: &Path) -> Result<(), String> {
let source =
std::fs::read_to_string(path).map_err(|e| format!("Failed to read file: {}", e))?;
let language = self
.detect_language_from_path(path)
.ok_or_else(|| format!("Could not detect language for {:?}", path))?;
let tree = match language {
Language::Rust => {
let mut parser = tree_sitter::Parser::new();
parser
.set_language(&tree_sitter_rust::LANGUAGE.into())
.map_err(|e| format!("Failed to set Rust language: {}", e))?;
parser
.parse(&source, None)
.ok_or_else(|| "Failed to parse Rust source".to_string())?
}
Language::Python => {
#[cfg(feature = "python-ast")]
{
let mut parser = tree_sitter::Parser::new();
parser
.set_language(&tree_sitter_python::LANGUAGE.into())
.map_err(|e| format!("Failed to set Python language: {}", e))?;
parser
.parse(&source, None)
.ok_or_else(|| "Failed to parse Python source".to_string())?
}
#[cfg(not(feature = "python-ast"))]
{
return Err("python-ast feature is disabled".to_string());
}
}
Language::TypeScript | Language::JavaScript => {
let mut parser = tree_sitter::Parser::new();
parser
.set_language(&tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into())
.map_err(|e| format!("Failed to set TypeScript language: {}", e))?;
parser
.parse(&source, None)
.ok_or_else(|| "Failed to parse TypeScript source".to_string())?
}
_ => return Err(format!("Language {:?} not supported for parsing", language)),
};
let mut cache = self.ast_cache.lock().expect("Mutex should not be poisoned");
cache.insert(path.to_path_buf(), tree);
Ok(())
}
}