1use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8use std::time::Duration;
9
10#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12pub struct ParserConfig {
13 pub backend: ParserBackend,
15
16 pub timeout: Duration,
18
19 pub max_expression_depth: u32,
21
22 pub max_collection_size: u32,
24
25 pub max_string_length: u32,
27
28 pub max_parameters: u32,
30
31 pub strict_validation: bool,
33
34 pub allow_experimental: bool,
36
37 pub backend_options: HashMap<String, serde_json::Value>,
39
40 pub features: Vec<ParserFeature>,
42
43 pub memory_limits: MemoryLimits,
45
46 pub performance: PerformanceSettings,
48
49 pub error_handling: ErrorHandlingSettings,
51
52 pub memory_settings: MemorySettings,
54
55 pub security_settings: SecuritySettings,
57}
58
59#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
61pub enum ParserBackend {
62 Nom,
64
65 Antlr,
67
68 Auto,
70
71 Custom(String),
73}
74
75#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
77pub enum ParserFeature {
78 Streaming,
80
81 ErrorRecovery,
83
84 SyntaxHighlighting,
86
87 CodeCompletion,
89
90 AstTransformation,
92
93 CustomOperators,
95
96 Parallel,
98
99 Caching,
101
102 OnlineValidation,
104
105 Profiling,
107}
108
109#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
111pub struct MemoryLimits {
112 pub max_ast_size: u64,
114
115 pub max_temp_memory: u64,
117
118 pub max_stack_depth: u32,
120
121 pub max_cache_entries: u32,
123}
124
125#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
127pub struct PerformanceSettings {
128 pub worker_threads: u32,
130
131 pub stream_buffer_size: u32,
133
134 pub enable_caching: bool,
136
137 pub cache_ttl: Duration,
139
140 pub enable_jit: bool,
142
143 pub optimization_level: u8,
145}
146
147#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
149pub struct ErrorHandlingSettings {
150 pub max_errors: u32,
152
153 pub continue_on_error: bool,
155
156 pub error_context_lines: u32,
158
159 pub include_suggestions: bool,
161
162 pub collect_error_stats: bool,
164}
165
166#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
168pub struct MemorySettings {
169 pub max_parser_memory: u64,
171
172 pub allocation_strategy: MemoryAllocationStrategy,
174
175 pub enable_memory_pooling: bool,
177
178 pub memory_pool_size: usize,
180}
181
182#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
184pub enum MemoryAllocationStrategy {
185 Standard,
187 Pooled,
189 Arena,
191}
192
193#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
195pub struct SecuritySettings {
196 pub max_query_depth: u32,
198
199 pub max_token_count: u32,
201
202 pub enable_input_sanitization: bool,
204
205 pub restrict_dangerous_operations: bool,
207
208 pub blocked_keywords: Vec<String>,
210}
211
212impl Default for ParserConfig {
213 fn default() -> Self {
214 Self {
215 backend: ParserBackend::Auto,
216 timeout: Duration::from_secs(30),
217 max_expression_depth: 100,
218 max_collection_size: 10_000,
219 max_string_length: 1_000_000,
220 max_parameters: 1000,
221 strict_validation: true,
222 allow_experimental: false,
223 backend_options: HashMap::new(),
224 features: vec![
225 ParserFeature::ErrorRecovery,
226 ParserFeature::OnlineValidation,
227 ],
228 memory_limits: MemoryLimits::default(),
229 performance: PerformanceSettings::default(),
230 error_handling: ErrorHandlingSettings::default(),
231 memory_settings: MemorySettings::default(),
232 security_settings: SecuritySettings::default(),
233 }
234 }
235}
236
237impl Default for MemoryLimits {
238 fn default() -> Self {
239 Self {
240 max_ast_size: 100 * 1024 * 1024, max_temp_memory: 50 * 1024 * 1024, max_stack_depth: 1000,
243 max_cache_entries: 10_000,
244 }
245 }
246}
247
248impl Default for PerformanceSettings {
249 fn default() -> Self {
250 Self {
251 worker_threads: num_cpus::get() as u32,
252 stream_buffer_size: 64 * 1024, enable_caching: true,
254 cache_ttl: Duration::from_secs(300), enable_jit: false,
256 optimization_level: 2,
257 }
258 }
259}
260
261impl Default for ErrorHandlingSettings {
262 fn default() -> Self {
263 Self {
264 max_errors: 100,
265 continue_on_error: true,
266 error_context_lines: 3,
267 include_suggestions: true,
268 collect_error_stats: false,
269 }
270 }
271}
272
273impl Default for MemorySettings {
274 fn default() -> Self {
275 Self {
276 max_parser_memory: 50 * 1024 * 1024, allocation_strategy: MemoryAllocationStrategy::Standard,
278 enable_memory_pooling: false,
279 memory_pool_size: 1024,
280 }
281 }
282}
283
284impl Default for SecuritySettings {
285 fn default() -> Self {
286 Self {
287 max_query_depth: 100,
288 max_token_count: 10_000,
289 enable_input_sanitization: true,
290 restrict_dangerous_operations: true,
291 blocked_keywords: vec![],
292 }
293 }
294}
295
296impl ParserConfig {
297 pub fn new() -> Self {
299 Self::default()
300 }
301
302 pub fn fast() -> Self {
307 Self {
308 backend: ParserBackend::Nom,
309 timeout: Duration::from_secs(10),
310 strict_validation: false,
311 features: vec![
312 ParserFeature::Parallel,
313 ParserFeature::Caching,
314 ParserFeature::Streaming,
315 ],
316 performance: PerformanceSettings {
317 optimization_level: 3,
318 enable_jit: true,
319 worker_threads: (num_cpus::get() as u32).max(2),
320 ..Default::default()
321 },
322 ..Default::default()
323 }
324 }
325
326 pub fn strict() -> Self {
328 Self {
329 backend: ParserBackend::Antlr,
330 strict_validation: true,
331 allow_experimental: false,
332 features: vec![
333 ParserFeature::ErrorRecovery,
334 ParserFeature::OnlineValidation,
335 ParserFeature::Profiling,
336 ParserFeature::SyntaxHighlighting,
337 ],
338 error_handling: ErrorHandlingSettings {
339 max_errors: 1,
340 continue_on_error: false,
341 include_suggestions: true,
342 collect_error_stats: true,
343 ..Default::default()
344 },
345 ..Default::default()
346 }
347 }
348
349 pub fn development() -> Self {
351 Self {
352 backend: ParserBackend::Auto,
353 allow_experimental: true,
354 features: vec![
355 ParserFeature::ErrorRecovery,
356 ParserFeature::SyntaxHighlighting,
357 ParserFeature::CodeCompletion,
358 ParserFeature::AstTransformation,
359 ParserFeature::OnlineValidation,
360 ParserFeature::Profiling,
361 ],
362 error_handling: ErrorHandlingSettings {
363 continue_on_error: true,
364 include_suggestions: true,
365 collect_error_stats: true,
366 ..Default::default()
367 },
368 ..Default::default()
369 }
370 }
371
372 pub fn minimal() -> Self {
374 Self {
375 backend: ParserBackend::Nom,
376 timeout: Duration::from_secs(5),
377 max_expression_depth: 50,
378 max_collection_size: 1000,
379 max_string_length: 10_000,
380 max_parameters: 100,
381 strict_validation: false,
382 features: vec![],
383 memory_limits: MemoryLimits {
384 max_ast_size: 10 * 1024 * 1024, max_temp_memory: 5 * 1024 * 1024, max_stack_depth: 100,
387 max_cache_entries: 100,
388 },
389 performance: PerformanceSettings {
390 worker_threads: 1,
391 enable_caching: false,
392 optimization_level: 1,
393 ..Default::default()
394 },
395 error_handling: ErrorHandlingSettings {
396 max_errors: 10,
397 error_context_lines: 1,
398 include_suggestions: false,
399 collect_error_stats: false,
400 ..Default::default()
401 },
402 ..Default::default()
403 }
404 }
405
406 pub fn with_backend(mut self, backend: ParserBackend) -> Self {
408 self.backend = backend;
409 self
410 }
411
412 pub fn with_timeout(mut self, timeout: Duration) -> Self {
414 self.timeout = timeout;
415 self
416 }
417
418 pub fn with_strict_validation(mut self, strict: bool) -> Self {
420 self.strict_validation = strict;
421 self
422 }
423
424 pub fn with_feature(mut self, feature: ParserFeature) -> Self {
426 if !self.features.contains(&feature) {
427 self.features.push(feature);
428 }
429 self
430 }
431
432 pub fn has_feature(&self, feature: &ParserFeature) -> bool {
434 self.features.contains(feature)
435 }
436
437 pub fn validate(&self) -> Result<(), String> {
439 if self.timeout.as_secs() == 0 {
440 return Err("Timeout must be greater than 0".to_string());
441 }
442 if self.max_expression_depth == 0 {
443 return Err("Max expression depth must be greater than 0".to_string());
444 }
445 if self.max_collection_size == 0 {
446 return Err("Max collection size must be greater than 0".to_string());
447 }
448 if self.memory_limits.max_ast_size == 0 {
449 return Err("Max AST size must be greater than 0".to_string());
450 }
451 if self.memory_limits.max_stack_depth == 0 {
452 return Err("Max stack depth must be greater than 0".to_string());
453 }
454 if self.performance.worker_threads == 0 {
455 return Err("Worker threads must be greater than 0".to_string());
456 }
457 if self.performance.stream_buffer_size < 1024 {
458 return Err("Stream buffer size should be at least 1KB for efficiency".to_string());
459 }
460 if self.performance.optimization_level > 3 {
461 return Err("Optimization level must be 0-3".to_string());
462 }
463 if self.error_handling.max_errors == 0 {
464 return Err("Max errors must be greater than 0".to_string());
465 }
466
467 if self.has_feature(&ParserFeature::Parallel) && self.performance.worker_threads == 1 {
468 return Err("Parallel parsing requires at least 2 worker threads. Use ParserConfig::fast() for automatic thread count adjustment.".to_string());
469 }
470 if self.has_feature(&ParserFeature::Streaming)
471 && matches!(self.backend, ParserBackend::Antlr)
472 {
473 return Err("Streaming is not supported with ANTLR backend".to_string());
474 }
475
476 Ok(())
477 }
478}
479
480#[cfg(test)]
481mod tests {
482 use super::*;
483
484 #[test]
485 fn test_default_config() {
486 let config = ParserConfig::default();
487 assert!(matches!(config.backend, ParserBackend::Auto));
488 assert!(config.strict_validation);
489 assert!(!config.allow_experimental);
490 assert!(config.validate().is_ok());
491 }
492
493 #[test]
494 fn test_preset_configs() {
495 let fast = ParserConfig::fast();
496 assert!(matches!(fast.backend, ParserBackend::Nom));
497 assert!(!fast.strict_validation);
498 assert!(fast.validate().is_ok());
499
500 let strict = ParserConfig::strict();
501 assert!(matches!(strict.backend, ParserBackend::Antlr));
502 assert!(strict.strict_validation);
503 assert!(strict.validate().is_ok());
504
505 let minimal = ParserConfig::minimal();
506 assert_eq!(minimal.memory_limits.max_ast_size, 10 * 1024 * 1024);
507 assert!(minimal.validate().is_ok());
508 }
509
510 #[test]
511 fn test_config_validation() {
512 let mut config = ParserConfig::default();
513 assert!(config.validate().is_ok());
514
515 config.timeout = Duration::from_secs(0);
516 assert!(config.validate().is_err());
517
518 config = ParserConfig::default();
519 config.performance.optimization_level = 5;
520 assert!(config.validate().is_err());
521 }
522
523 #[test]
524 fn test_feature_management() {
525 let mut config = ParserConfig::default();
526 assert!(!config.has_feature(&ParserFeature::Streaming));
527
528 config = config.with_feature(ParserFeature::Streaming);
529 assert!(config.has_feature(&ParserFeature::Streaming));
530 }
531
532 #[test]
533 fn test_parallel_requires_multiple_workers() {
534 let mut config = ParserConfig::minimal().with_feature(ParserFeature::Parallel);
535 config.performance.worker_threads = 1;
536 let err = config
537 .validate()
538 .expect_err("parallel parsing should require >1 worker");
539 assert!(err.contains("Parallel parsing requires at least 2 worker threads"));
540 }
541
542 #[test]
543 fn test_streaming_not_allowed_with_antlr() {
544 let config = ParserConfig::strict().with_feature(ParserFeature::Streaming);
545 let err = config
546 .validate()
547 .expect_err("streaming should be incompatible with ANTLR backend");
548 assert!(err.contains("Streaming is not supported with ANTLR backend"));
549 }
550}