use std::fmt;
use std::time::Duration;
use chrono::{DateTime, Utc};
use rustc_hash::FxHashMap;
use crate::Builtins::Core::DixValue;
use crate::Compiler::AST::{Expression, QuickFunction};
pub struct ValueResolutionResult {
pub is_success: bool,
pub original_ast: Option<crate::Compiler::AST::DixScript>,
pub resolved_ast: Option<crate::Compiler::AST::DixScript>,
pub function_calls_resolved: usize,
pub errors: Vec<String>,
pub log_statements: Vec<String>,
pub resolution_duration: Duration,
pub resolution_history: Vec<ResolutionRecord>,
}
impl ValueResolutionResult {
pub fn new() -> Self {
ValueResolutionResult {
is_success: false,
original_ast: None,
resolved_ast: None,
function_calls_resolved: 0,
errors: Vec::new(),
log_statements: Vec::new(),
resolution_duration: Duration::ZERO,
resolution_history: Vec::new(),
}
}
}
impl Default for ValueResolutionResult {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct FunctionCallInfo {
pub function_name: String,
pub namespace_name: Option<String>,
pub arguments: Vec<Expression>,
pub location: String,
pub scope: String,
pub entry_path: String,
pub position: crate::Compiler::AST::Position,
pub scope_context: FxHashMap<String, String>,
}
impl FunctionCallInfo {
pub fn fully_qualified_name(&self) -> String {
match &self.namespace_name {
Some(ns) if !ns.is_empty() => format!("{}.{}", ns, self.function_name),
_ => self.function_name.clone(),
}
}
}
impl fmt::Display for FunctionCallInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}() at {} [entry: {}, pos: {}]",
self.fully_qualified_name(),
self.location,
self.entry_path,
self.position
)
}
}
#[derive(Debug, Clone)]
pub struct ResolutionRecord {
pub function_name: String,
pub namespace_name: Option<String>,
pub location: String,
pub scope: String,
pub arguments: Vec<String>,
pub result: Option<DixValue>,
pub success: bool,
pub error_message: String,
pub timestamp: DateTime<Utc>,
}
impl ResolutionRecord {
pub fn display_name(&self) -> String {
match &self.namespace_name {
Some(ns) if !ns.is_empty() => format!("{}.{}", ns, self.function_name),
_ => self.function_name.clone(),
}
}
}
impl fmt::Display for ResolutionRecord {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let status = if self.success { "OK" } else { "FAIL" };
write!(f, "[{}] {} at {}", status, self.display_name(), self.location)?;
if !self.success && !self.error_message.is_empty() {
write!(f, " — {}", self.error_message)?;
}
Ok(())
}
}
pub struct ScopeTracker {
path_segments: Vec<String>,
current_scope_variables: FxHashMap<String, String>,
}
impl ScopeTracker {
pub fn new() -> Self {
let mut path_segments = Vec::with_capacity(8);
path_segments.push("DATA".to_string());
ScopeTracker {
path_segments,
current_scope_variables: FxHashMap::default(),
}
}
pub fn enter_scope(&mut self, segment: &str) {
self.path_segments.push(segment.to_string());
}
pub fn exit_scope(&mut self) {
if self.path_segments.len() > 1 {
self.path_segments.pop();
}
}
pub fn reset_to_root(&mut self) {
self.path_segments.clear();
self.path_segments.push("DATA".to_string());
self.current_scope_variables.clear();
}
pub fn get_current_path(&self) -> String {
let segments: Vec<&str> = self
.path_segments
.iter()
.skip(1)
.map(|s| s.as_str())
.collect();
crate::Compiler::Utilities::PathBuilder::build(&segments)
}
pub fn get_current_scope(&self) -> String {
let len = self.path_segments.len();
if len <= 2 {
return "DATA".to_string();
}
let segments: Vec<&str> = self
.path_segments
.iter()
.skip(1)
.take(len - 2)
.map(|s| s.as_str())
.collect();
crate::Compiler::Utilities::PathBuilder::build(&segments)
}
pub fn register_variable(&mut self, name: &str, full_path: &str) {
self.current_scope_variables
.insert(name.to_string(), full_path.to_string());
}
pub fn clear_scope_variables(&mut self) {
self.current_scope_variables.clear();
}
pub fn get_scope_variables_snapshot(&self) -> FxHashMap<String, String> {
self.current_scope_variables.clone()
}
}
impl Default for ScopeTracker {
fn default() -> Self {
Self::new()
}
}
pub struct FunctionRegistry {
functions: FxHashMap<String, QuickFunction>,
}
impl FunctionRegistry {
pub fn new() -> Self {
FunctionRegistry {
functions: FxHashMap::default(),
}
}
pub fn register(&mut self, function: QuickFunction) -> Result<(), FunctionExecutionError> {
let name = function.name.clone();
if self.functions.contains_key(&name) {
return Err(FunctionExecutionError::new(format!(
"Function '{}' already registered",
name
)));
}
self.functions.insert(name, function);
Ok(())
}
pub fn get(&self, name: &str) -> Option<&QuickFunction> {
self.functions.get(name)
}
pub fn contains(&self, name: &str) -> bool {
self.functions.contains_key(name)
}
pub fn count(&self) -> usize {
self.functions.len()
}
pub fn function_names(&self) -> impl Iterator<Item = &String> {
self.functions.keys()
}
}
impl Default for FunctionRegistry {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub enum ExecutionError {
InvalidVariableName(String),
VariableAlreadyDefined(String),
UndefinedVariable {
name: String,
function_name: String,
},
CannotExitRootScope,
}
impl fmt::Display for ExecutionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ExecutionError::InvalidVariableName(msg) => {
write!(f, "Invalid variable name: {}", msg)
}
ExecutionError::VariableAlreadyDefined(name) => {
write!(f, "Variable '{}' already defined in current scope", name)
}
ExecutionError::UndefinedVariable { name, function_name } => {
write!(f, "Undefined variable '{}' in function '{}'", name, function_name)
}
ExecutionError::CannotExitRootScope => write!(f, "Cannot exit root scope"),
}
}
}
impl std::error::Error for ExecutionError {}
#[derive(Debug, Clone)]
pub struct FunctionExecutionError {
pub message: String,
pub inner: Option<Box<FunctionExecutionError>>,
}
impl FunctionExecutionError {
pub fn new(message: impl Into<String>) -> Self {
FunctionExecutionError {
message: message.into(),
inner: None,
}
}
pub fn with_inner(message: impl Into<String>, inner: FunctionExecutionError) -> Self {
FunctionExecutionError {
message: message.into(),
inner: Some(Box::new(inner)),
}
}
}
impl fmt::Display for FunctionExecutionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.message)?;
if let Some(ref inner) = self.inner {
write!(f, " | caused by: {}", inner)?;
}
Ok(())
}
}
impl std::error::Error for FunctionExecutionError {}
impl From<ExecutionError> for FunctionExecutionError {
fn from(err: ExecutionError) -> Self {
FunctionExecutionError::new(err.to_string())
}
}