#![cfg_attr(coverage_nightly, coverage(off))]
use super::execution_recorder::ExecutionRecorder;
use super::types::*;
use super::variable_inspector::VariableInspector;
use crate::cli::language_analyzer::Language;
use serde_json::{json, Value};
use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use tree_sitter::Tree;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ServerState {
Uninitialized,
Initialized,
Running,
Stopped,
}
pub struct DapServer {
state: Arc<Mutex<ServerState>>,
response_seq: Arc<Mutex<i64>>,
capabilities: DapCapabilities,
program: Arc<Mutex<Option<String>>>,
breakpoints: Arc<Mutex<HashMap<String, HashSet<i64>>>>,
current_language: Arc<Mutex<Option<Language>>>,
ast_cache: Arc<Mutex<HashMap<PathBuf, Tree>>>,
variable_inspector: VariableInspector,
current_stopped_file: Arc<Mutex<Option<String>>>,
current_stopped_line: Arc<Mutex<Option<usize>>>,
recording_dir: Option<PathBuf>,
recording_path: Arc<Mutex<Option<PathBuf>>>,
execution_recorder: Arc<Mutex<Option<ExecutionRecorder<File>>>>,
}
impl DapServer {
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn new() -> Self {
Self::with_recording(None)
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "path_exists")]
pub fn with_recording(recording_dir: Option<PathBuf>) -> Self {
Self {
state: Arc::new(Mutex::new(ServerState::Uninitialized)),
response_seq: Arc::new(Mutex::new(0)),
capabilities: Self::default_capabilities(),
program: Arc::new(Mutex::new(None)),
breakpoints: Arc::new(Mutex::new(HashMap::new())),
current_language: Arc::new(Mutex::new(None)),
ast_cache: Arc::new(Mutex::new(HashMap::new())),
variable_inspector: VariableInspector::new(),
current_stopped_file: Arc::new(Mutex::new(None)),
current_stopped_line: Arc::new(Mutex::new(None)),
recording_dir,
recording_path: Arc::new(Mutex::new(None)),
execution_recorder: Arc::new(Mutex::new(None)),
}
}
fn default_capabilities() -> DapCapabilities {
DapCapabilities {
supports_configuration_done_request: true,
supports_function_breakpoints: false,
supports_conditional_breakpoints: true,
supports_hit_conditional_breakpoints: false,
supports_evaluate_for_hovers: false,
supports_step_back: false,
supports_set_variable: false,
supports_restart_frame: false,
supports_goto_targets_request: false,
supports_step_in_targets_request: false,
supports_completions_request: false,
supports_modules_request: false,
supports_restart_request: false,
supports_exception_options: false,
supports_value_formatting_options: false,
supports_exception_info_request: false,
supports_terminate_debuggee: true,
supports_delayed_stack_trace_loading: false,
supports_loaded_sources_request: false,
supports_log_points: false,
supports_terminate_threads_request: false,
supports_set_expression: false,
supports_terminate_request: true,
supports_data_breakpoints: false,
supports_read_memory_request: false,
supports_write_memory_request: false,
supports_disassemble_request: false,
supports_cancel_request: false,
supports_breakpoint_locations_request: false,
supports_clipboard_context: false,
supports_stepping_granularity: false,
supports_instruction_breakpoints: false,
supports_exception_filter_options: false,
}
}
fn next_seq(&self) -> i64 {
let mut seq = self
.response_seq
.lock()
.expect("Mutex should not be poisoned");
*seq += 1;
*seq
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn is_initialized(&self) -> bool {
let state = self.state.lock().expect("Mutex should not be poisoned");
*state != ServerState::Uninitialized
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn is_running(&self) -> bool {
let state = self.state.lock().expect("Mutex should not be poisoned");
*state == ServerState::Running
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn has_program_loaded(&self) -> bool {
let program = self.program.lock().expect("Mutex should not be poisoned");
program.is_some()
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn current_program(&self) -> Option<String> {
let program = self.program.lock().expect("Mutex should not be poisoned");
program.clone()
}
}
include!("server_request_handlers.rs");
include!("server_pmat_integration.rs");
include!("server_recording.rs");
impl Default for DapServer {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
#[path = "server_tests.rs"]
mod tests;