tcss_core/
context.rs

1//! Execution context for TCSS
2//!
3//! This module manages the execution environment including:
4//! - Variable storage and lookup
5//! - Function definitions
6//! - Scope management (nested scopes)
7
8use crate::ast::Statement;
9use std::collections::HashMap;
10
11/// A value that can be stored in the execution context
12#[derive(Debug, Clone, PartialEq)]
13pub enum Value {
14    /// Number value
15    Number(f64),
16    
17    /// String value
18    String(String),
19    
20    /// Number with unit (e.g., 16px, 2em)
21    Unit { value: f64, unit: String },
22    
23    /// Color value (hex format)
24    Color(String),
25    
26    /// Boolean value
27    Boolean(bool),
28    
29    /// Array of values
30    Array(Vec<Value>),
31    
32    /// Object/Map of key-value pairs
33    Object(HashMap<String, Value>),
34    
35    /// Null/undefined value
36    Null,
37}
38
39impl Value {
40    /// Convert value to a CSS string representation
41    pub fn to_css_string(&self) -> String {
42        match self {
43            Value::Number(n) => {
44                // Format number, removing unnecessary decimals
45                if n.fract() == 0.0 {
46                    format!("{}", *n as i64)
47                } else {
48                    format!("{}", n)
49                }
50            }
51            Value::String(s) => s.clone(),
52            Value::Unit { value, unit } => {
53                if value.fract() == 0.0 {
54                    format!("{}{}", *value as i64, unit)
55                } else {
56                    format!("{}{}", value, unit)
57                }
58            }
59            Value::Color(c) => c.clone(),
60            Value::Boolean(b) => b.to_string(),
61            Value::Array(arr) => {
62                let items: Vec<String> = arr.iter().map(|v| v.to_css_string()).collect();
63                items.join(", ")
64            }
65            Value::Object(_) => "[object]".to_string(),
66            Value::Null => "null".to_string(),
67        }
68    }
69
70    /// Check if value is truthy
71    pub fn is_truthy(&self) -> bool {
72        match self {
73            Value::Boolean(b) => *b,
74            Value::Null => false,
75            Value::Number(n) => *n != 0.0,
76            Value::String(s) => !s.is_empty(),
77            _ => true,
78        }
79    }
80}
81
82/// Function definition stored in context
83#[derive(Debug, Clone)]
84pub struct FunctionDef {
85    pub params: Vec<String>,
86    pub body: Vec<Statement>,
87}
88
89/// Execution context with scope management
90#[derive(Debug, Clone)]
91pub struct Context {
92    /// Stack of scopes (each scope is a HashMap of variables)
93    scopes: Vec<HashMap<String, Value>>,
94    
95    /// Function definitions (global)
96    functions: HashMap<String, FunctionDef>,
97}
98
99impl Context {
100    /// Create a new execution context
101    pub fn new() -> Self {
102        Self {
103            scopes: vec![HashMap::new()], // Start with global scope
104            functions: HashMap::new(),
105        }
106    }
107
108    /// Push a new scope onto the stack
109    pub fn push_scope(&mut self) {
110        self.scopes.push(HashMap::new());
111    }
112
113    /// Pop the current scope from the stack
114    pub fn pop_scope(&mut self) {
115        if self.scopes.len() > 1 {
116            self.scopes.pop();
117        }
118    }
119
120    /// Set a variable in the current scope
121    pub fn set_variable(&mut self, name: String, value: Value) {
122        if let Some(scope) = self.scopes.last_mut() {
123            scope.insert(name, value);
124        }
125    }
126
127    /// Get a variable value (searches from current scope up to global)
128    pub fn get_variable(&self, name: &str) -> Option<Value> {
129        // Search from innermost scope to outermost
130        for scope in self.scopes.iter().rev() {
131            if let Some(value) = scope.get(name) {
132                return Some(value.clone());
133            }
134        }
135        None
136    }
137
138    /// Define a function
139    pub fn define_function(&mut self, name: String, params: Vec<String>, body: Vec<Statement>) {
140        self.functions.insert(name, FunctionDef { params, body });
141    }
142
143    /// Get a function definition
144    pub fn get_function(&self, name: &str) -> Option<&FunctionDef> {
145        self.functions.get(name)
146    }
147
148    /// Check if a variable exists
149    pub fn has_variable(&self, name: &str) -> bool {
150        self.scopes.iter().rev().any(|scope| scope.contains_key(name))
151    }
152
153    /// Check if a function exists
154    pub fn has_function(&self, name: &str) -> bool {
155        self.functions.contains_key(name)
156    }
157}
158
159impl Default for Context {
160    fn default() -> Self {
161        Self::new()
162    }
163}
164