Skip to main content

legalis_dsl/
codegen.rs

1//! Code generation framework for translating legal statutes to other languages.
2//!
3//! This module provides a pluggable architecture for generating code in various
4//! target languages from the legal DSL AST.
5
6use crate::DslResult;
7use crate::ast::{ConditionNode, ConditionValue, LegalDocument, StatuteNode, TemporalField};
8use std::fmt::Write;
9
10/// Helper function to convert TemporalField to a string representation.
11fn temporal_field_to_string(field: &TemporalField) -> String {
12    match field {
13        TemporalField::CurrentDate => "current_date".to_string(),
14        TemporalField::DateField(name) => name.clone(),
15    }
16}
17
18/// Trait for code generators that can translate legal documents.
19pub trait CodeGenerator {
20    /// Generates code for the entire document.
21    fn generate(&self, doc: &LegalDocument) -> DslResult<String>;
22
23    /// Returns the target language name.
24    fn target_language(&self) -> &str;
25
26    /// Returns file extension for generated code.
27    fn file_extension(&self) -> &str;
28}
29
30/// SQL generator for creating database schemas and queries from statutes.
31pub struct SqlGenerator {
32    /// Use CHECK constraints for conditions
33    pub use_check_constraints: bool,
34    /// Generate INSERT statements for default values
35    pub generate_defaults: bool,
36}
37
38impl Default for SqlGenerator {
39    fn default() -> Self {
40        Self {
41            use_check_constraints: true,
42            generate_defaults: true,
43        }
44    }
45}
46
47impl SqlGenerator {
48    /// Creates a new SQL generator.
49    pub fn new() -> Self {
50        Self::default()
51    }
52
53    /// Generates a table name from statute ID.
54    fn table_name(&self, id: &str) -> String {
55        id.replace('-', "_")
56    }
57
58    /// Generates SQL condition expression.
59    fn generate_condition(&self, condition: &ConditionNode) -> DslResult<String> {
60        match condition {
61            ConditionNode::Comparison {
62                field,
63                operator,
64                value,
65            } => {
66                let val = self.format_value(value)?;
67                Ok(format!("{} {} {}", field, operator, val))
68            }
69            ConditionNode::HasAttribute { key } => Ok(format!("{} IS NOT NULL", key)),
70            ConditionNode::Between { field, min, max } => {
71                let min_val = self.format_value(min)?;
72                let max_val = self.format_value(max)?;
73                Ok(format!("{} BETWEEN {} AND {}", field, min_val, max_val))
74            }
75            ConditionNode::In { field, values } => {
76                let vals: Result<Vec<_>, _> = values.iter().map(|v| self.format_value(v)).collect();
77                let vals = vals?;
78                Ok(format!("{} IN ({})", field, vals.join(", ")))
79            }
80            ConditionNode::Like { field, pattern } => Ok(format!("{} LIKE '{}'", field, pattern)),
81            ConditionNode::And(left, right) => {
82                let left_sql = self.generate_condition(left)?;
83                let right_sql = self.generate_condition(right)?;
84                Ok(format!("({} AND {})", left_sql, right_sql))
85            }
86            ConditionNode::Or(left, right) => {
87                let left_sql = self.generate_condition(left)?;
88                let right_sql = self.generate_condition(right)?;
89                Ok(format!("({} OR {})", left_sql, right_sql))
90            }
91            ConditionNode::Not(inner) => {
92                let inner_sql = self.generate_condition(inner)?;
93                Ok(format!("NOT ({})", inner_sql))
94            }
95            ConditionNode::InRange {
96                field,
97                min,
98                max,
99                inclusive_min,
100                inclusive_max,
101            } => {
102                let min_val = self.format_value(min)?;
103                let max_val = self.format_value(max)?;
104                let min_op = if *inclusive_min { ">=" } else { ">" };
105                let max_op = if *inclusive_max { "<=" } else { "<" };
106                Ok(format!(
107                    "({} {} {} AND {} {} {})",
108                    field, min_op, min_val, field, max_op, max_val
109                ))
110            }
111            ConditionNode::NotInRange {
112                field,
113                min,
114                max,
115                inclusive_min,
116                inclusive_max,
117            } => {
118                let min_val = self.format_value(min)?;
119                let max_val = self.format_value(max)?;
120                let min_op = if *inclusive_min { "<" } else { "<=" };
121                let max_op = if *inclusive_max { ">" } else { ">=" };
122                Ok(format!(
123                    "({} {} {} OR {} {} {})",
124                    field, min_op, min_val, field, max_op, max_val
125                ))
126            }
127            ConditionNode::Matches {
128                field,
129                regex_pattern: _,
130            } => {
131                // SQL doesn't have universal regex support, use LIKE as fallback
132                Ok(format!("{} LIKE '%'", field))
133            }
134            ConditionNode::TemporalComparison {
135                field,
136                operator,
137                value,
138            } => {
139                let val = self.format_value(value)?;
140                Ok(format!("{:?} {} {}", field, operator, val))
141            }
142        }
143    }
144
145    /// Formats a condition value for SQL.
146    fn format_value(&self, value: &ConditionValue) -> DslResult<String> {
147        match value {
148            ConditionValue::Number(n) => Ok(n.to_string()),
149            ConditionValue::String(s) => Ok(format!("'{}'", s.replace('\'', "''"))),
150            ConditionValue::Boolean(b) => Ok(if *b {
151                "TRUE".to_string()
152            } else {
153                "FALSE".to_string()
154            }),
155            ConditionValue::Date(d) => Ok(format!("'{}'", d)),
156            ConditionValue::SetExpr(_) => Ok("NULL".to_string()), // Set expressions not directly supported in SQL
157        }
158    }
159
160    /// Generates CREATE TABLE statement for a statute.
161    fn generate_table(&self, statute: &StatuteNode) -> DslResult<String> {
162        let mut sql = String::new();
163        let table_name = self.table_name(&statute.id);
164
165        writeln!(&mut sql, "-- Statute: {}", statute.title).unwrap();
166        writeln!(&mut sql, "CREATE TABLE {} (", table_name).unwrap();
167        writeln!(&mut sql, "    id SERIAL PRIMARY KEY,").unwrap();
168
169        // Extract fields from conditions
170        let mut fields = std::collections::HashSet::new();
171        for condition in &statute.conditions {
172            self.extract_fields(condition, &mut fields);
173        }
174
175        for field in &fields {
176            writeln!(&mut sql, "    {} VARCHAR(255),", field).unwrap();
177        }
178
179        // Add effect tracking
180        writeln!(&mut sql, "    applied BOOLEAN DEFAULT FALSE,").unwrap();
181        writeln!(&mut sql, "    applied_at TIMESTAMP").unwrap();
182
183        // Add CHECK constraints if enabled
184        if self.use_check_constraints && !statute.conditions.is_empty() {
185            write!(&mut sql, "    CONSTRAINT check_{} CHECK (", table_name).unwrap();
186            let conditions: Result<Vec<_>, _> = statute
187                .conditions
188                .iter()
189                .map(|c| self.generate_condition(c))
190                .collect();
191            let conditions = conditions?;
192            write!(&mut sql, "{}", conditions.join(" AND ")).unwrap();
193            writeln!(&mut sql, ")").unwrap();
194        }
195
196        writeln!(&mut sql, ");").unwrap();
197        writeln!(&mut sql).unwrap();
198
199        Ok(sql)
200    }
201
202    /// Extracts field names from conditions.
203    #[allow(clippy::only_used_in_recursion)]
204    fn extract_fields(
205        &self,
206        condition: &ConditionNode,
207        fields: &mut std::collections::HashSet<String>,
208    ) {
209        match condition {
210            ConditionNode::Comparison { field, .. }
211            | ConditionNode::Between { field, .. }
212            | ConditionNode::In { field, .. }
213            | ConditionNode::Like { field, .. }
214            | ConditionNode::Matches { field, .. }
215            | ConditionNode::InRange { field, .. }
216            | ConditionNode::NotInRange { field, .. } => {
217                fields.insert(field.clone());
218            }
219            ConditionNode::HasAttribute { key } => {
220                fields.insert(key.clone());
221            }
222            ConditionNode::And(left, right) | ConditionNode::Or(left, right) => {
223                self.extract_fields(left, fields);
224                self.extract_fields(right, fields);
225            }
226            ConditionNode::Not(inner) => {
227                self.extract_fields(inner, fields);
228            }
229            ConditionNode::TemporalComparison { .. } => {
230                // Temporal comparisons might need special handling
231            }
232        }
233    }
234}
235
236impl CodeGenerator for SqlGenerator {
237    fn generate(&self, doc: &LegalDocument) -> DslResult<String> {
238        let mut sql = String::new();
239
240        writeln!(&mut sql, "-- Generated SQL from Legal DSL").unwrap();
241        writeln!(&mut sql, "-- Total statutes: {}", doc.statutes.len()).unwrap();
242        writeln!(&mut sql).unwrap();
243
244        for statute in &doc.statutes {
245            let table_sql = self.generate_table(statute)?;
246            sql.push_str(&table_sql);
247        }
248
249        Ok(sql)
250    }
251
252    fn target_language(&self) -> &str {
253        "SQL"
254    }
255
256    fn file_extension(&self) -> &str {
257        "sql"
258    }
259}
260
261/// Python generator for creating Python functions from statutes.
262pub struct PythonGenerator {
263    /// Use type hints
264    pub use_type_hints: bool,
265    /// Generate docstrings
266    pub generate_docstrings: bool,
267}
268
269impl Default for PythonGenerator {
270    fn default() -> Self {
271        Self {
272            use_type_hints: true,
273            generate_docstrings: true,
274        }
275    }
276}
277
278impl PythonGenerator {
279    /// Creates a new Python generator.
280    pub fn new() -> Self {
281        Self::default()
282    }
283
284    /// Generates a Python function name from statute ID.
285    fn function_name(&self, id: &str) -> String {
286        id.replace('-', "_").to_lowercase()
287    }
288
289    /// Generates Python condition expression.
290    #[allow(clippy::only_used_in_recursion)]
291    fn generate_condition(&self, condition: &ConditionNode, indent: usize) -> DslResult<String> {
292        match condition {
293            ConditionNode::Comparison {
294                field,
295                operator,
296                value,
297            } => {
298                let py_op = match operator.as_str() {
299                    "=" | "==" => "==",
300                    op => op,
301                };
302                let val = self.format_value(value)?;
303                Ok(format!("{}.{} {} {}", "obj", field, py_op, val))
304            }
305            ConditionNode::HasAttribute { key } => Ok(format!(
306                "hasattr(obj, '{}') and obj.{} is not None",
307                key, key
308            )),
309            ConditionNode::Between { field, min, max } => {
310                let min_val = self.format_value(min)?;
311                let max_val = self.format_value(max)?;
312                Ok(format!("{} <= obj.{} <= {}", min_val, field, max_val))
313            }
314            ConditionNode::In { field, values } => {
315                let vals: Result<Vec<_>, _> = values.iter().map(|v| self.format_value(v)).collect();
316                let vals = vals?;
317                Ok(format!("obj.{} in [{}]", field, vals.join(", ")))
318            }
319            ConditionNode::And(left, right) => {
320                let left_py = self.generate_condition(left, indent)?;
321                let right_py = self.generate_condition(right, indent)?;
322                Ok(format!("({} and {})", left_py, right_py))
323            }
324            ConditionNode::Or(left, right) => {
325                let left_py = self.generate_condition(left, indent)?;
326                let right_py = self.generate_condition(right, indent)?;
327                Ok(format!("({} or {})", left_py, right_py))
328            }
329            ConditionNode::Not(inner) => {
330                let inner_py = self.generate_condition(inner, indent)?;
331                Ok(format!("not ({})", inner_py))
332            }
333            _ => Ok("True".to_string()),
334        }
335    }
336
337    /// Formats a condition value for Python.
338    fn format_value(&self, value: &ConditionValue) -> DslResult<String> {
339        match value {
340            ConditionValue::Number(n) => Ok(n.to_string()),
341            ConditionValue::String(s) => Ok(format!("'{}'", s.replace('\'', "\\'"))),
342            ConditionValue::Boolean(b) => Ok(if *b {
343                "True".to_string()
344            } else {
345                "False".to_string()
346            }),
347            ConditionValue::Date(d) => Ok(format!("'{}'", d)),
348            ConditionValue::SetExpr(_) => Ok("None".to_string()), // Set expressions not directly supported
349        }
350    }
351
352    /// Generates a Python function for a statute.
353    fn generate_function(&self, statute: &StatuteNode) -> DslResult<String> {
354        let mut py = String::new();
355        let func_name = self.function_name(&statute.id);
356
357        // Function signature
358        if self.use_type_hints {
359            writeln!(&mut py, "def {}(obj: Any) -> bool:", func_name).unwrap();
360        } else {
361            writeln!(&mut py, "def {}(obj):", func_name).unwrap();
362        }
363
364        // Docstring
365        if self.generate_docstrings {
366            writeln!(&mut py, "    \"\"\"{}\"\"\"", statute.title).unwrap();
367        }
368
369        // Generate condition check
370        if !statute.conditions.is_empty() {
371            let conditions: Result<Vec<_>, _> = statute
372                .conditions
373                .iter()
374                .map(|c| self.generate_condition(c, 1))
375                .collect();
376            let conditions = conditions?;
377            writeln!(&mut py, "    return {}", conditions.join(" and ")).unwrap();
378        } else {
379            writeln!(&mut py, "    return True").unwrap();
380        }
381
382        writeln!(&mut py).unwrap();
383        Ok(py)
384    }
385}
386
387impl CodeGenerator for PythonGenerator {
388    fn generate(&self, doc: &LegalDocument) -> DslResult<String> {
389        let mut py = String::new();
390
391        writeln!(&mut py, "# Generated Python from Legal DSL").unwrap();
392        writeln!(&mut py, "# Total statutes: {}", doc.statutes.len()).unwrap();
393        writeln!(&mut py, "from typing import Any").unwrap();
394        writeln!(&mut py).unwrap();
395
396        for statute in &doc.statutes {
397            let func_py = self.generate_function(statute)?;
398            py.push_str(&func_py);
399        }
400
401        Ok(py)
402    }
403
404    fn target_language(&self) -> &str {
405        "Python"
406    }
407
408    fn file_extension(&self) -> &str {
409        "py"
410    }
411}
412
413/// Prolog generator for creating logic predicates from statutes.
414pub struct PrologGenerator {
415    /// Generate module declarations
416    pub generate_module: bool,
417    /// Use dynamic predicates
418    pub use_dynamic: bool,
419}
420
421impl Default for PrologGenerator {
422    fn default() -> Self {
423        Self {
424            generate_module: true,
425            use_dynamic: false,
426        }
427    }
428}
429
430impl PrologGenerator {
431    /// Creates a new Prolog generator.
432    pub fn new() -> Self {
433        Self::default()
434    }
435
436    /// Generates a Prolog predicate name from statute ID.
437    fn predicate_name(&self, id: &str) -> String {
438        id.replace('-', "_").to_lowercase()
439    }
440
441    /// Generates Prolog condition expression.
442    #[allow(clippy::only_used_in_recursion)]
443    fn generate_condition(&self, condition: &ConditionNode, var: &str) -> DslResult<String> {
444        match condition {
445            ConditionNode::Comparison {
446                field,
447                operator,
448                value,
449            } => {
450                let pl_op = match operator.as_str() {
451                    "=" | "==" => "=",
452                    "!=" => "\\=",
453                    ">=" => ">=",
454                    "<=" => "=<", // Prolog uses =< instead of <=
455                    ">" => ">",
456                    "<" => "<",
457                    _ => "=",
458                };
459                let val = self.format_value(value)?;
460                Ok(format!("{}_{} {} {}", var, field, pl_op, val))
461            }
462            ConditionNode::HasAttribute { key } => Ok(format!(
463                "nonvar({}_{}) , {}_{} \\= null",
464                var, key, var, key
465            )),
466            ConditionNode::Between { field, min, max } => {
467                let min_val = self.format_value(min)?;
468                let max_val = self.format_value(max)?;
469                Ok(format!(
470                    "{}_{} >= {} , {}_{} =< {}",
471                    var, field, min_val, var, field, max_val
472                ))
473            }
474            ConditionNode::In { field, values } => {
475                let vals: Result<Vec<_>, _> = values.iter().map(|v| self.format_value(v)).collect();
476                let vals = vals?;
477                Ok(format!("member({}_{}, [{}])", var, field, vals.join(", ")))
478            }
479            ConditionNode::Like { field, pattern } => {
480                // Prolog doesn't have built-in LIKE, use atom_string and sub_string
481                Ok(format!(
482                    "atom_string({}_{}, Str), sub_string(Str, _, _, _, \"{}\")",
483                    var, field, pattern
484                ))
485            }
486            ConditionNode::And(left, right) => {
487                let left_pl = self.generate_condition(left, var)?;
488                let right_pl = self.generate_condition(right, var)?;
489                Ok(format!("({} , {})", left_pl, right_pl))
490            }
491            ConditionNode::Or(left, right) => {
492                let left_pl = self.generate_condition(left, var)?;
493                let right_pl = self.generate_condition(right, var)?;
494                Ok(format!("({} ; {})", left_pl, right_pl))
495            }
496            ConditionNode::Not(inner) => {
497                let inner_pl = self.generate_condition(inner, var)?;
498                Ok(format!("\\+ ({})", inner_pl))
499            }
500            ConditionNode::InRange {
501                field,
502                min,
503                max,
504                inclusive_min,
505                inclusive_max,
506            } => {
507                let min_val = self.format_value(min)?;
508                let max_val = self.format_value(max)?;
509                let min_op = if *inclusive_min { ">=" } else { ">" };
510                let max_op = if *inclusive_max { "=<" } else { "<" };
511                Ok(format!(
512                    "{}_{} {} {} , {}_{} {} {}",
513                    var, field, min_op, min_val, var, field, max_op, max_val
514                ))
515            }
516            ConditionNode::NotInRange {
517                field,
518                min,
519                max,
520                inclusive_min,
521                inclusive_max,
522            } => {
523                let min_val = self.format_value(min)?;
524                let max_val = self.format_value(max)?;
525                let min_op = if *inclusive_min { "<" } else { "=<" };
526                let max_op = if *inclusive_max { ">" } else { ">=" };
527                Ok(format!(
528                    "({}_{} {} {} ; {}_{} {} {})",
529                    var, field, min_op, min_val, var, field, max_op, max_val
530                ))
531            }
532            ConditionNode::Matches {
533                field,
534                regex_pattern,
535            } => {
536                // Prolog regex support varies, use simple pattern matching
537                Ok(format!(
538                    "atom_string({}_{}, Str), re_match(\"{}\"^^_, Str)",
539                    var, field, regex_pattern
540                ))
541            }
542            ConditionNode::TemporalComparison {
543                field,
544                operator,
545                value,
546            } => {
547                let val = self.format_value(value)?;
548                let pl_op = match operator.as_str() {
549                    "=" | "==" => "=",
550                    "!=" => "\\=",
551                    ">=" => ">=",
552                    "<=" => "=<",
553                    ">" => ">",
554                    "<" => "<",
555                    _ => "=",
556                };
557                Ok(format!("{:?}_{} {} {}", field, var, pl_op, val))
558            }
559        }
560    }
561
562    /// Formats a condition value for Prolog.
563    fn format_value(&self, value: &ConditionValue) -> DslResult<String> {
564        match value {
565            ConditionValue::Number(n) => Ok(n.to_string()),
566            ConditionValue::String(s) => Ok(format!("'{}'", s.replace('\'', "\\'"))),
567            ConditionValue::Boolean(b) => Ok(if *b {
568                "true".to_string()
569            } else {
570                "false".to_string()
571            }),
572            ConditionValue::Date(d) => Ok(format!("'{}'", d)),
573            ConditionValue::SetExpr(_) => Ok("[]".to_string()), // Empty list for unsupported set expressions
574        }
575    }
576
577    /// Generates a Prolog predicate for a statute.
578    fn generate_predicate(&self, statute: &StatuteNode) -> DslResult<String> {
579        let mut pl = String::new();
580        let pred_name = self.predicate_name(&statute.id);
581
582        // Comment with statute title
583        writeln!(&mut pl, "% {}", statute.title).unwrap();
584
585        // Generate required predicates if any
586        if !statute.requires.is_empty() {
587            writeln!(&mut pl, "% Requires: {}", statute.requires.join(", ")).unwrap();
588        }
589
590        // Predicate head
591        write!(&mut pl, "{}(Entity) :- ", pred_name).unwrap();
592
593        // Generate condition body
594        if !statute.conditions.is_empty() {
595            let conditions: Result<Vec<_>, _> = statute
596                .conditions
597                .iter()
598                .map(|c| self.generate_condition(c, "Entity"))
599                .collect();
600            let conditions = conditions?;
601
602            // Join conditions with comma (AND)
603            let body = conditions.join(" , ");
604            writeln!(&mut pl, "{}", body).unwrap();
605        } else {
606            writeln!(&mut pl, "true").unwrap();
607        }
608
609        // Add required statute checks
610        for req in &statute.requires {
611            let req_pred = self.predicate_name(req);
612            writeln!(&mut pl, "    , {}(Entity)", req_pred).unwrap();
613        }
614
615        writeln!(&mut pl, ".").unwrap();
616        writeln!(&mut pl).unwrap();
617
618        // Generate effect predicates
619        for (idx, effect) in statute.effects.iter().enumerate() {
620            writeln!(
621                &mut pl,
622                "% Effect {}: {} - {}",
623                idx + 1,
624                effect.effect_type,
625                effect.description
626            )
627            .unwrap();
628            writeln!(
629                &mut pl,
630                "{}_effect_{}(Entity, '{}') :- {}(Entity).",
631                pred_name,
632                idx + 1,
633                effect.description,
634                pred_name
635            )
636            .unwrap();
637            writeln!(&mut pl).unwrap();
638        }
639
640        Ok(pl)
641    }
642}
643
644impl CodeGenerator for PrologGenerator {
645    fn generate(&self, doc: &LegalDocument) -> DslResult<String> {
646        let mut pl = String::new();
647
648        writeln!(&mut pl, "% Generated Prolog from Legal DSL").unwrap();
649        writeln!(&mut pl, "% Total statutes: {}", doc.statutes.len()).unwrap();
650        writeln!(&mut pl).unwrap();
651
652        if self.generate_module {
653            writeln!(&mut pl, ":- module(legal_statutes, []).").unwrap();
654            writeln!(&mut pl).unwrap();
655        }
656
657        if self.use_dynamic {
658            for statute in &doc.statutes {
659                let pred_name = self.predicate_name(&statute.id);
660                writeln!(&mut pl, ":- dynamic {}/1.", pred_name).unwrap();
661            }
662            writeln!(&mut pl).unwrap();
663        }
664
665        for statute in &doc.statutes {
666            let pred_pl = self.generate_predicate(statute)?;
667            pl.push_str(&pred_pl);
668        }
669
670        Ok(pl)
671    }
672
673    fn target_language(&self) -> &str {
674        "Prolog"
675    }
676
677    fn file_extension(&self) -> &str {
678        "pl"
679    }
680}
681
682/// TypeScript/JavaScript generator for creating type-safe validation functions.
683pub struct TypeScriptGenerator {
684    /// Generate TypeScript (true) or JavaScript (false)
685    pub use_typescript: bool,
686    /// Generate ES6 modules
687    pub use_es6_modules: bool,
688}
689
690impl Default for TypeScriptGenerator {
691    fn default() -> Self {
692        Self {
693            use_typescript: true,
694            use_es6_modules: true,
695        }
696    }
697}
698
699impl TypeScriptGenerator {
700    /// Creates a new TypeScript generator.
701    pub fn new() -> Self {
702        Self::default()
703    }
704
705    /// Generates function name from statute ID.
706    fn function_name(&self, id: &str) -> String {
707        id.replace('-', "_")
708    }
709
710    /// Generates TypeScript/JavaScript condition expression.
711    fn generate_condition(&self, condition: &ConditionNode, entity_var: &str) -> DslResult<String> {
712        match condition {
713            ConditionNode::Comparison {
714                field,
715                operator,
716                value,
717            } => {
718                let val = self.format_value(value)?;
719                Ok(format!("{}.{} {} {}", entity_var, field, operator, val))
720            }
721            ConditionNode::HasAttribute { key } => Ok(format!(
722                "{}.{} !== undefined && {}.{} !== null",
723                entity_var, key, entity_var, key
724            )),
725            ConditionNode::Between { field, min, max } => {
726                let min_val = self.format_value(min)?;
727                let max_val = self.format_value(max)?;
728                Ok(format!(
729                    "{}.{} >= {} && {}.{} <= {}",
730                    entity_var, field, min_val, entity_var, field, max_val
731                ))
732            }
733            ConditionNode::In { field, values } => {
734                let vals: Result<Vec<_>, _> = values.iter().map(|v| self.format_value(v)).collect();
735                let vals = vals?;
736                Ok(format!(
737                    "[{}].includes({}.{})",
738                    vals.join(", "),
739                    entity_var,
740                    field
741                ))
742            }
743            ConditionNode::Like { field, pattern } => Ok(format!(
744                "/{}/i.test({}.{})",
745                pattern.replace('%', ".*"),
746                entity_var,
747                field
748            )),
749            ConditionNode::And(left, right) => {
750                let left_js = self.generate_condition(left, entity_var)?;
751                let right_js = self.generate_condition(right, entity_var)?;
752                Ok(format!("({} && {})", left_js, right_js))
753            }
754            ConditionNode::Or(left, right) => {
755                let left_js = self.generate_condition(left, entity_var)?;
756                let right_js = self.generate_condition(right, entity_var)?;
757                Ok(format!("({} || {})", left_js, right_js))
758            }
759            ConditionNode::Not(inner) => {
760                let inner_js = self.generate_condition(inner, entity_var)?;
761                Ok(format!("!({})", inner_js))
762            }
763            ConditionNode::InRange {
764                field,
765                min,
766                max,
767                inclusive_min,
768                inclusive_max,
769            } => {
770                let min_val = self.format_value(min)?;
771                let max_val = self.format_value(max)?;
772                let min_op = if *inclusive_min { ">=" } else { ">" };
773                let max_op = if *inclusive_max { "<=" } else { "<" };
774                Ok(format!(
775                    "{}.{} {} {} && {}.{} {} {}",
776                    entity_var, field, min_op, min_val, entity_var, field, max_op, max_val
777                ))
778            }
779            ConditionNode::NotInRange {
780                field,
781                min,
782                max,
783                inclusive_min,
784                inclusive_max,
785            } => {
786                let min_val = self.format_value(min)?;
787                let max_val = self.format_value(max)?;
788                let min_op = if *inclusive_min { "<" } else { "<=" };
789                let max_op = if *inclusive_max { ">" } else { ">=" };
790                Ok(format!(
791                    "{}.{} {} {} || {}.{} {} {}",
792                    entity_var, field, min_op, min_val, entity_var, field, max_op, max_val
793                ))
794            }
795            ConditionNode::Matches {
796                field,
797                regex_pattern,
798            } => Ok(format!(
799                "/{}/i.test({}.{})",
800                regex_pattern, entity_var, field
801            )),
802            ConditionNode::TemporalComparison {
803                field,
804                operator,
805                value,
806            } => {
807                let val = self.format_value(value)?;
808                let field_str = temporal_field_to_string(field);
809                Ok(format!(
810                    "new Date({}.{}) {} new Date({})",
811                    entity_var, field_str, operator, val
812                ))
813            }
814        }
815    }
816
817    /// Formats a condition value for TypeScript/JavaScript.
818    fn format_value(&self, value: &ConditionValue) -> DslResult<String> {
819        match value {
820            ConditionValue::Number(n) => Ok(n.to_string()),
821            ConditionValue::String(s) => Ok(format!("\"{}\"", s.replace('"', "\\\""))),
822            ConditionValue::Boolean(b) => Ok(b.to_string()),
823            ConditionValue::Date(d) => Ok(format!("\"{}\"", d)),
824            ConditionValue::SetExpr(_) => Ok("[]".to_string()),
825        }
826    }
827
828    /// Generates validation function for a statute.
829    fn generate_function(&self, statute: &StatuteNode) -> DslResult<String> {
830        let mut code = String::new();
831        let fn_name = self.function_name(&statute.id);
832
833        // Add JSDoc comment
834        writeln!(&mut code, "/**").unwrap();
835        writeln!(&mut code, " * {}", statute.title).unwrap();
836        if !statute.conditions.is_empty() {
837            writeln!(
838                &mut code,
839                " * @param {{any}} entity - The entity to validate"
840            )
841            .unwrap();
842            writeln!(
843                &mut code,
844                " * @returns {{boolean}} - Whether the statute applies"
845            )
846            .unwrap();
847        }
848        writeln!(&mut code, " */").unwrap();
849
850        // Function signature
851        if self.use_typescript {
852            write!(
853                &mut code,
854                "export function {}(entity: any): boolean ",
855                fn_name
856            )
857            .unwrap();
858        } else {
859            write!(&mut code, "export function {}(entity) ", fn_name).unwrap();
860        }
861
862        writeln!(&mut code, "{{").unwrap();
863
864        if statute.conditions.is_empty() {
865            writeln!(&mut code, "  return true;").unwrap();
866        } else {
867            write!(&mut code, "  return ").unwrap();
868            let conditions: Result<Vec<_>, _> = statute
869                .conditions
870                .iter()
871                .map(|c| self.generate_condition(c, "entity"))
872                .collect();
873            let conditions = conditions?;
874            writeln!(&mut code, "{};", conditions.join(" && ")).unwrap();
875        }
876
877        writeln!(&mut code, "}}").unwrap();
878        writeln!(&mut code).unwrap();
879
880        Ok(code)
881    }
882}
883
884impl CodeGenerator for TypeScriptGenerator {
885    fn generate(&self, doc: &LegalDocument) -> DslResult<String> {
886        let mut code = String::new();
887
888        writeln!(
889            &mut code,
890            "// Generated TypeScript/JavaScript from Legal DSL"
891        )
892        .unwrap();
893        writeln!(&mut code, "// Total statutes: {}", doc.statutes.len()).unwrap();
894        writeln!(&mut code).unwrap();
895
896        for statute in &doc.statutes {
897            let fn_code = self.generate_function(statute)?;
898            code.push_str(&fn_code);
899        }
900
901        Ok(code)
902    }
903
904    fn target_language(&self) -> &str {
905        if self.use_typescript {
906            "TypeScript"
907        } else {
908            "JavaScript"
909        }
910    }
911
912    fn file_extension(&self) -> &str {
913        if self.use_typescript { "ts" } else { "js" }
914    }
915}
916
917/// Rust generator for creating type-safe validation functions.
918pub struct RustGenerator {
919    /// Use serde for JSON serialization
920    pub use_serde: bool,
921}
922
923impl Default for RustGenerator {
924    fn default() -> Self {
925        Self { use_serde: true }
926    }
927}
928
929impl RustGenerator {
930    /// Creates a new Rust generator.
931    pub fn new() -> Self {
932        Self::default()
933    }
934
935    /// Generates function name from statute ID.
936    fn function_name(&self, id: &str) -> String {
937        id.replace('-', "_")
938    }
939
940    /// Generates Rust condition expression.
941    fn generate_condition(&self, condition: &ConditionNode, entity_var: &str) -> DslResult<String> {
942        match condition {
943            ConditionNode::Comparison {
944                field,
945                operator,
946                value,
947            } => {
948                let val = self.format_value(value)?;
949                Ok(format!("{}.{} {} {}", entity_var, field, operator, val))
950            }
951            ConditionNode::HasAttribute { key } => Ok(format!("{}.{}.is_some()", entity_var, key)),
952            ConditionNode::Between { field, min, max } => {
953                let min_val = self.format_value(min)?;
954                let max_val = self.format_value(max)?;
955                Ok(format!(
956                    "{}.{} >= {} && {}.{} <= {}",
957                    entity_var, field, min_val, entity_var, field, max_val
958                ))
959            }
960            ConditionNode::In { field, values } => {
961                let vals: Result<Vec<_>, _> = values.iter().map(|v| self.format_value(v)).collect();
962                let vals = vals?;
963                Ok(format!(
964                    "[{}].contains(&{}.{})",
965                    vals.join(", "),
966                    entity_var,
967                    field
968                ))
969            }
970            ConditionNode::Like { field, pattern } => Ok(format!(
971                "{}.{}.contains(\"{}\")",
972                entity_var,
973                field,
974                pattern.replace('%', "")
975            )),
976            ConditionNode::And(left, right) => {
977                let left_rs = self.generate_condition(left, entity_var)?;
978                let right_rs = self.generate_condition(right, entity_var)?;
979                Ok(format!("({} && {})", left_rs, right_rs))
980            }
981            ConditionNode::Or(left, right) => {
982                let left_rs = self.generate_condition(left, entity_var)?;
983                let right_rs = self.generate_condition(right, entity_var)?;
984                Ok(format!("({} || {})", left_rs, right_rs))
985            }
986            ConditionNode::Not(inner) => {
987                let inner_rs = self.generate_condition(inner, entity_var)?;
988                Ok(format!("!({})", inner_rs))
989            }
990            ConditionNode::InRange {
991                field,
992                min,
993                max,
994                inclusive_min,
995                inclusive_max,
996            } => {
997                let min_val = self.format_value(min)?;
998                let max_val = self.format_value(max)?;
999                let min_op = if *inclusive_min { ">=" } else { ">" };
1000                let max_op = if *inclusive_max { "<=" } else { "<" };
1001                Ok(format!(
1002                    "{}.{} {} {} && {}.{} {} {}",
1003                    entity_var, field, min_op, min_val, entity_var, field, max_op, max_val
1004                ))
1005            }
1006            ConditionNode::NotInRange {
1007                field,
1008                min,
1009                max,
1010                inclusive_min,
1011                inclusive_max,
1012            } => {
1013                let min_val = self.format_value(min)?;
1014                let max_val = self.format_value(max)?;
1015                let min_op = if *inclusive_min { "<" } else { "<=" };
1016                let max_op = if *inclusive_max { ">" } else { ">=" };
1017                Ok(format!(
1018                    "{}.{} {} {} || {}.{} {} {}",
1019                    entity_var, field, min_op, min_val, entity_var, field, max_op, max_val
1020                ))
1021            }
1022            ConditionNode::Matches {
1023                field,
1024                regex_pattern,
1025            } => Ok(format!(
1026                "Regex::new(r\"{}\").unwrap().is_match(&{}.{})",
1027                regex_pattern, entity_var, field
1028            )),
1029            ConditionNode::TemporalComparison {
1030                field,
1031                operator,
1032                value,
1033            } => {
1034                let val = self.format_value(value)?;
1035                let field_str = temporal_field_to_string(field);
1036                Ok(format!("{}.{} {} {}", entity_var, field_str, operator, val))
1037            }
1038        }
1039    }
1040
1041    /// Formats a condition value for Rust.
1042    fn format_value(&self, value: &ConditionValue) -> DslResult<String> {
1043        match value {
1044            ConditionValue::Number(n) => Ok(n.to_string()),
1045            ConditionValue::String(s) => Ok(format!("\"{}\"", s.replace('"', "\\\""))),
1046            ConditionValue::Boolean(b) => Ok(b.to_string()),
1047            ConditionValue::Date(d) => Ok(format!("\"{}\"", d)),
1048            ConditionValue::SetExpr(_) => Ok("vec![]".to_string()),
1049        }
1050    }
1051
1052    /// Generates validation function for a statute.
1053    fn generate_function(&self, statute: &StatuteNode) -> DslResult<String> {
1054        let mut code = String::new();
1055        let fn_name = self.function_name(&statute.id);
1056
1057        writeln!(&mut code, "/// {}", statute.title).unwrap();
1058        writeln!(&mut code, "#[allow(dead_code)]").unwrap();
1059        write!(&mut code, "pub fn {}<T>(entity: &T) -> bool ", fn_name).unwrap();
1060        writeln!(&mut code, "{{").unwrap();
1061
1062        if statute.conditions.is_empty() {
1063            writeln!(&mut code, "    true").unwrap();
1064        } else {
1065            write!(&mut code, "    ").unwrap();
1066            let conditions: Result<Vec<_>, _> = statute
1067                .conditions
1068                .iter()
1069                .map(|c| self.generate_condition(c, "entity"))
1070                .collect();
1071            let conditions = conditions?;
1072            writeln!(&mut code, "{}", conditions.join(" && ")).unwrap();
1073        }
1074
1075        writeln!(&mut code, "}}").unwrap();
1076        writeln!(&mut code).unwrap();
1077
1078        Ok(code)
1079    }
1080}
1081
1082impl CodeGenerator for RustGenerator {
1083    fn generate(&self, doc: &LegalDocument) -> DslResult<String> {
1084        let mut code = String::new();
1085
1086        writeln!(&mut code, "// Generated Rust code from Legal DSL").unwrap();
1087        writeln!(&mut code, "// Total statutes: {}", doc.statutes.len()).unwrap();
1088        writeln!(&mut code).unwrap();
1089
1090        if self.use_serde {
1091            writeln!(&mut code, "use serde::{{Serialize, Deserialize}};").unwrap();
1092        }
1093        writeln!(&mut code, "use regex::Regex;").unwrap();
1094        writeln!(&mut code).unwrap();
1095
1096        for statute in &doc.statutes {
1097            let fn_code = self.generate_function(statute)?;
1098            code.push_str(&fn_code);
1099        }
1100
1101        Ok(code)
1102    }
1103
1104    fn target_language(&self) -> &str {
1105        "Rust"
1106    }
1107
1108    fn file_extension(&self) -> &str {
1109        "rs"
1110    }
1111}
1112
1113/// Go generator for creating validation functions.
1114pub struct GoGenerator {
1115    /// Package name for generated code
1116    pub package_name: String,
1117}
1118
1119impl Default for GoGenerator {
1120    fn default() -> Self {
1121        Self {
1122            package_name: "statutes".to_string(),
1123        }
1124    }
1125}
1126
1127impl GoGenerator {
1128    /// Creates a new Go generator.
1129    pub fn new() -> Self {
1130        Self::default()
1131    }
1132
1133    /// Generates function name from statute ID (capitalize first letter).
1134    fn function_name(&self, id: &str) -> String {
1135        let name = id.replace('-', "_");
1136        let mut chars = name.chars();
1137        match chars.next() {
1138            None => String::new(),
1139            Some(first) => first.to_uppercase().chain(chars).collect(),
1140        }
1141    }
1142
1143    /// Generates Go condition expression.
1144    fn generate_condition(&self, condition: &ConditionNode, entity_var: &str) -> DslResult<String> {
1145        match condition {
1146            ConditionNode::Comparison {
1147                field,
1148                operator,
1149                value,
1150            } => {
1151                let val = self.format_value(value)?;
1152                Ok(format!("{}.{} {} {}", entity_var, field, operator, val))
1153            }
1154            ConditionNode::HasAttribute { key } => Ok(format!("{}.{} != nil", entity_var, key)),
1155            ConditionNode::Between { field, min, max } => {
1156                let min_val = self.format_value(min)?;
1157                let max_val = self.format_value(max)?;
1158                Ok(format!(
1159                    "{}.{} >= {} && {}.{} <= {}",
1160                    entity_var, field, min_val, entity_var, field, max_val
1161                ))
1162            }
1163            ConditionNode::In { field, values } => {
1164                let vals: Result<Vec<_>, _> = values.iter().map(|v| self.format_value(v)).collect();
1165                let vals = vals?;
1166                Ok(format!(
1167                    "contains([]interface{{{{{}}}}}, {}.{})",
1168                    vals.join(", "),
1169                    entity_var,
1170                    field
1171                ))
1172            }
1173            ConditionNode::Like { field, pattern } => Ok(format!(
1174                "strings.Contains({}.{}, \"{}\")",
1175                entity_var,
1176                field,
1177                pattern.replace('%', "")
1178            )),
1179            ConditionNode::And(left, right) => {
1180                let left_go = self.generate_condition(left, entity_var)?;
1181                let right_go = self.generate_condition(right, entity_var)?;
1182                Ok(format!("({} && {})", left_go, right_go))
1183            }
1184            ConditionNode::Or(left, right) => {
1185                let left_go = self.generate_condition(left, entity_var)?;
1186                let right_go = self.generate_condition(right, entity_var)?;
1187                Ok(format!("({} || {})", left_go, right_go))
1188            }
1189            ConditionNode::Not(inner) => {
1190                let inner_go = self.generate_condition(inner, entity_var)?;
1191                Ok(format!("!({})", inner_go))
1192            }
1193            ConditionNode::InRange {
1194                field,
1195                min,
1196                max,
1197                inclusive_min,
1198                inclusive_max,
1199            } => {
1200                let min_val = self.format_value(min)?;
1201                let max_val = self.format_value(max)?;
1202                let min_op = if *inclusive_min { ">=" } else { ">" };
1203                let max_op = if *inclusive_max { "<=" } else { "<" };
1204                Ok(format!(
1205                    "{}.{} {} {} && {}.{} {} {}",
1206                    entity_var, field, min_op, min_val, entity_var, field, max_op, max_val
1207                ))
1208            }
1209            ConditionNode::NotInRange {
1210                field,
1211                min,
1212                max,
1213                inclusive_min,
1214                inclusive_max,
1215            } => {
1216                let min_val = self.format_value(min)?;
1217                let max_val = self.format_value(max)?;
1218                let min_op = if *inclusive_min { "<" } else { "<=" };
1219                let max_op = if *inclusive_max { ">" } else { ">=" };
1220                Ok(format!(
1221                    "{}.{} {} {} || {}.{} {} {}",
1222                    entity_var, field, min_op, min_val, entity_var, field, max_op, max_val
1223                ))
1224            }
1225            ConditionNode::Matches {
1226                field,
1227                regex_pattern,
1228            } => Ok(format!(
1229                "regexp.MustCompile(\"{}\").MatchString({}.{})",
1230                regex_pattern, entity_var, field
1231            )),
1232            ConditionNode::TemporalComparison {
1233                field,
1234                operator,
1235                value,
1236            } => {
1237                let val = self.format_value(value)?;
1238                let field_str = temporal_field_to_string(field);
1239                Ok(format!("{}.{} {} {}", entity_var, field_str, operator, val))
1240            }
1241        }
1242    }
1243
1244    /// Formats a condition value for Go.
1245    fn format_value(&self, value: &ConditionValue) -> DslResult<String> {
1246        match value {
1247            ConditionValue::Number(n) => Ok(n.to_string()),
1248            ConditionValue::String(s) => Ok(format!("\"{}\"", s.replace('"', "\\\""))),
1249            ConditionValue::Boolean(b) => Ok(b.to_string()),
1250            ConditionValue::Date(d) => Ok(format!("\"{}\"", d)),
1251            ConditionValue::SetExpr(_) => Ok("[]interface{}{}".to_string()),
1252        }
1253    }
1254
1255    /// Generates validation function for a statute.
1256    fn generate_function(&self, statute: &StatuteNode) -> DslResult<String> {
1257        let mut code = String::new();
1258        let fn_name = self.function_name(&statute.id);
1259
1260        writeln!(&mut code, "// {} - {}", fn_name, statute.title).unwrap();
1261        writeln!(&mut code, "func {}(entity interface{{}}) bool {{", fn_name).unwrap();
1262
1263        if statute.conditions.is_empty() {
1264            writeln!(&mut code, "\treturn true").unwrap();
1265        } else {
1266            write!(&mut code, "\treturn ").unwrap();
1267            let conditions: Result<Vec<_>, _> = statute
1268                .conditions
1269                .iter()
1270                .map(|c| self.generate_condition(c, "entity"))
1271                .collect();
1272            let conditions = conditions?;
1273            writeln!(&mut code, "{}", conditions.join(" && ")).unwrap();
1274        }
1275
1276        writeln!(&mut code, "}}").unwrap();
1277        writeln!(&mut code).unwrap();
1278
1279        Ok(code)
1280    }
1281}
1282
1283impl CodeGenerator for GoGenerator {
1284    fn generate(&self, doc: &LegalDocument) -> DslResult<String> {
1285        let mut code = String::new();
1286
1287        writeln!(&mut code, "// Generated Go code from Legal DSL").unwrap();
1288        writeln!(&mut code, "// Total statutes: {}", doc.statutes.len()).unwrap();
1289        writeln!(&mut code).unwrap();
1290
1291        writeln!(&mut code, "package {}", self.package_name).unwrap();
1292        writeln!(&mut code).unwrap();
1293        writeln!(&mut code, "import (").unwrap();
1294        writeln!(&mut code, "\t\"regexp\"").unwrap();
1295        writeln!(&mut code, "\t\"strings\"").unwrap();
1296        writeln!(&mut code, ")").unwrap();
1297        writeln!(&mut code).unwrap();
1298
1299        for statute in &doc.statutes {
1300            let fn_code = self.generate_function(statute)?;
1301            code.push_str(&fn_code);
1302        }
1303
1304        Ok(code)
1305    }
1306
1307    fn target_language(&self) -> &str {
1308        "Go"
1309    }
1310
1311    fn file_extension(&self) -> &str {
1312        "go"
1313    }
1314}
1315
1316/// Java generator for creating validation classes.
1317pub struct JavaGenerator {
1318    /// Package name for generated code
1319    pub package_name: String,
1320    /// Class name for generated code
1321    pub class_name: String,
1322}
1323
1324impl Default for JavaGenerator {
1325    fn default() -> Self {
1326        Self {
1327            package_name: "com.legal.statutes".to_string(),
1328            class_name: "StatuteValidator".to_string(),
1329        }
1330    }
1331}
1332
1333impl JavaGenerator {
1334    /// Creates a new Java generator.
1335    pub fn new() -> Self {
1336        Self::default()
1337    }
1338
1339    /// Generates method name from statute ID (camelCase).
1340    fn method_name(&self, id: &str) -> String {
1341        let parts: Vec<&str> = id.split('-').collect();
1342        if parts.is_empty() {
1343            return String::new();
1344        }
1345
1346        let mut result = parts[0].to_string();
1347        for part in &parts[1..] {
1348            let mut chars = part.chars();
1349            if let Some(first) = chars.next() {
1350                result.push_str(&first.to_uppercase().chain(chars).collect::<String>());
1351            }
1352        }
1353        result
1354    }
1355
1356    /// Generates Java condition expression.
1357    fn generate_condition(&self, condition: &ConditionNode, entity_var: &str) -> DslResult<String> {
1358        match condition {
1359            ConditionNode::Comparison {
1360                field,
1361                operator,
1362                value,
1363            } => {
1364                let val = self.format_value(value)?;
1365                let getter = format!("get{}()", self.capitalize_first(field));
1366                Ok(format!("{}.{} {} {}", entity_var, getter, operator, val))
1367            }
1368            ConditionNode::HasAttribute { key } => {
1369                let getter = format!("get{}()", self.capitalize_first(key));
1370                Ok(format!("{}.{} != null", entity_var, getter))
1371            }
1372            ConditionNode::Between { field, min, max } => {
1373                let min_val = self.format_value(min)?;
1374                let max_val = self.format_value(max)?;
1375                let getter = format!("get{}()", self.capitalize_first(field));
1376                Ok(format!(
1377                    "{}.{} >= {} && {}.{} <= {}",
1378                    entity_var, getter, min_val, entity_var, getter, max_val
1379                ))
1380            }
1381            ConditionNode::In { field, values } => {
1382                let vals: Result<Vec<_>, _> = values.iter().map(|v| self.format_value(v)).collect();
1383                let vals = vals?;
1384                let getter = format!("get{}()", self.capitalize_first(field));
1385                Ok(format!(
1386                    "Arrays.asList({}).contains({}.{})",
1387                    vals.join(", "),
1388                    entity_var,
1389                    getter
1390                ))
1391            }
1392            ConditionNode::Like { field, pattern } => {
1393                let getter = format!("get{}()", self.capitalize_first(field));
1394                Ok(format!(
1395                    "{}.{}.contains(\"{}\")",
1396                    entity_var,
1397                    getter,
1398                    pattern.replace('%', "")
1399                ))
1400            }
1401            ConditionNode::And(left, right) => {
1402                let left_java = self.generate_condition(left, entity_var)?;
1403                let right_java = self.generate_condition(right, entity_var)?;
1404                Ok(format!("({} && {})", left_java, right_java))
1405            }
1406            ConditionNode::Or(left, right) => {
1407                let left_java = self.generate_condition(left, entity_var)?;
1408                let right_java = self.generate_condition(right, entity_var)?;
1409                Ok(format!("({} || {})", left_java, right_java))
1410            }
1411            ConditionNode::Not(inner) => {
1412                let inner_java = self.generate_condition(inner, entity_var)?;
1413                Ok(format!("!({})", inner_java))
1414            }
1415            ConditionNode::InRange {
1416                field,
1417                min,
1418                max,
1419                inclusive_min,
1420                inclusive_max,
1421            } => {
1422                let min_val = self.format_value(min)?;
1423                let max_val = self.format_value(max)?;
1424                let getter = format!("get{}()", self.capitalize_first(field));
1425                let min_op = if *inclusive_min { ">=" } else { ">" };
1426                let max_op = if *inclusive_max { "<=" } else { "<" };
1427                Ok(format!(
1428                    "{}.{} {} {} && {}.{} {} {}",
1429                    entity_var, getter, min_op, min_val, entity_var, getter, max_op, max_val
1430                ))
1431            }
1432            ConditionNode::NotInRange {
1433                field,
1434                min,
1435                max,
1436                inclusive_min,
1437                inclusive_max,
1438            } => {
1439                let min_val = self.format_value(min)?;
1440                let max_val = self.format_value(max)?;
1441                let getter = format!("get{}()", self.capitalize_first(field));
1442                let min_op = if *inclusive_min { "<" } else { "<=" };
1443                let max_op = if *inclusive_max { ">" } else { ">=" };
1444                Ok(format!(
1445                    "{}.{} {} {} || {}.{} {} {}",
1446                    entity_var, getter, min_op, min_val, entity_var, getter, max_op, max_val
1447                ))
1448            }
1449            ConditionNode::Matches {
1450                field,
1451                regex_pattern,
1452            } => {
1453                let getter = format!("get{}()", self.capitalize_first(field));
1454                Ok(format!(
1455                    "Pattern.compile(\"{}\").matcher({}.{}).matches()",
1456                    regex_pattern, entity_var, getter
1457                ))
1458            }
1459            ConditionNode::TemporalComparison {
1460                field,
1461                operator,
1462                value,
1463            } => {
1464                let val = self.format_value(value)?;
1465                let field_str = temporal_field_to_string(field);
1466                let getter = format!("get{}()", self.capitalize_first(&field_str));
1467                Ok(format!("{}.{} {} {}", entity_var, getter, operator, val))
1468            }
1469        }
1470    }
1471
1472    /// Capitalizes first character of a string.
1473    fn capitalize_first(&self, s: &str) -> String {
1474        let mut chars = s.chars();
1475        match chars.next() {
1476            None => String::new(),
1477            Some(first) => first.to_uppercase().chain(chars).collect(),
1478        }
1479    }
1480
1481    /// Formats a condition value for Java.
1482    fn format_value(&self, value: &ConditionValue) -> DslResult<String> {
1483        match value {
1484            ConditionValue::Number(n) => Ok(n.to_string()),
1485            ConditionValue::String(s) => Ok(format!("\"{}\"", s.replace('"', "\\\""))),
1486            ConditionValue::Boolean(b) => Ok(b.to_string()),
1487            ConditionValue::Date(d) => Ok(format!("\"{}\"", d)),
1488            ConditionValue::SetExpr(_) => Ok("new ArrayList<>()".to_string()),
1489        }
1490    }
1491
1492    /// Generates validation method for a statute.
1493    fn generate_method(&self, statute: &StatuteNode) -> DslResult<String> {
1494        let mut code = String::new();
1495        let method_name = self.method_name(&statute.id);
1496
1497        writeln!(&mut code, "    /**").unwrap();
1498        writeln!(&mut code, "     * {}", statute.title).unwrap();
1499        writeln!(&mut code, "     * @param entity The entity to validate").unwrap();
1500        writeln!(&mut code, "     * @return Whether the statute applies").unwrap();
1501        writeln!(&mut code, "     */").unwrap();
1502        writeln!(
1503            &mut code,
1504            "    public static boolean {}(Object entity) {{",
1505            method_name
1506        )
1507        .unwrap();
1508
1509        if statute.conditions.is_empty() {
1510            writeln!(&mut code, "        return true;").unwrap();
1511        } else {
1512            write!(&mut code, "        return ").unwrap();
1513            let conditions: Result<Vec<_>, _> = statute
1514                .conditions
1515                .iter()
1516                .map(|c| self.generate_condition(c, "entity"))
1517                .collect();
1518            let conditions = conditions?;
1519            writeln!(&mut code, "{};", conditions.join(" && ")).unwrap();
1520        }
1521
1522        writeln!(&mut code, "    }}").unwrap();
1523        writeln!(&mut code).unwrap();
1524
1525        Ok(code)
1526    }
1527}
1528
1529impl CodeGenerator for JavaGenerator {
1530    fn generate(&self, doc: &LegalDocument) -> DslResult<String> {
1531        let mut code = String::new();
1532
1533        writeln!(&mut code, "// Generated Java code from Legal DSL").unwrap();
1534        writeln!(&mut code, "// Total statutes: {}", doc.statutes.len()).unwrap();
1535        writeln!(&mut code).unwrap();
1536
1537        writeln!(&mut code, "package {};", self.package_name).unwrap();
1538        writeln!(&mut code).unwrap();
1539        writeln!(&mut code, "import java.util.Arrays;").unwrap();
1540        writeln!(&mut code, "import java.util.ArrayList;").unwrap();
1541        writeln!(&mut code, "import java.util.regex.Pattern;").unwrap();
1542        writeln!(&mut code).unwrap();
1543
1544        writeln!(&mut code, "public class {} {{", self.class_name).unwrap();
1545        writeln!(&mut code).unwrap();
1546
1547        for statute in &doc.statutes {
1548            let method_code = self.generate_method(statute)?;
1549            code.push_str(&method_code);
1550        }
1551
1552        writeln!(&mut code, "}}").unwrap();
1553
1554        Ok(code)
1555    }
1556
1557    fn target_language(&self) -> &str {
1558        "Java"
1559    }
1560
1561    fn file_extension(&self) -> &str {
1562        "java"
1563    }
1564}
1565
1566/// C# generator for creating validation classes.
1567pub struct CSharpGenerator {
1568    /// Namespace for generated code
1569    pub namespace: String,
1570    /// Class name for generated code
1571    pub class_name: String,
1572}
1573
1574impl Default for CSharpGenerator {
1575    fn default() -> Self {
1576        Self {
1577            namespace: "Legal.Statutes".to_string(),
1578            class_name: "StatuteValidator".to_string(),
1579        }
1580    }
1581}
1582
1583impl CSharpGenerator {
1584    /// Creates a new C# generator.
1585    pub fn new() -> Self {
1586        Self::default()
1587    }
1588
1589    /// Generates method name from statute ID (PascalCase).
1590    fn method_name(&self, id: &str) -> String {
1591        id.split('-')
1592            .map(|part| {
1593                let mut chars = part.chars();
1594                match chars.next() {
1595                    None => String::new(),
1596                    Some(first) => first.to_uppercase().chain(chars).collect(),
1597                }
1598            })
1599            .collect()
1600    }
1601
1602    /// Generates C# condition expression.
1603    fn generate_condition(&self, condition: &ConditionNode, entity_var: &str) -> DslResult<String> {
1604        match condition {
1605            ConditionNode::Comparison {
1606                field,
1607                operator,
1608                value,
1609            } => {
1610                let val = self.format_value(value)?;
1611                Ok(format!(
1612                    "{}.{} {} {}",
1613                    entity_var,
1614                    self.capitalize_first(field),
1615                    operator,
1616                    val
1617                ))
1618            }
1619            ConditionNode::HasAttribute { key } => Ok(format!(
1620                "{}.{} != null",
1621                entity_var,
1622                self.capitalize_first(key)
1623            )),
1624            ConditionNode::Between { field, min, max } => {
1625                let min_val = self.format_value(min)?;
1626                let max_val = self.format_value(max)?;
1627                let prop = self.capitalize_first(field);
1628                Ok(format!(
1629                    "{}.{} >= {} && {}.{} <= {}",
1630                    entity_var, prop, min_val, entity_var, prop, max_val
1631                ))
1632            }
1633            ConditionNode::In { field, values } => {
1634                let vals: Result<Vec<_>, _> = values.iter().map(|v| self.format_value(v)).collect();
1635                let vals = vals?;
1636                let prop = self.capitalize_first(field);
1637                Ok(format!(
1638                    "new[] {{ {} }}.Contains({}.{})",
1639                    vals.join(", "),
1640                    entity_var,
1641                    prop
1642                ))
1643            }
1644            ConditionNode::Like { field, pattern } => {
1645                let prop = self.capitalize_first(field);
1646                Ok(format!(
1647                    "{}.{}.Contains(\"{}\")",
1648                    entity_var,
1649                    prop,
1650                    pattern.replace('%', "")
1651                ))
1652            }
1653            ConditionNode::And(left, right) => {
1654                let left_cs = self.generate_condition(left, entity_var)?;
1655                let right_cs = self.generate_condition(right, entity_var)?;
1656                Ok(format!("({} && {})", left_cs, right_cs))
1657            }
1658            ConditionNode::Or(left, right) => {
1659                let left_cs = self.generate_condition(left, entity_var)?;
1660                let right_cs = self.generate_condition(right, entity_var)?;
1661                Ok(format!("({} || {})", left_cs, right_cs))
1662            }
1663            ConditionNode::Not(inner) => {
1664                let inner_cs = self.generate_condition(inner, entity_var)?;
1665                Ok(format!("!({})", inner_cs))
1666            }
1667            ConditionNode::InRange {
1668                field,
1669                min,
1670                max,
1671                inclusive_min,
1672                inclusive_max,
1673            } => {
1674                let min_val = self.format_value(min)?;
1675                let max_val = self.format_value(max)?;
1676                let prop = self.capitalize_first(field);
1677                let min_op = if *inclusive_min { ">=" } else { ">" };
1678                let max_op = if *inclusive_max { "<=" } else { "<" };
1679                Ok(format!(
1680                    "{}.{} {} {} && {}.{} {} {}",
1681                    entity_var, prop, min_op, min_val, entity_var, prop, max_op, max_val
1682                ))
1683            }
1684            ConditionNode::NotInRange {
1685                field,
1686                min,
1687                max,
1688                inclusive_min,
1689                inclusive_max,
1690            } => {
1691                let min_val = self.format_value(min)?;
1692                let max_val = self.format_value(max)?;
1693                let prop = self.capitalize_first(field);
1694                let min_op = if *inclusive_min { "<" } else { "<=" };
1695                let max_op = if *inclusive_max { ">" } else { ">=" };
1696                Ok(format!(
1697                    "{}.{} {} {} || {}.{} {} {}",
1698                    entity_var, prop, min_op, min_val, entity_var, prop, max_op, max_val
1699                ))
1700            }
1701            ConditionNode::Matches {
1702                field,
1703                regex_pattern,
1704            } => {
1705                let prop = self.capitalize_first(field);
1706                Ok(format!(
1707                    "Regex.IsMatch({}.{}, @\"{}\")",
1708                    entity_var, prop, regex_pattern
1709                ))
1710            }
1711            ConditionNode::TemporalComparison {
1712                field,
1713                operator,
1714                value,
1715            } => {
1716                let val = self.format_value(value)?;
1717                let field_str = temporal_field_to_string(field);
1718                let prop = self.capitalize_first(&field_str);
1719                Ok(format!("{}.{} {} {}", entity_var, prop, operator, val))
1720            }
1721        }
1722    }
1723
1724    /// Capitalizes first character of a string.
1725    fn capitalize_first(&self, s: &str) -> String {
1726        let mut chars = s.chars();
1727        match chars.next() {
1728            None => String::new(),
1729            Some(first) => first.to_uppercase().chain(chars).collect(),
1730        }
1731    }
1732
1733    /// Formats a condition value for C#.
1734    fn format_value(&self, value: &ConditionValue) -> DslResult<String> {
1735        match value {
1736            ConditionValue::Number(n) => Ok(n.to_string()),
1737            ConditionValue::String(s) => Ok(format!("\"{}\"", s.replace('"', "\\\""))),
1738            ConditionValue::Boolean(b) => Ok(if *b { "true" } else { "false" }.to_string()),
1739            ConditionValue::Date(d) => Ok(format!("\"{}\"", d)),
1740            ConditionValue::SetExpr(_) => Ok("new List<object>()".to_string()),
1741        }
1742    }
1743
1744    /// Generates validation method for a statute.
1745    fn generate_method(&self, statute: &StatuteNode) -> DslResult<String> {
1746        let mut code = String::new();
1747        let method_name = self.method_name(&statute.id);
1748
1749        writeln!(&mut code, "    /// <summary>").unwrap();
1750        writeln!(&mut code, "    /// {}", statute.title).unwrap();
1751        writeln!(&mut code, "    /// </summary>").unwrap();
1752        writeln!(
1753            &mut code,
1754            "    /// <param name=\"entity\">The entity to validate</param>"
1755        )
1756        .unwrap();
1757        writeln!(
1758            &mut code,
1759            "    /// <returns>Whether the statute applies</returns>"
1760        )
1761        .unwrap();
1762        writeln!(
1763            &mut code,
1764            "    public static bool {}(object entity)",
1765            method_name
1766        )
1767        .unwrap();
1768        writeln!(&mut code, "    {{").unwrap();
1769
1770        if statute.conditions.is_empty() {
1771            writeln!(&mut code, "        return true;").unwrap();
1772        } else {
1773            write!(&mut code, "        return ").unwrap();
1774            let conditions: Result<Vec<_>, _> = statute
1775                .conditions
1776                .iter()
1777                .map(|c| self.generate_condition(c, "entity"))
1778                .collect();
1779            let conditions = conditions?;
1780            writeln!(&mut code, "{};", conditions.join(" && ")).unwrap();
1781        }
1782
1783        writeln!(&mut code, "    }}").unwrap();
1784        writeln!(&mut code).unwrap();
1785
1786        Ok(code)
1787    }
1788}
1789
1790impl CodeGenerator for CSharpGenerator {
1791    fn generate(&self, doc: &LegalDocument) -> DslResult<String> {
1792        let mut code = String::new();
1793
1794        writeln!(&mut code, "// Generated C# code from Legal DSL").unwrap();
1795        writeln!(&mut code, "// Total statutes: {}", doc.statutes.len()).unwrap();
1796        writeln!(&mut code).unwrap();
1797
1798        writeln!(&mut code, "using System;").unwrap();
1799        writeln!(&mut code, "using System.Linq;").unwrap();
1800        writeln!(&mut code, "using System.Collections.Generic;").unwrap();
1801        writeln!(&mut code, "using System.Text.RegularExpressions;").unwrap();
1802        writeln!(&mut code).unwrap();
1803
1804        writeln!(&mut code, "namespace {}", self.namespace).unwrap();
1805        writeln!(&mut code, "{{").unwrap();
1806        writeln!(&mut code, "    public static class {}", self.class_name).unwrap();
1807        writeln!(&mut code, "    {{").unwrap();
1808
1809        for statute in &doc.statutes {
1810            let method_code = self.generate_method(statute)?;
1811            code.push_str(&method_code);
1812        }
1813
1814        writeln!(&mut code, "    }}").unwrap();
1815        writeln!(&mut code, "}}").unwrap();
1816
1817        Ok(code)
1818    }
1819
1820    fn target_language(&self) -> &str {
1821        "C#"
1822    }
1823
1824    fn file_extension(&self) -> &str {
1825        "cs"
1826    }
1827}
1828
1829#[cfg(test)]
1830mod tests {
1831    use super::*;
1832    use crate::ast::{ConditionValue, EffectNode};
1833
1834    fn sample_statute() -> StatuteNode {
1835        StatuteNode {
1836            id: "voting-rights".to_string(),
1837            visibility: crate::module_system::Visibility::Private,
1838            title: "Voting Rights Statute".to_string(),
1839            conditions: vec![
1840                ConditionNode::Comparison {
1841                    field: "age".to_string(),
1842                    operator: ">=".to_string(),
1843                    value: ConditionValue::Number(18),
1844                },
1845                ConditionNode::HasAttribute {
1846                    key: "citizen".to_string(),
1847                },
1848            ],
1849            effects: vec![EffectNode {
1850                effect_type: "grant".to_string(),
1851                description: "Right to vote".to_string(),
1852                parameters: vec![],
1853            }],
1854            discretion: None,
1855            exceptions: vec![],
1856            amendments: vec![],
1857            supersedes: vec![],
1858            defaults: vec![],
1859            requires: vec![],
1860            delegates: vec![],
1861            scope: None,
1862            constraints: vec![],
1863            priority: None,
1864        }
1865    }
1866
1867    #[test]
1868    fn test_sql_generation() {
1869        let doc = LegalDocument {
1870            namespace: None,
1871            exports: vec![],
1872            imports: vec![],
1873            statutes: vec![sample_statute()],
1874        };
1875
1876        let generator = SqlGenerator::new();
1877        let sql = generator.generate(&doc).unwrap();
1878
1879        assert!(sql.contains("CREATE TABLE voting_rights"));
1880        assert!(sql.contains("age"));
1881        assert!(sql.contains("citizen"));
1882    }
1883
1884    #[test]
1885    fn test_python_generation() {
1886        let doc = LegalDocument {
1887            namespace: None,
1888            exports: vec![],
1889            imports: vec![],
1890            statutes: vec![sample_statute()],
1891        };
1892
1893        let generator = PythonGenerator::new();
1894        let py = generator.generate(&doc).unwrap();
1895
1896        assert!(py.contains("def voting_rights"));
1897        assert!(py.contains("obj.age >= 18"));
1898        assert!(py.contains("hasattr(obj, 'citizen')"));
1899    }
1900
1901    #[test]
1902    fn test_sql_generator_metadata() {
1903        let generator = SqlGenerator::new();
1904        assert_eq!(generator.target_language(), "SQL");
1905        assert_eq!(generator.file_extension(), "sql");
1906    }
1907
1908    #[test]
1909    fn test_python_generator_metadata() {
1910        let generator = PythonGenerator::new();
1911        assert_eq!(generator.target_language(), "Python");
1912        assert_eq!(generator.file_extension(), "py");
1913    }
1914
1915    #[test]
1916    fn test_prolog_generation() {
1917        let doc = LegalDocument {
1918            namespace: None,
1919            exports: vec![],
1920            imports: vec![],
1921            statutes: vec![sample_statute()],
1922        };
1923
1924        let generator = PrologGenerator::new();
1925        let pl = generator.generate(&doc).unwrap();
1926
1927        assert!(pl.contains("voting_rights(Entity)"));
1928        assert!(pl.contains("Entity_age >= 18"));
1929        assert!(pl.contains("nonvar(Entity_citizen)"));
1930    }
1931
1932    #[test]
1933    fn test_prolog_generator_metadata() {
1934        let generator = PrologGenerator::new();
1935        assert_eq!(generator.target_language(), "Prolog");
1936        assert_eq!(generator.file_extension(), "pl");
1937    }
1938
1939    #[test]
1940    fn test_prolog_module_generation() {
1941        let doc = LegalDocument {
1942            namespace: None,
1943            exports: vec![],
1944            imports: vec![],
1945            statutes: vec![sample_statute()],
1946        };
1947
1948        let generator = PrologGenerator {
1949            generate_module: true,
1950            use_dynamic: true,
1951        };
1952        let pl = generator.generate(&doc).unwrap();
1953
1954        assert!(pl.contains(":- module(legal_statutes, [])"));
1955        assert!(pl.contains(":- dynamic voting_rights/1"));
1956    }
1957
1958    #[test]
1959    fn test_prolog_effect_generation() {
1960        let doc = LegalDocument {
1961            namespace: None,
1962            exports: vec![],
1963            imports: vec![],
1964            statutes: vec![sample_statute()],
1965        };
1966
1967        let generator = PrologGenerator::new();
1968        let pl = generator.generate(&doc).unwrap();
1969
1970        assert!(pl.contains("voting_rights_effect_1"));
1971        assert!(pl.contains("Right to vote"));
1972    }
1973
1974    #[test]
1975    fn test_sql_roundtrip_validation() {
1976        let doc = LegalDocument {
1977            namespace: None,
1978            exports: vec![],
1979            imports: vec![],
1980            statutes: vec![sample_statute()],
1981        };
1982
1983        let generator = SqlGenerator::new();
1984        let sql = generator.generate(&doc).unwrap();
1985
1986        // Verify SQL contains expected keywords
1987        assert!(sql.contains("CREATE TABLE"));
1988        assert!(sql.contains("PRIMARY KEY"));
1989        assert!(sql.contains("CHECK"));
1990
1991        // Verify no syntax errors in basic structure
1992        assert!(!sql.contains(";;")); // No double semicolons
1993        assert!(sql.matches('(').count() == sql.matches(')').count()); // Balanced parentheses
1994    }
1995
1996    #[test]
1997    fn test_python_roundtrip_validation() {
1998        let doc = LegalDocument {
1999            namespace: None,
2000            exports: vec![],
2001            imports: vec![],
2002            statutes: vec![sample_statute()],
2003        };
2004
2005        let generator = PythonGenerator::new();
2006        let py = generator.generate(&doc).unwrap();
2007
2008        // Verify Python contains expected structures
2009        assert!(py.contains("def "));
2010        assert!(py.contains("return "));
2011        assert!(py.contains("from typing import Any"));
2012
2013        // Verify basic Python syntax
2014        assert!(py.matches("def ").count() == py.matches("return ").count());
2015    }
2016
2017    #[test]
2018    fn test_prolog_roundtrip_validation() {
2019        let doc = LegalDocument {
2020            namespace: None,
2021            exports: vec![],
2022            imports: vec![],
2023            statutes: vec![sample_statute()],
2024        };
2025
2026        let generator = PrologGenerator::new();
2027        let pl = generator.generate(&doc).unwrap();
2028
2029        // Verify Prolog contains expected structures
2030        assert!(pl.contains("(Entity) :- "));
2031        assert!(pl.ends_with("\n") || pl.ends_with("."));
2032
2033        // Verify balanced predicates (all :- have corresponding .)
2034        assert!(pl.matches(":-").count() <= pl.matches('.').count());
2035    }
2036
2037    #[test]
2038    fn test_complex_document_all_generators() {
2039        let complex_statute = StatuteNode {
2040            id: "complex-law".to_string(),
2041            visibility: crate::module_system::Visibility::Private,
2042            title: "Complex Law Test".to_string(),
2043            conditions: vec![ConditionNode::And(
2044                Box::new(ConditionNode::Comparison {
2045                    field: "age".to_string(),
2046                    operator: ">=".to_string(),
2047                    value: ConditionValue::Number(18),
2048                }),
2049                Box::new(ConditionNode::In {
2050                    field: "status".to_string(),
2051                    values: vec![
2052                        ConditionValue::String("citizen".to_string()),
2053                        ConditionValue::String("resident".to_string()),
2054                    ],
2055                }),
2056            )],
2057            effects: vec![
2058                EffectNode {
2059                    effect_type: "GRANT".to_string(),
2060                    description: "Voting rights".to_string(),
2061                    parameters: vec![],
2062                },
2063                EffectNode {
2064                    effect_type: "OBLIGATION".to_string(),
2065                    description: "Register to vote".to_string(),
2066                    parameters: vec![],
2067                },
2068            ],
2069            discretion: None,
2070            exceptions: vec![],
2071            amendments: vec![],
2072            supersedes: vec![],
2073            defaults: vec![],
2074            requires: vec![],
2075            delegates: vec![],
2076            scope: None,
2077            constraints: vec![],
2078            priority: None,
2079        };
2080
2081        let doc = LegalDocument {
2082            namespace: None,
2083            exports: vec![],
2084            imports: vec![],
2085            statutes: vec![complex_statute],
2086        };
2087
2088        // Test all generators can handle complex documents
2089        let sql_gen = SqlGenerator::new();
2090        let sql = sql_gen.generate(&doc).unwrap();
2091        assert!(sql.len() > 100);
2092
2093        let py_gen = PythonGenerator::new();
2094        let py = py_gen.generate(&doc).unwrap();
2095        assert!(py.len() > 100);
2096
2097        let pl_gen = PrologGenerator::new();
2098        let pl = pl_gen.generate(&doc).unwrap();
2099        assert!(pl.len() > 100);
2100
2101        // Test new generators
2102        let ts_gen = TypeScriptGenerator::new();
2103        let ts = ts_gen.generate(&doc).unwrap();
2104        assert!(ts.len() > 100);
2105
2106        let rust_gen = RustGenerator::new();
2107        let rust = rust_gen.generate(&doc).unwrap();
2108        assert!(rust.len() > 100);
2109
2110        let go_gen = GoGenerator::new();
2111        let go = go_gen.generate(&doc).unwrap();
2112        assert!(go.len() > 100);
2113
2114        let java_gen = JavaGenerator::new();
2115        let java = java_gen.generate(&doc).unwrap();
2116        assert!(java.len() > 100);
2117
2118        let cs_gen = CSharpGenerator::new();
2119        let cs = cs_gen.generate(&doc).unwrap();
2120        assert!(cs.len() > 100);
2121    }
2122
2123    #[test]
2124    fn test_typescript_generation() {
2125        let doc = LegalDocument {
2126            namespace: None,
2127            exports: vec![],
2128            imports: vec![],
2129            statutes: vec![sample_statute()],
2130        };
2131
2132        let generator = TypeScriptGenerator::new();
2133        let ts = generator.generate(&doc).unwrap();
2134
2135        assert!(ts.contains("export function"));
2136        assert!(ts.contains("voting_rights"));
2137        assert!(ts.contains("entity"));
2138        assert!(ts.contains(": boolean"));
2139    }
2140
2141    #[test]
2142    fn test_rust_generation() {
2143        let doc = LegalDocument {
2144            namespace: None,
2145            exports: vec![],
2146            imports: vec![],
2147            statutes: vec![sample_statute()],
2148        };
2149
2150        let generator = RustGenerator::new();
2151        let rs = generator.generate(&doc).unwrap();
2152
2153        assert!(rs.contains("pub fn voting_rights"));
2154        assert!(rs.contains("-> bool"));
2155        assert!(rs.contains("use regex::Regex"));
2156    }
2157
2158    #[test]
2159    fn test_go_generation() {
2160        let doc = LegalDocument {
2161            namespace: None,
2162            exports: vec![],
2163            imports: vec![],
2164            statutes: vec![sample_statute()],
2165        };
2166
2167        let generator = GoGenerator::new();
2168        let go = generator.generate(&doc).unwrap();
2169
2170        assert!(go.contains("package statutes"));
2171        assert!(go.contains("func Voting_rights"));
2172        assert!(go.contains("bool"));
2173        assert!(go.contains("import ("));
2174    }
2175
2176    #[test]
2177    fn test_java_generation() {
2178        let doc = LegalDocument {
2179            namespace: None,
2180            exports: vec![],
2181            imports: vec![],
2182            statutes: vec![sample_statute()],
2183        };
2184
2185        let generator = JavaGenerator::new();
2186        let java = generator.generate(&doc).unwrap();
2187
2188        assert!(java.contains("public class StatuteValidator"));
2189        assert!(java.contains("public static boolean votingRights"));
2190        assert!(java.contains("package com.legal.statutes"));
2191        assert!(java.contains("import java.util"));
2192    }
2193
2194    #[test]
2195    fn test_typescript_javascript_mode() {
2196        let doc = LegalDocument {
2197            namespace: None,
2198            exports: vec![],
2199            imports: vec![],
2200            statutes: vec![sample_statute()],
2201        };
2202
2203        let mut generator = TypeScriptGenerator::new();
2204        generator.use_typescript = false;
2205
2206        let js = generator.generate(&doc).unwrap();
2207        assert!(js.contains("export function"));
2208        assert!(!js.contains(": boolean"));
2209        assert_eq!(generator.file_extension(), "js");
2210        assert_eq!(generator.target_language(), "JavaScript");
2211    }
2212
2213    #[test]
2214    fn test_csharp_generation() {
2215        let doc = LegalDocument {
2216            namespace: None,
2217            exports: vec![],
2218            imports: vec![],
2219            statutes: vec![sample_statute()],
2220        };
2221
2222        let generator = CSharpGenerator::new();
2223        let cs = generator.generate(&doc).unwrap();
2224
2225        assert!(cs.contains("namespace Legal.Statutes"));
2226        assert!(cs.contains("public static class StatuteValidator"));
2227        assert!(cs.contains("public static bool VotingRights"));
2228        assert!(cs.contains("using System"));
2229    }
2230
2231    #[test]
2232    fn test_all_generators_file_extensions() {
2233        assert_eq!(SqlGenerator::new().file_extension(), "sql");
2234        assert_eq!(PythonGenerator::new().file_extension(), "py");
2235        assert_eq!(PrologGenerator::new().file_extension(), "pl");
2236        assert_eq!(TypeScriptGenerator::new().file_extension(), "ts");
2237        assert_eq!(RustGenerator::new().file_extension(), "rs");
2238        assert_eq!(GoGenerator::new().file_extension(), "go");
2239        assert_eq!(JavaGenerator::new().file_extension(), "java");
2240        assert_eq!(CSharpGenerator::new().file_extension(), "cs");
2241    }
2242
2243    #[test]
2244    fn test_all_generators_target_languages() {
2245        assert_eq!(SqlGenerator::new().target_language(), "SQL");
2246        assert_eq!(PythonGenerator::new().target_language(), "Python");
2247        assert_eq!(PrologGenerator::new().target_language(), "Prolog");
2248        assert_eq!(TypeScriptGenerator::new().target_language(), "TypeScript");
2249        assert_eq!(RustGenerator::new().target_language(), "Rust");
2250        assert_eq!(GoGenerator::new().target_language(), "Go");
2251        assert_eq!(JavaGenerator::new().target_language(), "Java");
2252        assert_eq!(CSharpGenerator::new().target_language(), "C#");
2253    }
2254}