1use regex::Regex;
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4use thiserror::Error;
5
6#[derive(Error, Debug)]
7pub enum AnnotationError {
8 #[error("Invalid annotation syntax: {0}")]
9 InvalidSyntax(String),
10 #[error("Unknown annotation key: {0}")]
11 UnknownKey(String),
12 #[error("Invalid value for key {key}: {value}")]
13 InvalidValue { key: String, value: String },
14}
15
16#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
17pub struct TranspilationAnnotations {
18 pub type_strategy: TypeStrategy,
19 pub ownership_model: OwnershipModel,
20 pub safety_level: SafetyLevel,
21 pub performance_hints: Vec<PerformanceHint>,
22 pub fallback_strategy: FallbackStrategy,
23 pub bounds_checking: BoundsChecking,
24 pub optimization_level: OptimizationLevel,
25 pub thread_safety: ThreadSafety,
26 pub interior_mutability: InteriorMutability,
27 pub string_strategy: StringStrategy,
28 pub hash_strategy: HashStrategy,
29 pub panic_behavior: PanicBehavior,
30 pub error_strategy: ErrorStrategy,
31 pub global_strategy: GlobalStrategy,
32 pub termination: Termination,
33 pub invariants: Vec<String>,
34 pub verify_bounds: bool,
35 pub service_type: Option<ServiceType>,
36 pub migration_strategy: Option<MigrationStrategy>,
37 pub compatibility_layer: Option<CompatibilityLayer>,
38 pub pattern: Option<String>,
39 pub lambda_annotations: Option<LambdaAnnotations>,
41}
42
43impl Default for TranspilationAnnotations {
44 fn default() -> Self {
45 Self {
46 type_strategy: TypeStrategy::Conservative,
47 ownership_model: OwnershipModel::Owned,
48 safety_level: SafetyLevel::Safe,
49 performance_hints: Vec::new(),
50 fallback_strategy: FallbackStrategy::Error,
51 bounds_checking: BoundsChecking::Explicit,
52 optimization_level: OptimizationLevel::Standard,
53 thread_safety: ThreadSafety::NotRequired,
54 interior_mutability: InteriorMutability::None,
55 string_strategy: StringStrategy::Conservative,
56 hash_strategy: HashStrategy::Standard,
57 panic_behavior: PanicBehavior::Propagate,
58 error_strategy: ErrorStrategy::Panic,
59 global_strategy: GlobalStrategy::None,
60 termination: Termination::Unknown,
61 invariants: Vec::new(),
62 verify_bounds: false,
63 service_type: None,
64 migration_strategy: None,
65 compatibility_layer: None,
66 pattern: None,
67 lambda_annotations: None,
68 }
69 }
70}
71
72#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
73pub struct LambdaAnnotations {
74 pub runtime: LambdaRuntime,
75 pub event_type: Option<LambdaEventType>,
76 pub cold_start_optimize: bool,
77 pub memory_size: u16,
78 pub architecture: Architecture,
79 pub pre_warm_paths: Vec<String>,
80 pub custom_serialization: bool,
81 pub batch_failure_reporting: bool,
82 pub timeout: Option<u16>,
83 pub tracing_enabled: bool,
84 pub environment_variables: Vec<(String, String)>,
85}
86
87impl Default for LambdaAnnotations {
88 fn default() -> Self {
89 Self {
90 runtime: LambdaRuntime::ProvidedAl2,
91 event_type: None,
92 cold_start_optimize: true,
93 memory_size: 128,
94 architecture: Architecture::Arm64,
95 pre_warm_paths: vec![],
96 custom_serialization: false,
97 batch_failure_reporting: false,
98 timeout: None,
99 tracing_enabled: false,
100 environment_variables: vec![],
101 }
102 }
103}
104
105#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
106pub enum LambdaRuntime {
107 ProvidedAl2,
108 ProvidedAl2023,
109 Custom(String),
110}
111
112#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
113pub enum LambdaEventType {
114 Auto,
115 S3Event,
116 ApiGatewayProxyRequest,
117 ApiGatewayV2HttpRequest,
118 SqsEvent,
119 SnsEvent,
120 DynamodbEvent,
121 EventBridgeEvent(Option<String>),
122 CloudwatchEvent,
123 KinesisEvent,
124 Custom(String),
125}
126
127#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
128pub enum Architecture {
129 X86_64,
130 Arm64,
131}
132
133#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
134pub enum TypeStrategy {
135 Conservative,
136 Aggressive,
137 ZeroCopy,
138 AlwaysOwned,
139}
140
141#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
142pub enum OwnershipModel {
143 Owned,
144 Borrowed,
145 Shared,
146}
147
148#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
149pub enum SafetyLevel {
150 Safe,
151 UnsafeAllowed,
152}
153
154#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
155pub enum PerformanceHint {
156 Vectorize,
157 UnrollLoops(u32),
158 OptimizeForLatency,
159 OptimizeForThroughput,
160 PerformanceCritical,
161}
162
163#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
164pub enum FallbackStrategy {
165 Mcp,
166 Manual,
167 Error,
168}
169
170#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
171pub enum BoundsChecking {
172 Explicit,
173 Implicit,
174 Disabled,
175}
176
177#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
178pub enum OptimizationLevel {
179 Standard,
180 Aggressive,
181 Conservative,
182}
183
184#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
185pub enum ThreadSafety {
186 Required,
187 NotRequired,
188}
189
190#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
191pub enum InteriorMutability {
192 None,
193 ArcMutex,
194 RefCell,
195 Cell,
196}
197
198#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
199pub enum StringStrategy {
200 Conservative,
201 AlwaysOwned,
202 ZeroCopy,
203}
204
205#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
206pub enum HashStrategy {
207 Standard,
208 Fnv,
209 AHash,
210}
211
212#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
213pub enum PanicBehavior {
214 Propagate,
215 ReturnError,
216 Abort,
217}
218
219#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
220pub enum ErrorStrategy {
221 Panic,
222 ResultType,
223 OptionType,
224}
225
226#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
227pub enum GlobalStrategy {
228 None,
229 LazyStatic,
230 OnceCell,
231}
232
233#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
234pub enum Termination {
235 Unknown,
236 Proven,
237 BoundedLoop(u32),
238}
239
240#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
241pub enum ServiceType {
242 WebApi,
243 Cli,
244 Library,
245}
246
247#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
248pub enum MigrationStrategy {
249 Incremental,
250 BigBang,
251 Hybrid,
252}
253
254#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
255pub enum CompatibilityLayer {
256 PyO3,
257 CTypes,
258 None,
259}
260
261pub struct AnnotationParser {
262 pattern: Regex,
263}
264
265#[derive(Debug, Clone, Default)]
266pub struct AnnotationValidator;
267
268impl AnnotationValidator {
269 pub fn new() -> Self {
270 Self
271 }
272
273 pub fn validate(&self, annotations: &TranspilationAnnotations) -> Result<(), Vec<String>> {
274 let mut errors = Vec::new();
275
276 if annotations.string_strategy == StringStrategy::ZeroCopy
278 && annotations.ownership_model == OwnershipModel::Owned
279 {
280 errors
281 .push("Zero-copy string strategy conflicts with owned ownership model".to_string());
282 }
283
284 if annotations.thread_safety == ThreadSafety::Required
285 && annotations.interior_mutability == InteriorMutability::RefCell
286 {
287 errors.push("RefCell is not thread-safe, use Arc<Mutex<T>> instead".to_string());
288 }
289
290 if annotations.panic_behavior == PanicBehavior::ReturnError
291 && annotations.error_strategy == ErrorStrategy::Panic
292 {
293 errors.push("Conflicting panic behavior and error strategy".to_string());
294 }
295
296 if annotations.optimization_level == OptimizationLevel::Aggressive
297 && annotations.bounds_checking == BoundsChecking::Explicit
298 {
299 errors.push(
300 "Aggressive optimization may conflict with explicit bounds checking".to_string(),
301 );
302 }
303
304 if errors.is_empty() {
305 Ok(())
306 } else {
307 Err(errors)
308 }
309 }
310
311 pub fn suggest_improvements(&self, annotations: &TranspilationAnnotations) -> Vec<String> {
312 let mut suggestions = Vec::new();
313
314 if annotations
315 .performance_hints
316 .contains(&PerformanceHint::PerformanceCritical)
317 && annotations.optimization_level != OptimizationLevel::Aggressive
318 {
319 suggestions.push(
320 "Consider using optimization_level = \"aggressive\" for performance critical code"
321 .to_string(),
322 );
323 }
324
325 if annotations.thread_safety == ThreadSafety::Required
326 && annotations.ownership_model != OwnershipModel::Shared
327 {
328 suggestions
329 .push("Consider using ownership = \"shared\" for thread-safe code".to_string());
330 }
331
332 if annotations.service_type == Some(ServiceType::WebApi)
333 && !annotations
334 .performance_hints
335 .contains(&PerformanceHint::OptimizeForLatency)
336 {
337 suggestions
338 .push("Consider adding optimization_hint = \"latency\" for web APIs".to_string());
339 }
340
341 suggestions
342 }
343}
344
345#[derive(Debug, Clone)]
346pub struct AnnotationExtractor {
347 function_pattern: Regex,
348 class_pattern: Regex,
349}
350
351impl Default for AnnotationExtractor {
352 fn default() -> Self {
353 Self {
354 function_pattern: Regex::new(r"(?m)^def\s+(\w+)\s*\(").unwrap(),
355 class_pattern: Regex::new(r"(?m)^class\s+(\w+)\s*[\(:]").unwrap(),
356 }
357 }
358}
359
360impl AnnotationExtractor {
361 pub fn new() -> Self {
362 Self::default()
363 }
364
365 pub fn extract_function_annotations(
366 &self,
367 source: &str,
368 function_name: &str,
369 ) -> Option<String> {
370 let lines: Vec<&str> = source.lines().collect();
371
372 for (i, line) in lines.iter().enumerate() {
373 if let Some(captures) = self.function_pattern.captures(line) {
374 if captures.get(1).unwrap().as_str() == function_name {
375 let mut annotations = Vec::new();
377 let mut j = i.saturating_sub(1);
378
379 while j < i && (lines[j].trim().starts_with("#") || lines[j].trim().is_empty())
380 {
381 if lines[j].contains("@depyler:") {
382 annotations.push(lines[j]);
383 }
384 if j == 0 {
385 break;
386 }
387 j = j.saturating_sub(1);
388 }
389
390 if !annotations.is_empty() {
391 annotations.reverse();
392 return Some(annotations.join("\n"));
393 }
394 }
395 }
396 }
397 None
398 }
399
400 pub fn extract_class_annotations(&self, source: &str, class_name: &str) -> Option<String> {
401 let lines: Vec<&str> = source.lines().collect();
402
403 for (i, line) in lines.iter().enumerate() {
404 if let Some(captures) = self.class_pattern.captures(line) {
405 if captures.get(1).unwrap().as_str() == class_name {
406 let mut annotations = Vec::new();
408 let mut j = i.saturating_sub(1);
409
410 while j < i && (lines[j].trim().starts_with("#") || lines[j].trim().is_empty())
411 {
412 if lines[j].contains("@depyler:") {
413 annotations.push(lines[j]);
414 }
415 if j == 0 {
416 break;
417 }
418 j = j.saturating_sub(1);
419 }
420
421 if !annotations.is_empty() {
422 annotations.reverse();
423 return Some(annotations.join("\n"));
424 }
425 }
426 }
427 }
428 None
429 }
430}
431
432impl Default for AnnotationParser {
433 fn default() -> Self {
434 Self::new()
435 }
436}
437
438impl AnnotationParser {
439 pub fn new() -> Self {
440 let pattern =
441 Regex::new(r"#\s*@depyler:\s*(\w+)\s*=\s*(.+)")
443 .unwrap_or_else(|e| panic!("Failed to compile annotation regex: {}", e));
444 Self { pattern }
445 }
446
447 pub fn parse_annotations(
448 &self,
449 source: &str,
450 ) -> Result<TranspilationAnnotations, AnnotationError> {
451 let mut annotations = TranspilationAnnotations::default();
452 let mut parsed_values: HashMap<String, String> = HashMap::new();
453
454 for line in source.lines() {
455 if let Some(captures) = self.pattern.captures(line) {
456 let key = captures.get(1).unwrap().as_str().to_string();
457 let value = captures.get(2).unwrap().as_str().trim_matches('"').trim();
458 parsed_values.insert(key, value.to_string());
459 }
460 }
461
462 self.apply_annotations(&mut annotations, parsed_values)?;
463 Ok(annotations)
464 }
465
466 pub fn parse_function_annotations(
467 &self,
468 function_source: &str,
469 ) -> Result<TranspilationAnnotations, AnnotationError> {
470 self.parse_annotations(function_source)
471 }
472
473 fn apply_annotations(
474 &self,
475 annotations: &mut TranspilationAnnotations,
476 values: HashMap<String, String>,
477 ) -> Result<(), AnnotationError> {
478 for (key, value) in values {
479 match key.as_str() {
480 "type_strategy" => {
481 annotations.type_strategy = self.parse_type_strategy(&value)?;
482 }
483 "ownership" => {
484 annotations.ownership_model = self.parse_ownership_model(&value)?;
485 }
486 "safety_level" => {
487 annotations.safety_level = self.parse_safety_level(&value)?;
488 }
489 "fallback" => {
490 annotations.fallback_strategy = self.parse_fallback_strategy(&value)?;
491 }
492 "bounds_checking" => {
493 annotations.bounds_checking = self.parse_bounds_checking(&value)?;
494 }
495 "optimization_level" => {
496 annotations.optimization_level = self.parse_optimization_level(&value)?;
497 }
498 "thread_safety" => {
499 annotations.thread_safety = self.parse_thread_safety(&value)?;
500 }
501 "interior_mutability" => {
502 annotations.interior_mutability = self.parse_interior_mutability(&value)?;
503 }
504 "performance_critical" => {
505 if value == "true" {
506 annotations
507 .performance_hints
508 .push(PerformanceHint::PerformanceCritical);
509 }
510 }
511 "vectorize" => {
512 if value == "true" {
513 annotations
514 .performance_hints
515 .push(PerformanceHint::Vectorize);
516 }
517 }
518 "unroll_loops" => {
519 let count: u32 = value.parse().map_err(|_| AnnotationError::InvalidValue {
520 key: key.clone(),
521 value: value.clone(),
522 })?;
523 annotations
524 .performance_hints
525 .push(PerformanceHint::UnrollLoops(count));
526 }
527 "optimization_hint" => {
528 match value.as_str() {
529 "vectorize" => annotations
530 .performance_hints
531 .push(PerformanceHint::Vectorize),
532 "latency" => annotations
533 .performance_hints
534 .push(PerformanceHint::OptimizeForLatency),
535 "throughput" => annotations
536 .performance_hints
537 .push(PerformanceHint::OptimizeForThroughput),
538 "async_ready" => {
539 eprintln!(
542 "Warning: async_ready is experimental and not yet fully supported"
543 );
544 }
545 _ => return Err(AnnotationError::InvalidValue { key, value }),
546 }
547 }
548 "string_strategy" => {
549 annotations.string_strategy = self.parse_string_strategy(&value)?;
550 }
551 "hash_strategy" => {
552 annotations.hash_strategy = self.parse_hash_strategy(&value)?;
553 }
554 "panic_behavior" => {
555 annotations.panic_behavior = self.parse_panic_behavior(&value)?;
556 }
557 "error_strategy" => {
558 annotations.error_strategy = self.parse_error_strategy(&value)?;
559 }
560 "global_strategy" => {
561 annotations.global_strategy = self.parse_global_strategy(&value)?;
562 }
563 "termination" => {
564 annotations.termination = self.parse_termination(&value)?;
565 }
566 "invariant" => {
567 annotations.invariants.push(value);
568 }
569 "verify_bounds" => {
570 annotations.verify_bounds = value == "true";
571 }
572 "service_type" => {
573 annotations.service_type = Some(self.parse_service_type(&value)?);
574 }
575 "migration_strategy" => {
576 annotations.migration_strategy = Some(self.parse_migration_strategy(&value)?);
577 }
578 "compatibility_layer" => {
579 annotations.compatibility_layer = Some(self.parse_compatibility_layer(&value)?);
580 }
581 "pattern" => {
582 annotations.pattern = Some(value);
583 }
584 "lambda_runtime" => {
586 let lambda_annotations = annotations
587 .lambda_annotations
588 .get_or_insert_with(LambdaAnnotations::default);
589 lambda_annotations.runtime = self.parse_lambda_runtime(&value)?;
590 }
591 "event_type" => {
592 let lambda_annotations = annotations
593 .lambda_annotations
594 .get_or_insert_with(LambdaAnnotations::default);
595 lambda_annotations.event_type = Some(self.parse_lambda_event_type(&value)?);
596 }
597 "cold_start_optimize" => {
598 let lambda_annotations = annotations
599 .lambda_annotations
600 .get_or_insert_with(LambdaAnnotations::default);
601 lambda_annotations.cold_start_optimize = value == "true";
602 }
603 "memory_size" => {
604 let lambda_annotations = annotations
605 .lambda_annotations
606 .get_or_insert_with(LambdaAnnotations::default);
607 lambda_annotations.memory_size =
608 value.parse().map_err(|_| AnnotationError::InvalidValue {
609 key: key.clone(),
610 value: value.clone(),
611 })?;
612 }
613 "architecture" => {
614 let lambda_annotations = annotations
615 .lambda_annotations
616 .get_or_insert_with(LambdaAnnotations::default);
617 lambda_annotations.architecture = self.parse_architecture(&value)?;
618 }
619 "batch_failure_reporting" => {
620 let lambda_annotations = annotations
621 .lambda_annotations
622 .get_or_insert_with(LambdaAnnotations::default);
623 lambda_annotations.batch_failure_reporting = value == "true";
624 }
625 "custom_serialization" => {
626 let lambda_annotations = annotations
627 .lambda_annotations
628 .get_or_insert_with(LambdaAnnotations::default);
629 lambda_annotations.custom_serialization = value == "true";
630 }
631 "timeout" => {
632 let lambda_annotations = annotations
633 .lambda_annotations
634 .get_or_insert_with(LambdaAnnotations::default);
635 lambda_annotations.timeout =
636 Some(value.parse().map_err(|_| AnnotationError::InvalidValue {
637 key: key.clone(),
638 value: value.clone(),
639 })?);
640 }
641 "tracing" => {
642 let lambda_annotations = annotations
643 .lambda_annotations
644 .get_or_insert_with(LambdaAnnotations::default);
645 lambda_annotations.tracing_enabled = value == "true" || value == "Active";
646 }
647 _ => return Err(AnnotationError::UnknownKey(key)),
648 }
649 }
650 Ok(())
651 }
652
653 fn parse_type_strategy(&self, value: &str) -> Result<TypeStrategy, AnnotationError> {
654 match value {
655 "conservative" => Ok(TypeStrategy::Conservative),
656 "aggressive" => Ok(TypeStrategy::Aggressive),
657 "zero_copy" => Ok(TypeStrategy::ZeroCopy),
658 "always_owned" => Ok(TypeStrategy::AlwaysOwned),
659 _ => Err(AnnotationError::InvalidValue {
660 key: "type_strategy".to_string(),
661 value: value.to_string(),
662 }),
663 }
664 }
665
666 fn parse_ownership_model(&self, value: &str) -> Result<OwnershipModel, AnnotationError> {
667 match value {
668 "owned" => Ok(OwnershipModel::Owned),
669 "borrowed" => Ok(OwnershipModel::Borrowed),
670 "shared" => Ok(OwnershipModel::Shared),
671 _ => Err(AnnotationError::InvalidValue {
672 key: "ownership".to_string(),
673 value: value.to_string(),
674 }),
675 }
676 }
677
678 fn parse_safety_level(&self, value: &str) -> Result<SafetyLevel, AnnotationError> {
679 match value {
680 "safe" => Ok(SafetyLevel::Safe),
681 "unsafe_allowed" => Ok(SafetyLevel::UnsafeAllowed),
682 _ => Err(AnnotationError::InvalidValue {
683 key: "safety_level".to_string(),
684 value: value.to_string(),
685 }),
686 }
687 }
688
689 fn parse_fallback_strategy(&self, value: &str) -> Result<FallbackStrategy, AnnotationError> {
690 match value {
691 "mcp" => Ok(FallbackStrategy::Mcp),
692 "manual" => Ok(FallbackStrategy::Manual),
693 "error" => Ok(FallbackStrategy::Error),
694 _ => Err(AnnotationError::InvalidValue {
695 key: "fallback".to_string(),
696 value: value.to_string(),
697 }),
698 }
699 }
700
701 fn parse_bounds_checking(&self, value: &str) -> Result<BoundsChecking, AnnotationError> {
702 match value {
703 "explicit" => Ok(BoundsChecking::Explicit),
704 "implicit" => Ok(BoundsChecking::Implicit),
705 "disabled" => Ok(BoundsChecking::Disabled),
706 _ => Err(AnnotationError::InvalidValue {
707 key: "bounds_checking".to_string(),
708 value: value.to_string(),
709 }),
710 }
711 }
712
713 fn parse_optimization_level(&self, value: &str) -> Result<OptimizationLevel, AnnotationError> {
714 match value {
715 "standard" => Ok(OptimizationLevel::Standard),
716 "aggressive" => Ok(OptimizationLevel::Aggressive),
717 "conservative" => Ok(OptimizationLevel::Conservative),
718 _ => Err(AnnotationError::InvalidValue {
719 key: "optimization_level".to_string(),
720 value: value.to_string(),
721 }),
722 }
723 }
724
725 fn parse_thread_safety(&self, value: &str) -> Result<ThreadSafety, AnnotationError> {
726 match value {
727 "required" => Ok(ThreadSafety::Required),
728 "not_required" => Ok(ThreadSafety::NotRequired),
729 _ => Err(AnnotationError::InvalidValue {
730 key: "thread_safety".to_string(),
731 value: value.to_string(),
732 }),
733 }
734 }
735
736 fn parse_interior_mutability(
737 &self,
738 value: &str,
739 ) -> Result<InteriorMutability, AnnotationError> {
740 match value {
741 "none" => Ok(InteriorMutability::None),
742 "arc_mutex" => Ok(InteriorMutability::ArcMutex),
743 "ref_cell" => Ok(InteriorMutability::RefCell),
744 "cell" => Ok(InteriorMutability::Cell),
745 _ => Err(AnnotationError::InvalidValue {
746 key: "interior_mutability".to_string(),
747 value: value.to_string(),
748 }),
749 }
750 }
751
752 fn parse_string_strategy(&self, value: &str) -> Result<StringStrategy, AnnotationError> {
753 match value {
754 "conservative" => Ok(StringStrategy::Conservative),
755 "always_owned" => Ok(StringStrategy::AlwaysOwned),
756 "zero_copy" => Ok(StringStrategy::ZeroCopy),
757 _ => Err(AnnotationError::InvalidValue {
758 key: "string_strategy".to_string(),
759 value: value.to_string(),
760 }),
761 }
762 }
763
764 fn parse_hash_strategy(&self, value: &str) -> Result<HashStrategy, AnnotationError> {
765 match value {
766 "standard" => Ok(HashStrategy::Standard),
767 "fnv" => Ok(HashStrategy::Fnv),
768 "ahash" => Ok(HashStrategy::AHash),
769 _ => Err(AnnotationError::InvalidValue {
770 key: "hash_strategy".to_string(),
771 value: value.to_string(),
772 }),
773 }
774 }
775
776 fn parse_panic_behavior(&self, value: &str) -> Result<PanicBehavior, AnnotationError> {
777 match value {
778 "propagate" => Ok(PanicBehavior::Propagate),
779 "return_error" => Ok(PanicBehavior::ReturnError),
780 "abort" => Ok(PanicBehavior::Abort),
781 _ => Err(AnnotationError::InvalidValue {
782 key: "panic_behavior".to_string(),
783 value: value.to_string(),
784 }),
785 }
786 }
787
788 fn parse_error_strategy(&self, value: &str) -> Result<ErrorStrategy, AnnotationError> {
789 match value {
790 "panic" => Ok(ErrorStrategy::Panic),
791 "result_type" => Ok(ErrorStrategy::ResultType),
792 "option_type" => Ok(ErrorStrategy::OptionType),
793 _ => Err(AnnotationError::InvalidValue {
794 key: "error_strategy".to_string(),
795 value: value.to_string(),
796 }),
797 }
798 }
799
800 fn parse_global_strategy(&self, value: &str) -> Result<GlobalStrategy, AnnotationError> {
801 match value {
802 "none" => Ok(GlobalStrategy::None),
803 "lazy_static" => Ok(GlobalStrategy::LazyStatic),
804 "once_cell" => Ok(GlobalStrategy::OnceCell),
805 _ => Err(AnnotationError::InvalidValue {
806 key: "global_strategy".to_string(),
807 value: value.to_string(),
808 }),
809 }
810 }
811
812 fn parse_termination(&self, value: &str) -> Result<Termination, AnnotationError> {
813 match value {
814 "unknown" => Ok(Termination::Unknown),
815 "proven" => Ok(Termination::Proven),
816 _ => {
817 if value.starts_with("bounded_") {
818 if let Some(num_str) = value.strip_prefix("bounded_") {
819 if let Ok(bound) = num_str.parse::<u32>() {
820 return Ok(Termination::BoundedLoop(bound));
821 }
822 }
823 }
824 Err(AnnotationError::InvalidValue {
825 key: "termination".to_string(),
826 value: value.to_string(),
827 })
828 }
829 }
830 }
831
832 fn parse_service_type(&self, value: &str) -> Result<ServiceType, AnnotationError> {
833 match value {
834 "web_api" => Ok(ServiceType::WebApi),
835 "cli" => Ok(ServiceType::Cli),
836 "library" => Ok(ServiceType::Library),
837 _ => Err(AnnotationError::InvalidValue {
838 key: "service_type".to_string(),
839 value: value.to_string(),
840 }),
841 }
842 }
843
844 fn parse_migration_strategy(&self, value: &str) -> Result<MigrationStrategy, AnnotationError> {
845 match value {
846 "incremental" => Ok(MigrationStrategy::Incremental),
847 "big_bang" => Ok(MigrationStrategy::BigBang),
848 "hybrid" => Ok(MigrationStrategy::Hybrid),
849 _ => Err(AnnotationError::InvalidValue {
850 key: "migration_strategy".to_string(),
851 value: value.to_string(),
852 }),
853 }
854 }
855
856 fn parse_compatibility_layer(
857 &self,
858 value: &str,
859 ) -> Result<CompatibilityLayer, AnnotationError> {
860 match value {
861 "pyo3" => Ok(CompatibilityLayer::PyO3),
862 "ctypes" => Ok(CompatibilityLayer::CTypes),
863 "none" => Ok(CompatibilityLayer::None),
864 _ => Err(AnnotationError::InvalidValue {
865 key: "compatibility_layer".to_string(),
866 value: value.to_string(),
867 }),
868 }
869 }
870
871 fn parse_lambda_runtime(&self, value: &str) -> Result<LambdaRuntime, AnnotationError> {
872 match value {
873 "provided.al2" => Ok(LambdaRuntime::ProvidedAl2),
874 "provided.al2023" => Ok(LambdaRuntime::ProvidedAl2023),
875 _ => Ok(LambdaRuntime::Custom(value.to_string())),
876 }
877 }
878
879 fn parse_lambda_event_type(&self, value: &str) -> Result<LambdaEventType, AnnotationError> {
880 match value {
881 "auto" => Ok(LambdaEventType::Auto),
882 "S3Event" => Ok(LambdaEventType::S3Event),
883 "APIGatewayProxyRequest" => Ok(LambdaEventType::ApiGatewayProxyRequest),
884 "APIGatewayV2HttpRequest" => Ok(LambdaEventType::ApiGatewayV2HttpRequest),
885 "SqsEvent" => Ok(LambdaEventType::SqsEvent),
886 "SnsEvent" => Ok(LambdaEventType::SnsEvent),
887 "DynamodbEvent" => Ok(LambdaEventType::DynamodbEvent),
888 "CloudwatchEvent" => Ok(LambdaEventType::CloudwatchEvent),
889 "KinesisEvent" => Ok(LambdaEventType::KinesisEvent),
890 _ => {
891 if value.starts_with("EventBridgeEvent<") && value.ends_with('>') {
892 let inner = &value[17..value.len() - 1];
893 Ok(LambdaEventType::EventBridgeEvent(Some(inner.to_string())))
894 } else if value == "EventBridgeEvent" {
895 Ok(LambdaEventType::EventBridgeEvent(None))
896 } else {
897 Ok(LambdaEventType::Custom(value.to_string()))
898 }
899 }
900 }
901 }
902
903 fn parse_architecture(&self, value: &str) -> Result<Architecture, AnnotationError> {
904 match value {
905 "x86_64" | "x64" => Ok(Architecture::X86_64),
906 "arm64" | "aarch64" => Ok(Architecture::Arm64),
907 _ => Err(AnnotationError::InvalidValue {
908 key: "architecture".to_string(),
909 value: value.to_string(),
910 }),
911 }
912 }
913}
914
915#[cfg(test)]
916mod tests {
917 use super::*;
918
919 #[test]
920 fn test_parse_basic_annotations() {
921 let parser = AnnotationParser::new();
922 let source = r#"
923# @depyler: type_strategy = "conservative"
924# @depyler: ownership = "borrowed"
925def test_function():
926 pass
927 "#;
928
929 let annotations = parser.parse_annotations(source).unwrap();
930 assert_eq!(annotations.type_strategy, TypeStrategy::Conservative);
931 assert_eq!(annotations.ownership_model, OwnershipModel::Borrowed);
932 }
933
934 #[test]
935 fn test_parse_performance_annotations() {
936 let parser = AnnotationParser::new();
937 let source = r#"
938# @depyler: performance_critical = "true"
939# @depyler: vectorize = "true"
940# @depyler: unroll_loops = "4"
941def fast_function():
942 pass
943 "#;
944
945 let annotations = parser.parse_annotations(source).unwrap();
946 assert!(annotations
947 .performance_hints
948 .contains(&PerformanceHint::PerformanceCritical));
949 assert!(annotations
950 .performance_hints
951 .contains(&PerformanceHint::Vectorize));
952 assert!(annotations
953 .performance_hints
954 .contains(&PerformanceHint::UnrollLoops(4)));
955 }
956
957 #[test]
958 fn test_parse_safety_annotations() {
959 let parser = AnnotationParser::new();
960 let source = r#"
961# @depyler: safety_level = "unsafe_allowed"
962# @depyler: bounds_checking = "disabled"
963def unsafe_function():
964 pass
965 "#;
966
967 let annotations = parser.parse_annotations(source).unwrap();
968 assert_eq!(annotations.safety_level, SafetyLevel::UnsafeAllowed);
969 assert_eq!(annotations.bounds_checking, BoundsChecking::Disabled);
970 }
971
972 #[test]
973 fn test_parse_fallback_strategy() {
974 let parser = AnnotationParser::new();
975 let source = r#"
976# @depyler: fallback = "mcp"
977def complex_function():
978 pass
979 "#;
980
981 let annotations = parser.parse_annotations(source).unwrap();
982 assert_eq!(annotations.fallback_strategy, FallbackStrategy::Mcp);
983 }
984
985 #[test]
986 fn test_parse_thread_safety() {
987 let parser = AnnotationParser::new();
988 let source = r#"
989# @depyler: thread_safety = "required"
990# @depyler: interior_mutability = "arc_mutex"
991def thread_safe_function():
992 pass
993 "#;
994
995 let annotations = parser.parse_annotations(source).unwrap();
996 assert_eq!(annotations.thread_safety, ThreadSafety::Required);
997 assert_eq!(
998 annotations.interior_mutability,
999 InteriorMutability::ArcMutex
1000 );
1001 }
1002
1003 #[test]
1004 fn test_invalid_annotation_key() {
1005 let parser = AnnotationParser::new();
1006 let source = r#"
1007# @depyler: invalid_key = "value"
1008def test_function():
1009 pass
1010 "#;
1011
1012 let result = parser.parse_annotations(source);
1013 assert!(matches!(result, Err(AnnotationError::UnknownKey(_))));
1014 }
1015
1016 #[test]
1017 fn test_invalid_annotation_value() {
1018 let parser = AnnotationParser::new();
1019 let source = r#"
1020# @depyler: type_strategy = "invalid_value"
1021def test_function():
1022 pass
1023 "#;
1024
1025 let result = parser.parse_annotations(source);
1026 assert!(matches!(result, Err(AnnotationError::InvalidValue { .. })));
1027 }
1028
1029 #[test]
1030 fn test_default_annotations() {
1031 let annotations = TranspilationAnnotations::default();
1032 assert_eq!(annotations.type_strategy, TypeStrategy::Conservative);
1033 assert_eq!(annotations.ownership_model, OwnershipModel::Owned);
1034 assert_eq!(annotations.safety_level, SafetyLevel::Safe);
1035 assert_eq!(annotations.fallback_strategy, FallbackStrategy::Error);
1036 }
1037
1038 #[test]
1039 fn test_optimization_hints() {
1040 let parser = AnnotationParser::new();
1041 let source = r#"
1042# @depyler: optimization_hint = "vectorize"
1043# @depyler: optimization_level = "aggressive"
1044def optimized_function():
1045 pass
1046 "#;
1047
1048 let annotations = parser.parse_annotations(source).unwrap();
1049 assert!(annotations
1050 .performance_hints
1051 .contains(&PerformanceHint::Vectorize));
1052 assert_eq!(
1053 annotations.optimization_level,
1054 OptimizationLevel::Aggressive
1055 );
1056 }
1057
1058 #[test]
1059 fn test_string_and_hash_strategies() {
1060 let parser = AnnotationParser::new();
1061 let source = r#"
1062# @depyler: string_strategy = "zero_copy"
1063# @depyler: hash_strategy = "fnv"
1064def string_function():
1065 pass
1066 "#;
1067
1068 let annotations = parser.parse_annotations(source).unwrap();
1069 assert_eq!(annotations.string_strategy, StringStrategy::ZeroCopy);
1070 assert_eq!(annotations.hash_strategy, HashStrategy::Fnv);
1071 }
1072
1073 #[test]
1074 fn test_error_handling_annotations() {
1075 let parser = AnnotationParser::new();
1076 let source = r#"
1077# @depyler: panic_behavior = "return_error"
1078# @depyler: error_strategy = "result_type"
1079def error_function():
1080 pass
1081 "#;
1082
1083 let annotations = parser.parse_annotations(source).unwrap();
1084 assert_eq!(annotations.panic_behavior, PanicBehavior::ReturnError);
1085 assert_eq!(annotations.error_strategy, ErrorStrategy::ResultType);
1086 }
1087
1088 #[test]
1089 fn test_service_and_migration_annotations() {
1090 let parser = AnnotationParser::new();
1091 let source = r#"
1092# @depyler: service_type = "web_api"
1093# @depyler: migration_strategy = "incremental"
1094# @depyler: compatibility_layer = "pyo3"
1095def service_function():
1096 pass
1097 "#;
1098
1099 let annotations = parser.parse_annotations(source).unwrap();
1100 assert_eq!(annotations.service_type, Some(ServiceType::WebApi));
1101 assert_eq!(
1102 annotations.migration_strategy,
1103 Some(MigrationStrategy::Incremental)
1104 );
1105 assert_eq!(
1106 annotations.compatibility_layer,
1107 Some(CompatibilityLayer::PyO3)
1108 );
1109 }
1110
1111 #[test]
1112 fn test_verification_annotations() {
1113 let parser = AnnotationParser::new();
1114 let source = r#"
1115# @depyler: termination = "proven"
1116# @depyler: invariant = "left <= right"
1117# @depyler: verify_bounds = "true"
1118def verified_function():
1119 pass
1120 "#;
1121
1122 let annotations = parser.parse_annotations(source).unwrap();
1123 assert_eq!(annotations.termination, Termination::Proven);
1124 assert!(annotations
1125 .invariants
1126 .contains(&"left <= right".to_string()));
1127 assert!(annotations.verify_bounds);
1128 }
1129
1130 #[test]
1131 fn test_global_strategy() {
1132 let parser = AnnotationParser::new();
1133 let source = r#"
1134# @depyler: global_strategy = "lazy_static"
1135def global_function():
1136 pass
1137 "#;
1138
1139 let annotations = parser.parse_annotations(source).unwrap();
1140 assert_eq!(annotations.global_strategy, GlobalStrategy::LazyStatic);
1141 }
1142
1143 #[test]
1144 fn test_lambda_annotations_basic() {
1145 let parser = AnnotationParser::new();
1146 let source = r#"
1147# @depyler: lambda_runtime = "provided.al2"
1148# @depyler: event_type = "APIGatewayProxyRequest"
1149# @depyler: cold_start_optimize = "true"
1150def handler(event, context):
1151 pass
1152 "#;
1153
1154 let annotations = parser.parse_annotations(source).unwrap();
1155 assert!(annotations.lambda_annotations.is_some());
1156
1157 let lambda_annotations = annotations.lambda_annotations.unwrap();
1158 assert_eq!(lambda_annotations.runtime, LambdaRuntime::ProvidedAl2);
1159 assert_eq!(
1160 lambda_annotations.event_type,
1161 Some(LambdaEventType::ApiGatewayProxyRequest)
1162 );
1163 assert!(lambda_annotations.cold_start_optimize);
1164 }
1165
1166 #[test]
1167 fn test_lambda_annotations_memory_and_architecture() {
1168 let parser = AnnotationParser::new();
1169 let source = r#"
1170# @depyler: memory_size = "256"
1171# @depyler: architecture = "arm64"
1172# @depyler: timeout = "30"
1173def handler(event, context):
1174 pass
1175 "#;
1176
1177 let annotations = parser.parse_annotations(source).unwrap();
1178 let lambda_annotations = annotations.lambda_annotations.unwrap();
1179 assert_eq!(lambda_annotations.memory_size, 256);
1180 assert_eq!(lambda_annotations.architecture, Architecture::Arm64);
1181 assert_eq!(lambda_annotations.timeout, Some(30));
1182 }
1183
1184 #[test]
1185 fn test_lambda_eventbridge_with_custom_type() {
1186 let parser = AnnotationParser::new();
1187 let source = r#"
1188# @depyler: event_type = "EventBridgeEvent<OrderEvent>"
1189# @depyler: custom_serialization = "true"
1190def handler(event, context):
1191 pass
1192 "#;
1193
1194 let annotations = parser.parse_annotations(source).unwrap();
1195 let lambda_annotations = annotations.lambda_annotations.unwrap();
1196 assert_eq!(
1197 lambda_annotations.event_type,
1198 Some(LambdaEventType::EventBridgeEvent(Some(
1199 "OrderEvent".to_string()
1200 )))
1201 );
1202 assert!(lambda_annotations.custom_serialization);
1203 }
1204
1205 #[test]
1206 fn test_lambda_sqs_batch_processing() {
1207 let parser = AnnotationParser::new();
1208 let source = r#"
1209# @depyler: event_type = "SqsEvent"
1210# @depyler: batch_failure_reporting = "true"
1211# @depyler: tracing = "Active"
1212def handler(event, context):
1213 pass
1214 "#;
1215
1216 let annotations = parser.parse_annotations(source).unwrap();
1217 let lambda_annotations = annotations.lambda_annotations.unwrap();
1218 assert_eq!(
1219 lambda_annotations.event_type,
1220 Some(LambdaEventType::SqsEvent)
1221 );
1222 assert!(lambda_annotations.batch_failure_reporting);
1223 assert!(lambda_annotations.tracing_enabled);
1224 }
1225
1226 #[test]
1227 fn test_lambda_auto_event_type() {
1228 let parser = AnnotationParser::new();
1229 let source = r#"
1230# @depyler: event_type = "auto"
1231# @depyler: cold_start_optimize = "true"
1232def handler(event, context):
1233 pass
1234 "#;
1235
1236 let annotations = parser.parse_annotations(source).unwrap();
1237 let lambda_annotations = annotations.lambda_annotations.unwrap();
1238 assert_eq!(lambda_annotations.event_type, Some(LambdaEventType::Auto));
1239 assert!(lambda_annotations.cold_start_optimize);
1240 }
1241
1242 #[test]
1243 fn test_lambda_custom_runtime() {
1244 let parser = AnnotationParser::new();
1245 let source = r#"
1246# @depyler: lambda_runtime = "rust-runtime-1.0"
1247def handler(event, context):
1248 pass
1249 "#;
1250
1251 let annotations = parser.parse_annotations(source).unwrap();
1252 let lambda_annotations = annotations.lambda_annotations.unwrap();
1253 assert_eq!(
1254 lambda_annotations.runtime,
1255 LambdaRuntime::Custom("rust-runtime-1.0".to_string())
1256 );
1257 }
1258}