oxur_repl/
server.rs

1//! REPL Server
2//!
3//! Implements three-tier execution strategy:
4//! - Tier 1: Interpreter for simple expressions (<1ms)
5//! - Tier 2: Cache of compiled functions (~0ms)
6//! - Tier 3: JIT compilation for complex code (50-200ms first time)
7
8use crate::{protocol::*, Result};
9use oxur_lang::{Expander, Parser};
10use std::collections::HashMap;
11
12/// Execution tier for performance tracking
13#[derive(Debug, Clone, Copy)]
14enum ExecutionTier {
15    Interpreter,
16    Cached,
17    Jit,
18}
19
20/// REPL server with tiered execution
21pub struct ReplServer {
22    #[allow(dead_code)]
23    parser: Parser,
24    #[allow(dead_code)]
25    expander: Expander,
26    cache: HashMap<String, String>,
27    stats: TierStats,
28}
29
30#[derive(Debug, Default)]
31struct TierStats {
32    tier1_count: usize,
33    tier2_count: usize,
34    tier3_count: usize,
35}
36
37impl ReplServer {
38    pub fn new() -> Self {
39        Self {
40            parser: Parser::new(String::new()),
41            expander: Expander::new(),
42            cache: HashMap::new(),
43            stats: TierStats::default(),
44        }
45    }
46
47    /// Handle a REPL request
48    pub fn handle(&mut self, request: ReplRequest) -> Result<ReplResponse> {
49        match request {
50            ReplRequest::Eval { source } => self.eval(&source),
51            ReplRequest::Load { path } => self.load(&path),
52            ReplRequest::Reset => {
53                self.reset();
54                Ok(ReplResponse::Ok)
55            }
56            ReplRequest::Status => Ok(ReplResponse::Status {
57                tier1_count: self.stats.tier1_count,
58                tier2_count: self.stats.tier2_count,
59                tier3_count: self.stats.tier3_count,
60            }),
61            ReplRequest::Shutdown => Ok(ReplResponse::Ok),
62        }
63    }
64
65    fn eval(&mut self, source: &str) -> Result<ReplResponse> {
66        // Determine execution tier
67        let tier = self.choose_tier(source);
68
69        match tier {
70            ExecutionTier::Interpreter => {
71                self.stats.tier1_count += 1;
72                self.eval_interpret(source)
73            }
74            ExecutionTier::Cached => {
75                self.stats.tier2_count += 1;
76                self.eval_cached(source)
77            }
78            ExecutionTier::Jit => {
79                self.stats.tier3_count += 1;
80                self.eval_jit(source)
81            }
82        }
83    }
84
85    fn choose_tier(&self, source: &str) -> ExecutionTier {
86        // Simple heuristic - would be more sophisticated in practice
87        if source.len() < 50 {
88            ExecutionTier::Interpreter
89        } else if self.cache.contains_key(source) {
90            ExecutionTier::Cached
91        } else {
92            ExecutionTier::Jit
93        }
94    }
95
96    fn eval_interpret(&mut self, source: &str) -> Result<ReplResponse> {
97        // Placeholder: direct interpretation
98        Ok(ReplResponse::Value { value: format!("interpreted: {}", source) })
99    }
100
101    fn eval_cached(&self, source: &str) -> Result<ReplResponse> {
102        // Placeholder: cached function call
103        if let Some(result) = self.cache.get(source) {
104            Ok(ReplResponse::Value { value: result.clone() })
105        } else {
106            Ok(ReplResponse::Error { message: "Cache miss".to_string() })
107        }
108    }
109
110    fn eval_jit(&mut self, source: &str) -> Result<ReplResponse> {
111        // Placeholder: compile and execute
112        let result = format!("jit-compiled: {}", source);
113        self.cache.insert(source.to_string(), result.clone());
114        Ok(ReplResponse::Value { value: result })
115    }
116
117    fn load(&mut self, _path: &str) -> Result<ReplResponse> {
118        // Placeholder implementation
119        Ok(ReplResponse::Ok)
120    }
121
122    fn reset(&mut self) {
123        self.cache.clear();
124        self.stats = TierStats::default();
125    }
126}
127
128impl Default for ReplServer {
129    fn default() -> Self {
130        Self::new()
131    }
132}
133
134#[cfg(test)]
135mod tests {
136    use super::*;
137
138    #[test]
139    fn test_server_creation() {
140        let server = ReplServer::new();
141        assert_eq!(server.stats.tier1_count, 0);
142    }
143
144    #[test]
145    fn test_server_default() {
146        let server = ReplServer::default();
147        assert_eq!(server.stats.tier1_count, 0);
148    }
149
150    #[test]
151    fn test_tier_selection() {
152        let server = ReplServer::new();
153
154        // Short expression → Tier 1
155        let tier = server.choose_tier("(+ 1 2)");
156        assert!(matches!(tier, ExecutionTier::Interpreter));
157
158        // Long expression → Tier 3
159        let tier = server.choose_tier(&"x".repeat(100));
160        assert!(matches!(tier, ExecutionTier::Jit));
161    }
162
163    #[test]
164    fn test_tier_selection_boundary() {
165        let server = ReplServer::new();
166        // Exactly 49 chars -> Tier 1
167        let tier = server.choose_tier(&"x".repeat(49));
168        assert!(matches!(tier, ExecutionTier::Interpreter));
169        // Exactly 50 chars -> Tier 3
170        let tier = server.choose_tier(&"x".repeat(50));
171        assert!(matches!(tier, ExecutionTier::Jit));
172    }
173
174    #[test]
175    fn test_handle_eval() {
176        let mut server = ReplServer::new();
177        let req = ReplRequest::Eval { source: "test".to_string() };
178        let resp = server.handle(req);
179        assert!(resp.is_ok());
180    }
181
182    #[test]
183    fn test_handle_load() {
184        let mut server = ReplServer::new();
185        let req = ReplRequest::Load { path: "test.ox".to_string() };
186        let resp = server.handle(req);
187        assert!(resp.is_ok());
188    }
189
190    #[test]
191    fn test_handle_reset() {
192        let mut server = ReplServer::new();
193        server.stats.tier1_count = 10;
194        let req = ReplRequest::Reset;
195        let resp = server.handle(req);
196        assert!(resp.is_ok());
197        match resp.unwrap() {
198            ReplResponse::Ok => (),
199            _ => panic!("Expected Ok response"),
200        }
201    }
202
203    #[test]
204    fn test_handle_status() {
205        let mut server = ReplServer::new();
206        server.stats.tier1_count = 1;
207        server.stats.tier2_count = 2;
208        server.stats.tier3_count = 3;
209        let req = ReplRequest::Status;
210        let resp = server.handle(req);
211        assert!(resp.is_ok());
212        match resp.unwrap() {
213            ReplResponse::Status { tier1_count, tier2_count, tier3_count } => {
214                assert_eq!(tier1_count, 1);
215                assert_eq!(tier2_count, 2);
216                assert_eq!(tier3_count, 3);
217            }
218            _ => panic!("Expected Status response"),
219        }
220    }
221
222    #[test]
223    fn test_handle_shutdown() {
224        let mut server = ReplServer::new();
225        let req = ReplRequest::Shutdown;
226        let resp = server.handle(req);
227        assert!(resp.is_ok());
228        match resp.unwrap() {
229            ReplResponse::Ok => (),
230            _ => panic!("Expected Ok response"),
231        }
232    }
233
234    #[test]
235    fn test_tier_stats() {
236        let stats = TierStats { tier1_count: 5, tier2_count: 10, tier3_count: 15 };
237        assert_eq!(stats.tier1_count, 5);
238        assert_eq!(stats.tier2_count, 10);
239        assert_eq!(stats.tier3_count, 15);
240    }
241
242    #[test]
243    fn test_tier_stats_default() {
244        let stats = TierStats::default();
245        assert_eq!(stats.tier1_count, 0);
246        assert_eq!(stats.tier2_count, 0);
247        assert_eq!(stats.tier3_count, 0);
248    }
249
250    #[test]
251    fn test_eval_short_source() {
252        let mut server = ReplServer::new();
253        let req = ReplRequest::Eval { source: "short".to_string() };
254        let resp = server.handle(req);
255        assert!(resp.is_ok());
256        assert_eq!(server.stats.tier1_count, 1);
257    }
258
259    #[test]
260    fn test_eval_long_source() {
261        let mut server = ReplServer::new();
262        let req = ReplRequest::Eval { source: "x".repeat(100) };
263        let resp = server.handle(req);
264        assert!(resp.is_ok());
265        assert_eq!(server.stats.tier3_count, 1);
266    }
267
268    #[test]
269    fn test_reset_clears_cache() {
270        let mut server = ReplServer::new();
271        // Add something to cache via JIT
272        let req = ReplRequest::Eval { source: "x".repeat(100) };
273        server.handle(req).unwrap();
274        assert!(server.cache.len() > 0);
275
276        // Reset should clear it
277        server.handle(ReplRequest::Reset).unwrap();
278        assert_eq!(server.cache.len(), 0);
279    }
280
281    #[test]
282    fn test_reset_clears_stats() {
283        let mut server = ReplServer::new();
284        server.stats.tier1_count = 10;
285        server.stats.tier2_count = 20;
286        server.stats.tier3_count = 30;
287
288        server.handle(ReplRequest::Reset).unwrap();
289        assert_eq!(server.stats.tier1_count, 0);
290        assert_eq!(server.stats.tier2_count, 0);
291        assert_eq!(server.stats.tier3_count, 0);
292    }
293}