1use crate::ast::Statement;
9use std::collections::HashMap;
10
11#[derive(Debug, Clone, PartialEq)]
13pub enum Value {
14 Number(f64),
16
17 String(String),
19
20 Unit { value: f64, unit: String },
22
23 Color(String),
25
26 Boolean(bool),
28
29 Array(Vec<Value>),
31
32 Object(HashMap<String, Value>),
34
35 Null,
37}
38
39impl Value {
40 pub fn to_css_string(&self) -> String {
42 match self {
43 Value::Number(n) => {
44 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 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#[derive(Debug, Clone)]
84pub struct FunctionDef {
85 pub params: Vec<String>,
86 pub body: Vec<Statement>,
87}
88
89#[derive(Debug, Clone)]
91pub struct Context {
92 scopes: Vec<HashMap<String, Value>>,
94
95 functions: HashMap<String, FunctionDef>,
97}
98
99impl Context {
100 pub fn new() -> Self {
102 Self {
103 scopes: vec![HashMap::new()], functions: HashMap::new(),
105 }
106 }
107
108 pub fn push_scope(&mut self) {
110 self.scopes.push(HashMap::new());
111 }
112
113 pub fn pop_scope(&mut self) {
115 if self.scopes.len() > 1 {
116 self.scopes.pop();
117 }
118 }
119
120 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 pub fn get_variable(&self, name: &str) -> Option<Value> {
129 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 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 pub fn get_function(&self, name: &str) -> Option<&FunctionDef> {
145 self.functions.get(name)
146 }
147
148 pub fn has_variable(&self, name: &str) -> bool {
150 self.scopes.iter().rev().any(|scope| scope.contains_key(name))
151 }
152
153 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