Skip to main content

oxilean_codegen/r_backend/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use std::collections::HashMap;
6use std::collections::{HashSet, VecDeque};
7use std::fmt::Write as FmtWrite;
8
9/// An R function definition.
10#[derive(Debug, Clone, PartialEq)]
11pub struct RFunction {
12    /// Function name (used when emitted as assignment)
13    pub name: String,
14    /// Formal parameters
15    pub formals: Vec<RFormal>,
16    /// Function body statements
17    pub body: Vec<RStmt>,
18    /// Whether this is a generic function (UseMethod-based)
19    pub is_generic: bool,
20    /// S3 method dispatch class, if any (e.g. `"numeric"`)
21    pub s3_methods: Vec<(String, RFunction)>,
22    /// Documentation string (Roxygen2 style)
23    pub doc: Option<String>,
24}
25impl RFunction {
26    pub fn new(name: &str, formals: Vec<RFormal>, body: Vec<RStmt>) -> Self {
27        RFunction {
28            name: name.to_string(),
29            formals,
30            body,
31            is_generic: false,
32            s3_methods: Vec::new(),
33            doc: None,
34        }
35    }
36    pub fn generic(mut self) -> Self {
37        self.is_generic = true;
38        self
39    }
40    pub fn with_doc(mut self, doc: &str) -> Self {
41        self.doc = Some(doc.to_string());
42        self
43    }
44    pub fn add_s3_method(&mut self, class: &str, method: RFunction) {
45        self.s3_methods.push((class.to_string(), method));
46    }
47}
48#[allow(dead_code)]
49#[derive(Debug, Clone)]
50pub struct RLangDepGraph {
51    pub(super) nodes: Vec<u32>,
52    pub(super) edges: Vec<(u32, u32)>,
53}
54impl RLangDepGraph {
55    #[allow(dead_code)]
56    pub fn new() -> Self {
57        RLangDepGraph {
58            nodes: Vec::new(),
59            edges: Vec::new(),
60        }
61    }
62    #[allow(dead_code)]
63    pub fn add_node(&mut self, id: u32) {
64        if !self.nodes.contains(&id) {
65            self.nodes.push(id);
66        }
67    }
68    #[allow(dead_code)]
69    pub fn add_dep(&mut self, dep: u32, dependent: u32) {
70        self.add_node(dep);
71        self.add_node(dependent);
72        self.edges.push((dep, dependent));
73    }
74    #[allow(dead_code)]
75    pub fn dependents_of(&self, node: u32) -> Vec<u32> {
76        self.edges
77            .iter()
78            .filter(|(d, _)| *d == node)
79            .map(|(_, dep)| *dep)
80            .collect()
81    }
82    #[allow(dead_code)]
83    pub fn dependencies_of(&self, node: u32) -> Vec<u32> {
84        self.edges
85            .iter()
86            .filter(|(_, dep)| *dep == node)
87            .map(|(d, _)| *d)
88            .collect()
89    }
90    #[allow(dead_code)]
91    pub fn topological_sort(&self) -> Vec<u32> {
92        let mut in_degree: std::collections::HashMap<u32, u32> = std::collections::HashMap::new();
93        for &n in &self.nodes {
94            in_degree.insert(n, 0);
95        }
96        for (_, dep) in &self.edges {
97            *in_degree.entry(*dep).or_insert(0) += 1;
98        }
99        let mut queue: std::collections::VecDeque<u32> = self
100            .nodes
101            .iter()
102            .filter(|&&n| in_degree[&n] == 0)
103            .copied()
104            .collect();
105        let mut result = Vec::new();
106        while let Some(node) = queue.pop_front() {
107            result.push(node);
108            for dep in self.dependents_of(node) {
109                let cnt = in_degree.entry(dep).or_insert(0);
110                *cnt = cnt.saturating_sub(1);
111                if *cnt == 0 {
112                    queue.push_back(dep);
113                }
114            }
115        }
116        result
117    }
118    #[allow(dead_code)]
119    pub fn has_cycle(&self) -> bool {
120        self.topological_sort().len() < self.nodes.len()
121    }
122}
123/// Which apply-family function to use.
124#[derive(Debug, Clone, PartialEq, Eq)]
125pub enum ApplyVariant {
126    Sapply,
127    Vapply,
128    Lapply,
129    Apply,
130    Tapply,
131    Mapply,
132}
133#[allow(dead_code)]
134#[derive(Debug, Clone)]
135pub struct RLangDominatorTree {
136    pub idom: Vec<Option<u32>>,
137    pub dom_children: Vec<Vec<u32>>,
138    pub dom_depth: Vec<u32>,
139}
140impl RLangDominatorTree {
141    #[allow(dead_code)]
142    pub fn new(size: usize) -> Self {
143        RLangDominatorTree {
144            idom: vec![None; size],
145            dom_children: vec![Vec::new(); size],
146            dom_depth: vec![0; size],
147        }
148    }
149    #[allow(dead_code)]
150    pub fn set_idom(&mut self, node: usize, idom: u32) {
151        self.idom[node] = Some(idom);
152    }
153    #[allow(dead_code)]
154    pub fn dominates(&self, a: usize, b: usize) -> bool {
155        if a == b {
156            return true;
157        }
158        let mut cur = b;
159        loop {
160            match self.idom[cur] {
161                Some(parent) if parent as usize == a => return true,
162                Some(parent) if parent as usize == cur => return false,
163                Some(parent) => cur = parent as usize,
164                None => return false,
165            }
166        }
167    }
168    #[allow(dead_code)]
169    pub fn depth(&self, node: usize) -> u32 {
170        self.dom_depth.get(node).copied().unwrap_or(0)
171    }
172}
173/// Formal parameter in a function definition.
174#[derive(Debug, Clone, PartialEq)]
175pub struct RFormal {
176    pub name: String,
177    pub default: Option<RExpr>,
178}
179impl RFormal {
180    pub fn required(name: &str) -> Self {
181        RFormal {
182            name: name.to_string(),
183            default: None,
184        }
185    }
186    pub fn with_default(name: &str, default: RExpr) -> Self {
187        RFormal {
188            name: name.to_string(),
189            default: Some(default),
190        }
191    }
192}
193/// Top-level R file structure.
194#[derive(Debug, Clone)]
195pub struct RFile {
196    /// Package imports (`library` calls)
197    pub imports: Vec<String>,
198    /// Top-level function definitions
199    pub functions: Vec<RFunction>,
200    /// Top-level script statements (non-function)
201    pub scripts: Vec<RStmt>,
202    /// Data object definitions
203    pub data_objects: Vec<RDataObject>,
204    /// File-level comment header
205    pub header_comment: Option<String>,
206    /// Shebang line (e.g., `#!/usr/bin/env Rscript`)
207    pub shebang: Option<String>,
208}
209impl RFile {
210    pub fn new() -> Self {
211        RFile {
212            imports: Vec::new(),
213            functions: Vec::new(),
214            scripts: Vec::new(),
215            data_objects: Vec::new(),
216            header_comment: None,
217            shebang: None,
218        }
219    }
220    pub fn with_header(mut self, comment: &str) -> Self {
221        self.header_comment = Some(comment.to_string());
222        self
223    }
224    pub fn add_import(&mut self, pkg: &str) {
225        if !self.imports.contains(&pkg.to_string()) {
226            self.imports.push(pkg.to_string());
227        }
228    }
229    pub fn add_function(&mut self, fun: RFunction) {
230        self.functions.push(fun);
231    }
232    pub fn add_script_stmt(&mut self, stmt: RStmt) {
233        self.scripts.push(stmt);
234    }
235    pub fn add_data(&mut self, obj: RDataObject) {
236        self.data_objects.push(obj);
237    }
238}
239/// Literal values in R.
240#[derive(Debug, Clone, PartialEq)]
241pub enum RLiteral {
242    /// `42L` or `42` integer
243    Integer(i64),
244    /// `3.14` numeric
245    Numeric(f64),
246    /// `TRUE` / `FALSE`
247    Logical(bool),
248    /// `"hello"` character
249    Character(String),
250    /// `1+2i` complex
251    Complex(f64, f64),
252    /// `NULL`
253    Null,
254    /// `NA`
255    Na,
256    /// `NA_integer_`
257    NaInteger,
258    /// `NA_real_`
259    NaReal,
260    /// `NA_character_`
261    NaCharacter,
262    /// `NA_complex_`
263    NaComplex,
264    /// `Inf`
265    Inf,
266    /// `NaN`
267    NaN,
268}
269/// Assignment operator variant.
270#[derive(Debug, Clone, PartialEq, Eq)]
271pub enum RAssignOp {
272    /// `<-` (standard)
273    LeftArrow,
274    /// `<<-` (global / super-assignment)
275    SuperArrow,
276    /// `=` (function args context, or R2 style)
277    Equals,
278    /// `->` (right-assign, uncommon)
279    RightArrow,
280}
281/// R type representation.
282#[derive(Debug, Clone, PartialEq)]
283pub enum RType {
284    /// `numeric` — double-precision float (default numeric mode)
285    Numeric,
286    /// `integer` — 32-bit integer (suffix `L` in literals)
287    Integer,
288    /// `logical` — boolean (TRUE/FALSE)
289    Logical,
290    /// `character` — string
291    Character,
292    /// `complex` — complex number
293    Complex,
294    /// `raw` — raw bytes
295    Raw,
296    /// `list` — heterogeneous list
297    List,
298    /// `data.frame` — tabular data
299    DataFrame,
300    /// `matrix` — 2-D homogeneous array
301    Matrix(Box<RType>),
302    /// `array` — N-dimensional homogeneous array
303    Array(Box<RType>, Vec<usize>),
304    /// `function` — R function
305    Function,
306    /// `environment` — R environment
307    Environment,
308    /// S3 class (informal, name-based)
309    S3(String),
310    /// S4 class (formal, slot-based)
311    S4(String),
312    /// R5 / Reference Class
313    R5(String),
314    /// R6 class (package R6)
315    R6(String),
316    /// `NULL`
317    Null,
318    /// `NA` (any mode)
319    Na,
320    /// Vector of a base type
321    Vector(Box<RType>),
322    /// Named list / environment
323    Named(String),
324}
325#[allow(dead_code)]
326#[derive(Debug, Clone, Default)]
327pub struct RLangPassStats {
328    pub total_runs: u32,
329    pub successful_runs: u32,
330    pub total_changes: u64,
331    pub time_ms: u64,
332    pub iterations_used: u32,
333}
334impl RLangPassStats {
335    #[allow(dead_code)]
336    pub fn new() -> Self {
337        Self::default()
338    }
339    #[allow(dead_code)]
340    pub fn record_run(&mut self, changes: u64, time_ms: u64, iterations: u32) {
341        self.total_runs += 1;
342        self.successful_runs += 1;
343        self.total_changes += changes;
344        self.time_ms += time_ms;
345        self.iterations_used = iterations;
346    }
347    #[allow(dead_code)]
348    pub fn average_changes_per_run(&self) -> f64 {
349        if self.total_runs == 0 {
350            return 0.0;
351        }
352        self.total_changes as f64 / self.total_runs as f64
353    }
354    #[allow(dead_code)]
355    pub fn success_rate(&self) -> f64 {
356        if self.total_runs == 0 {
357            return 0.0;
358        }
359        self.successful_runs as f64 / self.total_runs as f64
360    }
361    #[allow(dead_code)]
362    pub fn format_summary(&self) -> String {
363        format!(
364            "Runs: {}/{}, Changes: {}, Time: {}ms",
365            self.successful_runs, self.total_runs, self.total_changes, self.time_ms
366        )
367    }
368}
369/// Dominator tree for RLangExt.
370#[allow(dead_code)]
371#[derive(Debug, Clone)]
372pub struct RLangExtDomTree {
373    pub(super) idom: Vec<Option<usize>>,
374    pub(super) children: Vec<Vec<usize>>,
375    pub(super) depth: Vec<usize>,
376}
377impl RLangExtDomTree {
378    #[allow(dead_code)]
379    pub fn new(n: usize) -> Self {
380        Self {
381            idom: vec![None; n],
382            children: vec![Vec::new(); n],
383            depth: vec![0; n],
384        }
385    }
386    #[allow(dead_code)]
387    pub fn set_idom(&mut self, node: usize, dom: usize) {
388        if node < self.idom.len() {
389            self.idom[node] = Some(dom);
390            if dom < self.children.len() {
391                self.children[dom].push(node);
392            }
393            self.depth[node] = if dom < self.depth.len() {
394                self.depth[dom] + 1
395            } else {
396                1
397            };
398        }
399    }
400    #[allow(dead_code)]
401    pub fn dominates(&self, a: usize, mut b: usize) -> bool {
402        if a == b {
403            return true;
404        }
405        let n = self.idom.len();
406        for _ in 0..n {
407            match self.idom.get(b).copied().flatten() {
408                None => return false,
409                Some(p) if p == a => return true,
410                Some(p) if p == b => return false,
411                Some(p) => b = p,
412            }
413        }
414        false
415    }
416    #[allow(dead_code)]
417    pub fn children_of(&self, n: usize) -> &[usize] {
418        self.children.get(n).map(|v| v.as_slice()).unwrap_or(&[])
419    }
420    #[allow(dead_code)]
421    pub fn depth_of(&self, n: usize) -> usize {
422        self.depth.get(n).copied().unwrap_or(0)
423    }
424    #[allow(dead_code)]
425    pub fn lca(&self, mut a: usize, mut b: usize) -> usize {
426        let n = self.idom.len();
427        for _ in 0..(2 * n) {
428            if a == b {
429                return a;
430            }
431            if self.depth_of(a) > self.depth_of(b) {
432                a = self.idom.get(a).and_then(|x| *x).unwrap_or(a);
433            } else {
434                b = self.idom.get(b).and_then(|x| *x).unwrap_or(b);
435            }
436        }
437        0
438    }
439}
440#[allow(dead_code)]
441#[derive(Debug, Clone)]
442pub struct RLangPassConfig {
443    pub phase: RLangPassPhase,
444    pub enabled: bool,
445    pub max_iterations: u32,
446    pub debug_output: bool,
447    pub pass_name: String,
448}
449impl RLangPassConfig {
450    #[allow(dead_code)]
451    pub fn new(name: impl Into<String>, phase: RLangPassPhase) -> Self {
452        RLangPassConfig {
453            phase,
454            enabled: true,
455            max_iterations: 10,
456            debug_output: false,
457            pass_name: name.into(),
458        }
459    }
460    #[allow(dead_code)]
461    pub fn disabled(mut self) -> Self {
462        self.enabled = false;
463        self
464    }
465    #[allow(dead_code)]
466    pub fn with_debug(mut self) -> Self {
467        self.debug_output = true;
468        self
469    }
470    #[allow(dead_code)]
471    pub fn max_iter(mut self, n: u32) -> Self {
472        self.max_iterations = n;
473        self
474    }
475}
476/// Named or unnamed argument in a function call.
477#[derive(Debug, Clone, PartialEq)]
478pub struct RArg {
479    pub name: Option<String>,
480    pub value: RExpr,
481}
482impl RArg {
483    pub fn positional(value: RExpr) -> Self {
484        RArg { name: None, value }
485    }
486    pub fn named(name: &str, value: RExpr) -> Self {
487        RArg {
488            name: Some(name.to_string()),
489            value,
490        }
491    }
492}
493#[allow(dead_code)]
494#[derive(Debug, Clone)]
495pub struct RLangWorklist {
496    pub(super) items: std::collections::VecDeque<u32>,
497    pub(super) in_worklist: std::collections::HashSet<u32>,
498}
499impl RLangWorklist {
500    #[allow(dead_code)]
501    pub fn new() -> Self {
502        RLangWorklist {
503            items: std::collections::VecDeque::new(),
504            in_worklist: std::collections::HashSet::new(),
505        }
506    }
507    #[allow(dead_code)]
508    pub fn push(&mut self, item: u32) -> bool {
509        if self.in_worklist.insert(item) {
510            self.items.push_back(item);
511            true
512        } else {
513            false
514        }
515    }
516    #[allow(dead_code)]
517    pub fn pop(&mut self) -> Option<u32> {
518        let item = self.items.pop_front()?;
519        self.in_worklist.remove(&item);
520        Some(item)
521    }
522    #[allow(dead_code)]
523    pub fn is_empty(&self) -> bool {
524        self.items.is_empty()
525    }
526    #[allow(dead_code)]
527    pub fn len(&self) -> usize {
528        self.items.len()
529    }
530    #[allow(dead_code)]
531    pub fn contains(&self, item: u32) -> bool {
532        self.in_worklist.contains(&item)
533    }
534}
535/// Vectorized operation descriptor — captures element-wise or reduction ops.
536#[derive(Debug, Clone, PartialEq)]
537pub struct VectorizedOp {
538    /// The base R operator/function to apply element-wise
539    pub op: String,
540    /// Whether `Vectorize()` wrapper is needed
541    pub needs_vectorize: bool,
542    /// Whether `sapply`/`vapply` should be used
543    pub use_apply_family: Option<ApplyVariant>,
544    /// Whether broadcasting rules apply (recycling)
545    pub uses_recycling: bool,
546}
547impl VectorizedOp {
548    pub fn element_wise(op: &str) -> Self {
549        VectorizedOp {
550            op: op.to_string(),
551            needs_vectorize: false,
552            use_apply_family: None,
553            uses_recycling: true,
554        }
555    }
556    pub fn with_sapply(op: &str) -> Self {
557        VectorizedOp {
558            op: op.to_string(),
559            needs_vectorize: false,
560            use_apply_family: Some(ApplyVariant::Sapply),
561            uses_recycling: false,
562        }
563    }
564    pub fn with_vectorize(op: &str) -> Self {
565        VectorizedOp {
566            op: op.to_string(),
567            needs_vectorize: true,
568            use_apply_family: None,
569            uses_recycling: false,
570        }
571    }
572}
573/// Configuration for RLangExt passes.
574#[allow(dead_code)]
575#[derive(Debug, Clone)]
576pub struct RLangExtPassConfig {
577    pub name: String,
578    pub phase: RLangExtPassPhase,
579    pub enabled: bool,
580    pub max_iterations: usize,
581    pub debug: u32,
582    pub timeout_ms: Option<u64>,
583}
584impl RLangExtPassConfig {
585    #[allow(dead_code)]
586    pub fn new(name: impl Into<String>) -> Self {
587        Self {
588            name: name.into(),
589            phase: RLangExtPassPhase::Middle,
590            enabled: true,
591            max_iterations: 100,
592            debug: 0,
593            timeout_ms: None,
594        }
595    }
596    #[allow(dead_code)]
597    pub fn with_phase(mut self, phase: RLangExtPassPhase) -> Self {
598        self.phase = phase;
599        self
600    }
601    #[allow(dead_code)]
602    pub fn with_max_iter(mut self, n: usize) -> Self {
603        self.max_iterations = n;
604        self
605    }
606    #[allow(dead_code)]
607    pub fn with_debug(mut self, d: u32) -> Self {
608        self.debug = d;
609        self
610    }
611    #[allow(dead_code)]
612    pub fn disabled(mut self) -> Self {
613        self.enabled = false;
614        self
615    }
616    #[allow(dead_code)]
617    pub fn with_timeout(mut self, ms: u64) -> Self {
618        self.timeout_ms = Some(ms);
619        self
620    }
621    #[allow(dead_code)]
622    pub fn is_debug_enabled(&self) -> bool {
623        self.debug > 0
624    }
625}
626#[allow(dead_code)]
627pub struct RLangPassRegistry {
628    pub(super) configs: Vec<RLangPassConfig>,
629    pub(super) stats: std::collections::HashMap<String, RLangPassStats>,
630}
631impl RLangPassRegistry {
632    #[allow(dead_code)]
633    pub fn new() -> Self {
634        RLangPassRegistry {
635            configs: Vec::new(),
636            stats: std::collections::HashMap::new(),
637        }
638    }
639    #[allow(dead_code)]
640    pub fn register(&mut self, config: RLangPassConfig) {
641        self.stats
642            .insert(config.pass_name.clone(), RLangPassStats::new());
643        self.configs.push(config);
644    }
645    #[allow(dead_code)]
646    pub fn enabled_passes(&self) -> Vec<&RLangPassConfig> {
647        self.configs.iter().filter(|c| c.enabled).collect()
648    }
649    #[allow(dead_code)]
650    pub fn get_stats(&self, name: &str) -> Option<&RLangPassStats> {
651        self.stats.get(name)
652    }
653    #[allow(dead_code)]
654    pub fn total_passes(&self) -> usize {
655        self.configs.len()
656    }
657    #[allow(dead_code)]
658    pub fn enabled_count(&self) -> usize {
659        self.enabled_passes().len()
660    }
661    #[allow(dead_code)]
662    pub fn update_stats(&mut self, name: &str, changes: u64, time_ms: u64, iter: u32) {
663        if let Some(stats) = self.stats.get_mut(name) {
664            stats.record_run(changes, time_ms, iter);
665        }
666    }
667}
668/// Backend state for emitting R source code.
669pub struct RBackend {
670    /// Accumulated output buffer
671    pub(super) output: String,
672    /// Current indentation level
673    pub(super) indent: usize,
674    /// Indentation string (default: two spaces)
675    pub(super) indent_str: String,
676    /// Known S4 class definitions
677    pub(super) s4_classes: HashMap<String, Vec<(String, RType)>>,
678    /// Known S3 generics
679    pub(super) s3_generics: Vec<String>,
680    /// Vectorized operation registry
681    pub(super) vectorized_ops: HashMap<String, VectorizedOp>,
682}
683impl RBackend {
684    /// Create a new R backend with default settings.
685    pub fn new() -> Self {
686        RBackend {
687            output: String::new(),
688            indent: 0,
689            indent_str: "  ".to_string(),
690            s4_classes: HashMap::new(),
691            s3_generics: Vec::new(),
692            vectorized_ops: HashMap::new(),
693        }
694    }
695    /// Take the accumulated output, resetting the buffer.
696    pub fn take_output(&mut self) -> String {
697        std::mem::take(&mut self.output)
698    }
699    /// Register a vectorized operation.
700    pub fn register_vectorized(&mut self, name: &str, op: VectorizedOp) {
701        self.vectorized_ops.insert(name.to_string(), op);
702    }
703    pub(super) fn current_indent(&self) -> String {
704        self.indent_str.repeat(self.indent)
705    }
706    pub(super) fn emit_line(&mut self, line: &str) {
707        let indent = self.current_indent();
708        let _ = writeln!(self.output, "{}{}", indent, line);
709    }
710    pub(super) fn emit_raw(&mut self, s: &str) {
711        self.output.push_str(s);
712    }
713    pub(super) fn indent_up(&mut self) {
714        self.indent += 1;
715    }
716    pub(super) fn indent_down(&mut self) {
717        if self.indent > 0 {
718            self.indent -= 1;
719        }
720    }
721    /// Emit a complete R file.
722    pub fn emit_file(&mut self, file: &RFile) {
723        if let Some(shebang) = &file.shebang {
724            self.emit_line(shebang);
725        }
726        if let Some(header) = &file.header_comment {
727            for line in header.lines() {
728                self.emit_line(&format!("# {}", line));
729            }
730            self.emit_line("");
731        }
732        for pkg in &file.imports {
733            self.emit_line(&format!("library({})", pkg));
734        }
735        if !file.imports.is_empty() {
736            self.emit_line("");
737        }
738        for obj in &file.data_objects {
739            self.emit_data_object(obj);
740        }
741        if !file.data_objects.is_empty() {
742            self.emit_line("");
743        }
744        for fun in &file.functions {
745            self.emit_function(fun);
746            self.emit_line("");
747        }
748        for stmt in &file.scripts {
749            self.emit_stmt(stmt);
750        }
751    }
752    pub(super) fn emit_data_object(&mut self, obj: &RDataObject) {
753        if let Some(comment) = &obj.comment {
754            self.emit_line(&format!("# {}", comment));
755        }
756        let value_str = self.emit_expr(&obj.value);
757        self.emit_line(&format!("{} <- {}", obj.name, value_str));
758    }
759    /// Emit an R function definition.
760    pub fn emit_function(&mut self, fun: &RFunction) {
761        if let Some(doc) = &fun.doc {
762            for line in doc.lines() {
763                self.emit_line(&format!("#' {}", line));
764            }
765        }
766        let formals_str = self.emit_formals(&fun.formals);
767        self.emit_line(&format!("{} <- function({}) {{", fun.name, formals_str));
768        self.indent_up();
769        if fun.is_generic {
770            self.emit_line(&format!("UseMethod(\"{}\")", fun.name));
771        } else {
772            for stmt in &fun.body {
773                self.emit_stmt(stmt);
774            }
775        }
776        self.indent_down();
777        self.emit_line("}");
778        for (class, method) in &fun.s3_methods {
779            let method_name = format!("{}.{}", fun.name, class);
780            let formals_str2 = self.emit_formals(&method.formals);
781            self.emit_line(&format!("{} <- function({}) {{", method_name, formals_str2));
782            self.indent_up();
783            for stmt in &method.body {
784                self.emit_stmt(stmt);
785            }
786            self.indent_down();
787            self.emit_line("}");
788        }
789    }
790    pub(super) fn emit_formals(&self, formals: &[RFormal]) -> String {
791        let mut parts = Vec::new();
792        for formal in formals {
793            if let Some(default) = &formal.default {
794                let default_str = self.emit_expr_pure(default);
795                parts.push(format!("{} = {}", formal.name, default_str));
796            } else {
797                parts.push(formal.name.clone());
798            }
799        }
800        parts.join(", ")
801    }
802    /// Emit a single R statement.
803    pub fn emit_stmt(&mut self, stmt: &RStmt) {
804        match stmt {
805            RStmt::Assign(op, lhs, rhs) => {
806                let rhs_str = self.emit_expr(rhs);
807                self.emit_line(&format!("{} {} {}", lhs, op, rhs_str));
808            }
809            RStmt::AssignLhs(op, lhs, rhs) => {
810                let lhs_str = self.emit_expr(lhs);
811                let rhs_str = self.emit_expr(rhs);
812                self.emit_line(&format!("{} {} {}", lhs_str, op, rhs_str));
813            }
814            RStmt::ForLoop { var, seq, body } => {
815                let seq_str = self.emit_expr(seq);
816                self.emit_line(&format!("for ({} in {}) {{", var, seq_str));
817                self.indent_up();
818                for s in body {
819                    self.emit_stmt(s);
820                }
821                self.indent_down();
822                self.emit_line("}");
823            }
824            RStmt::WhileLoop { cond, body } => {
825                let cond_str = self.emit_expr(cond);
826                self.emit_line(&format!("while ({}) {{", cond_str));
827                self.indent_up();
828                for s in body {
829                    self.emit_stmt(s);
830                }
831                self.indent_down();
832                self.emit_line("}");
833            }
834            RStmt::Repeat(body) => {
835                self.emit_line("repeat {");
836                self.indent_up();
837                for s in body {
838                    self.emit_stmt(s);
839                }
840                self.indent_down();
841                self.emit_line("}");
842            }
843            RStmt::IfElse {
844                cond,
845                then_body,
846                else_if_branches,
847                else_body,
848            } => {
849                let cond_str = self.emit_expr(cond);
850                self.emit_line(&format!("if ({}) {{", cond_str));
851                self.indent_up();
852                for s in then_body {
853                    self.emit_stmt(s);
854                }
855                self.indent_down();
856                for (elif_cond, elif_body) in else_if_branches {
857                    let elif_cond_str = self.emit_expr(elif_cond);
858                    self.emit_line(&format!("}} else if ({}) {{", elif_cond_str));
859                    self.indent_up();
860                    for s in elif_body {
861                        self.emit_stmt(s);
862                    }
863                    self.indent_down();
864                }
865                if let Some(else_stmts) = else_body {
866                    self.emit_line("} else {");
867                    self.indent_up();
868                    for s in else_stmts {
869                        self.emit_stmt(s);
870                    }
871                    self.indent_down();
872                }
873                self.emit_line("}");
874            }
875            RStmt::Return(expr) => {
876                if let Some(e) = expr {
877                    let e_str = self.emit_expr(e);
878                    self.emit_line(&format!("return({})", e_str));
879                } else {
880                    self.emit_line("return(invisible(NULL))");
881                }
882            }
883            RStmt::Next => {
884                self.emit_line("next");
885            }
886            RStmt::Break => {
887                self.emit_line("break");
888            }
889            RStmt::FunctionDef(fun) => {
890                self.emit_function(fun);
891            }
892            RStmt::Library { pkg, use_require } => {
893                if *use_require {
894                    self.emit_line(&format!("require({}, quietly = TRUE)", pkg));
895                } else {
896                    self.emit_line(&format!("library({})", pkg));
897                }
898            }
899            RStmt::Source(path) => {
900                self.emit_line(&format!("source(\"{}\")", path));
901            }
902            RStmt::Expr(expr) => {
903                let e_str = self.emit_expr(expr);
904                self.emit_line(&e_str);
905            }
906            RStmt::Comment(text) => {
907                for line in text.lines() {
908                    self.emit_line(&format!("# {}", line));
909                }
910            }
911            RStmt::Stopifnot(conds) => {
912                let conds_str: Vec<String> = conds.iter().map(|c| self.emit_expr_pure(c)).collect();
913                self.emit_line(&format!("stopifnot({})", conds_str.join(", ")));
914            }
915            RStmt::TryCatch {
916                body,
917                handlers,
918                finally,
919            } => {
920                self.emit_line("tryCatch({");
921                self.indent_up();
922                for s in body {
923                    self.emit_stmt(s);
924                }
925                self.indent_down();
926                self.emit_raw(&self.current_indent());
927                self.emit_raw("}");
928                for (condition, formal, handler_body) in handlers {
929                    self.emit_raw(&format!(
930                        ",\n{}{} = function({}) {{\n",
931                        self.current_indent(),
932                        condition,
933                        formal.name
934                    ));
935                    self.indent_up();
936                    let handler_stmts: Vec<String> = handler_body
937                        .iter()
938                        .map(|s| {
939                            let mut tmp = RBackend::new();
940                            tmp.indent = self.indent;
941                            tmp.emit_stmt(s);
942                            tmp.take_output()
943                        })
944                        .collect();
945                    for h in handler_stmts {
946                        self.emit_raw(&h);
947                    }
948                    self.indent_down();
949                    self.emit_raw(&format!("{}}}", self.current_indent()));
950                }
951                if let Some(fin) = finally {
952                    self.emit_raw(",\nfinally = {\n");
953                    self.indent_up();
954                    for s in fin {
955                        self.emit_stmt(s);
956                    }
957                    self.indent_down();
958                    self.emit_raw(&format!("{}}}", self.current_indent()));
959                }
960                self.emit_raw(")\n");
961            }
962            RStmt::SetMethod {
963                generic,
964                signature,
965                fun,
966            } => {
967                let sig_str: Vec<String> = signature.iter().map(|s| format!("\"{}\"", s)).collect();
968                let formals_str = self.emit_formals(&fun.formals);
969                self.emit_line(&format!(
970                    "setMethod(\"{}\", signature({}), function({}) {{",
971                    generic,
972                    sig_str.join(", "),
973                    formals_str
974                ));
975                self.indent_up();
976                for s in &fun.body {
977                    self.emit_stmt(s);
978                }
979                self.indent_down();
980                self.emit_line("})");
981            }
982            RStmt::SetClass {
983                class,
984                contains,
985                slots,
986            } => {
987                let slots_str: Vec<String> = slots
988                    .iter()
989                    .map(|(name, ty)| format!("{} = \"{}\"", name, ty))
990                    .collect();
991                let contains_str = if let Some(parent) = contains {
992                    format!(", contains = \"{}\"", parent)
993                } else {
994                    String::new()
995                };
996                self.emit_line(&format!(
997                    "setClass(\"{}\", slots = c({}){})  ",
998                    class,
999                    slots_str.join(", "),
1000                    contains_str
1001                ));
1002            }
1003        }
1004    }
1005    /// Emit an R expression to a string (may use output buffer for nested stmts).
1006    pub fn emit_expr(&mut self, expr: &RExpr) -> String {
1007        self.emit_expr_pure(expr)
1008    }
1009    /// Emit an R expression to a string (pure, no side-effects on buffer).
1010    pub fn emit_expr_pure(&self, expr: &RExpr) -> String {
1011        match expr {
1012            RExpr::Lit(lit) => self.emit_literal(lit),
1013            RExpr::Var(name) => name.clone(),
1014            RExpr::Call(func, args) => {
1015                let func_str = self.emit_expr_pure(func);
1016                let args_str: Vec<String> = args.iter().map(|a| self.emit_arg(a)).collect();
1017                format!("{}({})", func_str, args_str.join(", "))
1018            }
1019            RExpr::InfixOp(op, lhs, rhs) => {
1020                let lhs_str = self.emit_expr_pure(lhs);
1021                let rhs_str = self.emit_expr_pure(rhs);
1022                format!("{} {} {}", lhs_str, op, rhs_str)
1023            }
1024            RExpr::UnaryOp(op, operand) => {
1025                let operand_str = self.emit_expr_pure(operand);
1026                if op == "!" || op == "-" || op == "+" {
1027                    format!("{}{}", op, operand_str)
1028                } else {
1029                    format!("{}({})", op, operand_str)
1030                }
1031            }
1032            RExpr::IndexSingle(obj, indices) => {
1033                let obj_str = self.emit_expr_pure(obj);
1034                let idx_str: Vec<String> = indices.iter().map(|i| self.emit_expr_pure(i)).collect();
1035                format!("{}[{}]", obj_str, idx_str.join(", "))
1036            }
1037            RExpr::IndexDouble(obj, index) => {
1038                let obj_str = self.emit_expr_pure(obj);
1039                let idx_str = self.emit_expr_pure(index);
1040                format!("{}[[{}]]", obj_str, idx_str)
1041            }
1042            RExpr::DollarAccess(obj, field) => {
1043                let obj_str = self.emit_expr_pure(obj);
1044                format!("{}${}", obj_str, field)
1045            }
1046            RExpr::AtAccess(obj, slot) => {
1047                let obj_str = self.emit_expr_pure(obj);
1048                format!("{}@{}", obj_str, slot)
1049            }
1050            RExpr::Formula(lhs, rhs) => {
1051                let rhs_str = self.emit_expr_pure(rhs);
1052                if let Some(lhs_expr) = lhs {
1053                    let lhs_str = self.emit_expr_pure(lhs_expr);
1054                    format!("{} ~ {}", lhs_str, rhs_str)
1055                } else {
1056                    format!("~ {}", rhs_str)
1057                }
1058            }
1059            RExpr::IfElse(cond, then_expr, else_expr) => {
1060                let cond_str = self.emit_expr_pure(cond);
1061                let then_str = self.emit_expr_pure(then_expr);
1062                if let Some(else_e) = else_expr {
1063                    let else_str = self.emit_expr_pure(else_e);
1064                    format!("if ({}) {} else {}", cond_str, then_str, else_str)
1065                } else {
1066                    format!("if ({}) {}", cond_str, then_str)
1067                }
1068            }
1069            RExpr::Lambda(formals, body) => {
1070                let formals_str = self.emit_formals(formals);
1071                let body_str = self.emit_expr_pure(body);
1072                format!("function({}) {}", formals_str, body_str)
1073            }
1074            RExpr::Pipe(lhs, rhs) => {
1075                let lhs_str = self.emit_expr_pure(lhs);
1076                let rhs_str = self.emit_expr_pure(rhs);
1077                format!("{} |> {}", lhs_str, rhs_str)
1078            }
1079            RExpr::MagrittrPipe(lhs, rhs) => {
1080                let lhs_str = self.emit_expr_pure(lhs);
1081                let rhs_str = self.emit_expr_pure(rhs);
1082                format!("{} %>% {}", lhs_str, rhs_str)
1083            }
1084            RExpr::Seq(start, end) => {
1085                let start_str = self.emit_expr_pure(start);
1086                let end_str = self.emit_expr_pure(end);
1087                format!("{}:{}", start_str, end_str)
1088            }
1089            RExpr::CVec(elems) => {
1090                let elems_str: Vec<String> = elems.iter().map(|e| self.emit_expr_pure(e)).collect();
1091                format!("c({})", elems_str.join(", "))
1092            }
1093            RExpr::ListExpr(args) => {
1094                let args_str: Vec<String> = args.iter().map(|a| self.emit_arg(a)).collect();
1095                format!("list({})", args_str.join(", "))
1096            }
1097            RExpr::Block(stmts) => {
1098                if stmts.is_empty() {
1099                    return "{}".to_string();
1100                }
1101                let mut inner = RBackend::new();
1102                inner.indent = self.indent + 1;
1103                for s in stmts {
1104                    inner.emit_stmt(s);
1105                }
1106                let inner_out = inner.take_output();
1107                format!("{{\n{}{}}}", inner_out, self.current_indent())
1108            }
1109            RExpr::Namespace(pkg, func) => format!("{}::{}", pkg, func),
1110            RExpr::NamespaceInternal(pkg, func) => format!("{}:::{}", pkg, func),
1111        }
1112    }
1113    pub(super) fn emit_literal(&self, lit: &RLiteral) -> String {
1114        match lit {
1115            RLiteral::Integer(n) => format!("{}L", n),
1116            RLiteral::Numeric(f) => {
1117                if f.fract() == 0.0 && f.abs() < 1e15 {
1118                    format!("{:.1}", f)
1119                } else {
1120                    format!("{}", f)
1121                }
1122            }
1123            RLiteral::Logical(b) => {
1124                if *b {
1125                    "TRUE".to_string()
1126                } else {
1127                    "FALSE".to_string()
1128                }
1129            }
1130            RLiteral::Character(s) => format!("\"{}\"", s.replace('"', "\\\"")),
1131            RLiteral::Complex(re, im) => {
1132                if *im >= 0.0 {
1133                    format!("{}+{}i", re, im)
1134                } else {
1135                    format!("{}{}i", re, im)
1136                }
1137            }
1138            RLiteral::Null => "NULL".to_string(),
1139            RLiteral::Na => "NA".to_string(),
1140            RLiteral::NaInteger => "NA_integer_".to_string(),
1141            RLiteral::NaReal => "NA_real_".to_string(),
1142            RLiteral::NaCharacter => "NA_character_".to_string(),
1143            RLiteral::NaComplex => "NA_complex_".to_string(),
1144            RLiteral::Inf => "Inf".to_string(),
1145            RLiteral::NaN => "NaN".to_string(),
1146        }
1147    }
1148    pub(super) fn emit_arg(&self, arg: &RArg) -> String {
1149        let val_str = self.emit_expr_pure(&arg.value);
1150        if let Some(name) = &arg.name {
1151            format!("{} = {}", name, val_str)
1152        } else {
1153            val_str
1154        }
1155    }
1156    /// Emit a vectorized operation over a vector expression.
1157    pub fn emit_vectorized(
1158        &self,
1159        op: &VectorizedOp,
1160        vec_expr: &RExpr,
1161        extra_args: &[RArg],
1162    ) -> String {
1163        let vec_str = self.emit_expr_pure(vec_expr);
1164        if let Some(apply_fn) = &op.use_apply_family {
1165            let func_expr = RExpr::Var(op.op.clone());
1166            let func_str = self.emit_expr_pure(&func_expr);
1167            let mut args_str = format!("{}, {}", vec_str, func_str);
1168            for a in extra_args {
1169                args_str.push_str(", ");
1170                args_str.push_str(&self.emit_arg(a));
1171            }
1172            format!("{}({})", apply_fn, args_str)
1173        } else if op.needs_vectorize {
1174            let func_str = op.op.clone();
1175            let extra: Vec<String> = extra_args.iter().map(|a| self.emit_arg(a)).collect();
1176            if extra.is_empty() {
1177                format!("Vectorize({})({})", func_str, vec_str)
1178            } else {
1179                format!("Vectorize({})({}{})", func_str, vec_str, extra.join(", "))
1180            }
1181        } else {
1182            let mut args_str = vec_str;
1183            for a in extra_args {
1184                args_str.push_str(", ");
1185                args_str.push_str(&self.emit_arg(a));
1186            }
1187            format!("{}({})", op.op, args_str)
1188        }
1189    }
1190}
1191/// A data object to be emitted (e.g., saved with `saveRDS` or inlined).
1192#[derive(Debug, Clone, PartialEq)]
1193pub struct RDataObject {
1194    /// Variable name
1195    pub name: String,
1196    /// The expression producing the data
1197    pub value: RExpr,
1198    /// Optional comment
1199    pub comment: Option<String>,
1200}
1201#[allow(dead_code)]
1202#[derive(Debug, Clone)]
1203pub struct RLangLivenessInfo {
1204    pub live_in: Vec<std::collections::HashSet<u32>>,
1205    pub live_out: Vec<std::collections::HashSet<u32>>,
1206    pub defs: Vec<std::collections::HashSet<u32>>,
1207    pub uses: Vec<std::collections::HashSet<u32>>,
1208}
1209impl RLangLivenessInfo {
1210    #[allow(dead_code)]
1211    pub fn new(block_count: usize) -> Self {
1212        RLangLivenessInfo {
1213            live_in: vec![std::collections::HashSet::new(); block_count],
1214            live_out: vec![std::collections::HashSet::new(); block_count],
1215            defs: vec![std::collections::HashSet::new(); block_count],
1216            uses: vec![std::collections::HashSet::new(); block_count],
1217        }
1218    }
1219    #[allow(dead_code)]
1220    pub fn add_def(&mut self, block: usize, var: u32) {
1221        if block < self.defs.len() {
1222            self.defs[block].insert(var);
1223        }
1224    }
1225    #[allow(dead_code)]
1226    pub fn add_use(&mut self, block: usize, var: u32) {
1227        if block < self.uses.len() {
1228            self.uses[block].insert(var);
1229        }
1230    }
1231    #[allow(dead_code)]
1232    pub fn is_live_in(&self, block: usize, var: u32) -> bool {
1233        self.live_in
1234            .get(block)
1235            .map(|s| s.contains(&var))
1236            .unwrap_or(false)
1237    }
1238    #[allow(dead_code)]
1239    pub fn is_live_out(&self, block: usize, var: u32) -> bool {
1240        self.live_out
1241            .get(block)
1242            .map(|s| s.contains(&var))
1243            .unwrap_or(false)
1244    }
1245}
1246#[allow(dead_code)]
1247pub struct RLangConstantFoldingHelper;
1248impl RLangConstantFoldingHelper {
1249    #[allow(dead_code)]
1250    pub fn fold_add_i64(a: i64, b: i64) -> Option<i64> {
1251        a.checked_add(b)
1252    }
1253    #[allow(dead_code)]
1254    pub fn fold_sub_i64(a: i64, b: i64) -> Option<i64> {
1255        a.checked_sub(b)
1256    }
1257    #[allow(dead_code)]
1258    pub fn fold_mul_i64(a: i64, b: i64) -> Option<i64> {
1259        a.checked_mul(b)
1260    }
1261    #[allow(dead_code)]
1262    pub fn fold_div_i64(a: i64, b: i64) -> Option<i64> {
1263        if b == 0 {
1264            None
1265        } else {
1266            a.checked_div(b)
1267        }
1268    }
1269    #[allow(dead_code)]
1270    pub fn fold_add_f64(a: f64, b: f64) -> f64 {
1271        a + b
1272    }
1273    #[allow(dead_code)]
1274    pub fn fold_mul_f64(a: f64, b: f64) -> f64 {
1275        a * b
1276    }
1277    #[allow(dead_code)]
1278    pub fn fold_neg_i64(a: i64) -> Option<i64> {
1279        a.checked_neg()
1280    }
1281    #[allow(dead_code)]
1282    pub fn fold_not_bool(a: bool) -> bool {
1283        !a
1284    }
1285    #[allow(dead_code)]
1286    pub fn fold_and_bool(a: bool, b: bool) -> bool {
1287        a && b
1288    }
1289    #[allow(dead_code)]
1290    pub fn fold_or_bool(a: bool, b: bool) -> bool {
1291        a || b
1292    }
1293    #[allow(dead_code)]
1294    pub fn fold_shl_i64(a: i64, b: u32) -> Option<i64> {
1295        a.checked_shl(b)
1296    }
1297    #[allow(dead_code)]
1298    pub fn fold_shr_i64(a: i64, b: u32) -> Option<i64> {
1299        a.checked_shr(b)
1300    }
1301    #[allow(dead_code)]
1302    pub fn fold_rem_i64(a: i64, b: i64) -> Option<i64> {
1303        if b == 0 {
1304            None
1305        } else {
1306            Some(a % b)
1307        }
1308    }
1309    #[allow(dead_code)]
1310    pub fn fold_bitand_i64(a: i64, b: i64) -> i64 {
1311        a & b
1312    }
1313    #[allow(dead_code)]
1314    pub fn fold_bitor_i64(a: i64, b: i64) -> i64 {
1315        a | b
1316    }
1317    #[allow(dead_code)]
1318    pub fn fold_bitxor_i64(a: i64, b: i64) -> i64 {
1319        a ^ b
1320    }
1321    #[allow(dead_code)]
1322    pub fn fold_bitnot_i64(a: i64) -> i64 {
1323        !a
1324    }
1325}
1326/// Pass execution phase for RLangExt.
1327#[allow(dead_code)]
1328#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1329pub enum RLangExtPassPhase {
1330    Early,
1331    Middle,
1332    Late,
1333    Finalize,
1334}
1335impl RLangExtPassPhase {
1336    #[allow(dead_code)]
1337    pub fn is_early(&self) -> bool {
1338        matches!(self, Self::Early)
1339    }
1340    #[allow(dead_code)]
1341    pub fn is_middle(&self) -> bool {
1342        matches!(self, Self::Middle)
1343    }
1344    #[allow(dead_code)]
1345    pub fn is_late(&self) -> bool {
1346        matches!(self, Self::Late)
1347    }
1348    #[allow(dead_code)]
1349    pub fn is_finalize(&self) -> bool {
1350        matches!(self, Self::Finalize)
1351    }
1352    #[allow(dead_code)]
1353    pub fn order(&self) -> u32 {
1354        match self {
1355            Self::Early => 0,
1356            Self::Middle => 1,
1357            Self::Late => 2,
1358            Self::Finalize => 3,
1359        }
1360    }
1361    #[allow(dead_code)]
1362    pub fn from_order(n: u32) -> Option<Self> {
1363        match n {
1364            0 => Some(Self::Early),
1365            1 => Some(Self::Middle),
1366            2 => Some(Self::Late),
1367            3 => Some(Self::Finalize),
1368            _ => None,
1369        }
1370    }
1371}
1372/// Liveness analysis for RLangExt.
1373#[allow(dead_code)]
1374#[derive(Debug, Clone, Default)]
1375pub struct RLangExtLiveness {
1376    pub live_in: Vec<Vec<usize>>,
1377    pub live_out: Vec<Vec<usize>>,
1378    pub defs: Vec<Vec<usize>>,
1379    pub uses: Vec<Vec<usize>>,
1380}
1381impl RLangExtLiveness {
1382    #[allow(dead_code)]
1383    pub fn new(n: usize) -> Self {
1384        Self {
1385            live_in: vec![Vec::new(); n],
1386            live_out: vec![Vec::new(); n],
1387            defs: vec![Vec::new(); n],
1388            uses: vec![Vec::new(); n],
1389        }
1390    }
1391    #[allow(dead_code)]
1392    pub fn live_in(&self, b: usize, v: usize) -> bool {
1393        self.live_in.get(b).map(|s| s.contains(&v)).unwrap_or(false)
1394    }
1395    #[allow(dead_code)]
1396    pub fn live_out(&self, b: usize, v: usize) -> bool {
1397        self.live_out
1398            .get(b)
1399            .map(|s| s.contains(&v))
1400            .unwrap_or(false)
1401    }
1402    #[allow(dead_code)]
1403    pub fn add_def(&mut self, b: usize, v: usize) {
1404        if let Some(s) = self.defs.get_mut(b) {
1405            if !s.contains(&v) {
1406                s.push(v);
1407            }
1408        }
1409    }
1410    #[allow(dead_code)]
1411    pub fn add_use(&mut self, b: usize, v: usize) {
1412        if let Some(s) = self.uses.get_mut(b) {
1413            if !s.contains(&v) {
1414                s.push(v);
1415            }
1416        }
1417    }
1418    #[allow(dead_code)]
1419    pub fn var_is_used_in_block(&self, b: usize, v: usize) -> bool {
1420        self.uses.get(b).map(|s| s.contains(&v)).unwrap_or(false)
1421    }
1422    #[allow(dead_code)]
1423    pub fn var_is_def_in_block(&self, b: usize, v: usize) -> bool {
1424        self.defs.get(b).map(|s| s.contains(&v)).unwrap_or(false)
1425    }
1426}
1427/// Pass registry for RLangExt.
1428#[allow(dead_code)]
1429#[derive(Debug, Default)]
1430pub struct RLangExtPassRegistry {
1431    pub(super) configs: Vec<RLangExtPassConfig>,
1432    pub(super) stats: Vec<RLangExtPassStats>,
1433}
1434impl RLangExtPassRegistry {
1435    #[allow(dead_code)]
1436    pub fn new() -> Self {
1437        Self::default()
1438    }
1439    #[allow(dead_code)]
1440    pub fn register(&mut self, c: RLangExtPassConfig) {
1441        self.stats.push(RLangExtPassStats::new());
1442        self.configs.push(c);
1443    }
1444    #[allow(dead_code)]
1445    pub fn len(&self) -> usize {
1446        self.configs.len()
1447    }
1448    #[allow(dead_code)]
1449    pub fn is_empty(&self) -> bool {
1450        self.configs.is_empty()
1451    }
1452    #[allow(dead_code)]
1453    pub fn get(&self, i: usize) -> Option<&RLangExtPassConfig> {
1454        self.configs.get(i)
1455    }
1456    #[allow(dead_code)]
1457    pub fn get_stats(&self, i: usize) -> Option<&RLangExtPassStats> {
1458        self.stats.get(i)
1459    }
1460    #[allow(dead_code)]
1461    pub fn enabled_passes(&self) -> Vec<&RLangExtPassConfig> {
1462        self.configs.iter().filter(|c| c.enabled).collect()
1463    }
1464    #[allow(dead_code)]
1465    pub fn passes_in_phase(&self, ph: &RLangExtPassPhase) -> Vec<&RLangExtPassConfig> {
1466        self.configs
1467            .iter()
1468            .filter(|c| c.enabled && &c.phase == ph)
1469            .collect()
1470    }
1471    #[allow(dead_code)]
1472    pub fn total_nodes_visited(&self) -> usize {
1473        self.stats.iter().map(|s| s.nodes_visited).sum()
1474    }
1475    #[allow(dead_code)]
1476    pub fn any_changed(&self) -> bool {
1477        self.stats.iter().any(|s| s.changed)
1478    }
1479}
1480#[allow(dead_code)]
1481#[derive(Debug, Clone)]
1482pub struct RLangAnalysisCache {
1483    pub(super) entries: std::collections::HashMap<String, RLangCacheEntry>,
1484    pub(super) max_size: usize,
1485    pub(super) hits: u64,
1486    pub(super) misses: u64,
1487}
1488impl RLangAnalysisCache {
1489    #[allow(dead_code)]
1490    pub fn new(max_size: usize) -> Self {
1491        RLangAnalysisCache {
1492            entries: std::collections::HashMap::new(),
1493            max_size,
1494            hits: 0,
1495            misses: 0,
1496        }
1497    }
1498    #[allow(dead_code)]
1499    pub fn get(&mut self, key: &str) -> Option<&RLangCacheEntry> {
1500        if self.entries.contains_key(key) {
1501            self.hits += 1;
1502            self.entries.get(key)
1503        } else {
1504            self.misses += 1;
1505            None
1506        }
1507    }
1508    #[allow(dead_code)]
1509    pub fn insert(&mut self, key: String, data: Vec<u8>) {
1510        if self.entries.len() >= self.max_size {
1511            if let Some(oldest) = self.entries.keys().next().cloned() {
1512                self.entries.remove(&oldest);
1513            }
1514        }
1515        self.entries.insert(
1516            key.clone(),
1517            RLangCacheEntry {
1518                key,
1519                data,
1520                timestamp: 0,
1521                valid: true,
1522            },
1523        );
1524    }
1525    #[allow(dead_code)]
1526    pub fn invalidate(&mut self, key: &str) {
1527        if let Some(entry) = self.entries.get_mut(key) {
1528            entry.valid = false;
1529        }
1530    }
1531    #[allow(dead_code)]
1532    pub fn clear(&mut self) {
1533        self.entries.clear();
1534    }
1535    #[allow(dead_code)]
1536    pub fn hit_rate(&self) -> f64 {
1537        let total = self.hits + self.misses;
1538        if total == 0 {
1539            return 0.0;
1540        }
1541        self.hits as f64 / total as f64
1542    }
1543    #[allow(dead_code)]
1544    pub fn size(&self) -> usize {
1545        self.entries.len()
1546    }
1547}
1548/// R statement.
1549#[derive(Debug, Clone, PartialEq)]
1550pub enum RStmt {
1551    /// Assignment: `x <- expr` or `x <<- expr` or `x = expr`
1552    Assign(RAssignOp, String, RExpr),
1553    /// Complex left-hand side assignment: `x$field <- expr`
1554    AssignLhs(RAssignOp, RExpr, RExpr),
1555    /// `for (var in seq) { body }`
1556    ForLoop {
1557        var: String,
1558        seq: RExpr,
1559        body: Vec<RStmt>,
1560    },
1561    /// `while (cond) { body }`
1562    WhileLoop { cond: RExpr, body: Vec<RStmt> },
1563    /// `repeat { body }`
1564    Repeat(Vec<RStmt>),
1565    /// `if (cond) { then } else if ... else { else }`
1566    IfElse {
1567        cond: RExpr,
1568        then_body: Vec<RStmt>,
1569        else_if_branches: Vec<(RExpr, Vec<RStmt>)>,
1570        else_body: Option<Vec<RStmt>>,
1571    },
1572    /// `return(expr)`
1573    Return(Option<RExpr>),
1574    /// `next` (continue)
1575    Next,
1576    /// `break`
1577    Break,
1578    /// Function definition: `name <- function(formals) { body }`
1579    FunctionDef(RFunction),
1580    /// `library(pkg)` or `require(pkg)`
1581    Library { pkg: String, use_require: bool },
1582    /// `source("file.R")`
1583    Source(String),
1584    /// Expression statement
1585    Expr(RExpr),
1586    /// Comment: `# text`
1587    Comment(String),
1588    /// `stopifnot(...)` assertion
1589    Stopifnot(Vec<RExpr>),
1590    /// `tryCatch({ body }, error = function(e) { handler })`
1591    TryCatch {
1592        body: Vec<RStmt>,
1593        handlers: Vec<(String, RFormal, Vec<RStmt>)>,
1594        finally: Option<Vec<RStmt>>,
1595    },
1596    /// S4 method definition: `setMethod(generic, signature, function)`
1597    SetMethod {
1598        generic: String,
1599        signature: Vec<String>,
1600        fun: RFunction,
1601    },
1602    /// S4 class definition
1603    SetClass {
1604        class: String,
1605        contains: Option<String>,
1606        slots: Vec<(String, RType)>,
1607    },
1608}
1609/// Analysis cache for RLangExt.
1610#[allow(dead_code)]
1611#[derive(Debug)]
1612pub struct RLangExtCache {
1613    pub(super) entries: Vec<(u64, Vec<u8>, bool, u32)>,
1614    pub(super) cap: usize,
1615    pub(super) total_hits: u64,
1616    pub(super) total_misses: u64,
1617}
1618impl RLangExtCache {
1619    #[allow(dead_code)]
1620    pub fn new(cap: usize) -> Self {
1621        Self {
1622            entries: Vec::new(),
1623            cap,
1624            total_hits: 0,
1625            total_misses: 0,
1626        }
1627    }
1628    #[allow(dead_code)]
1629    pub fn get(&mut self, key: u64) -> Option<&[u8]> {
1630        for e in self.entries.iter_mut() {
1631            if e.0 == key && e.2 {
1632                e.3 += 1;
1633                self.total_hits += 1;
1634                return Some(&e.1);
1635            }
1636        }
1637        self.total_misses += 1;
1638        None
1639    }
1640    #[allow(dead_code)]
1641    pub fn put(&mut self, key: u64, data: Vec<u8>) {
1642        if self.entries.len() >= self.cap {
1643            self.entries.retain(|e| e.2);
1644            if self.entries.len() >= self.cap {
1645                self.entries.remove(0);
1646            }
1647        }
1648        self.entries.push((key, data, true, 0));
1649    }
1650    #[allow(dead_code)]
1651    pub fn invalidate(&mut self) {
1652        for e in self.entries.iter_mut() {
1653            e.2 = false;
1654        }
1655    }
1656    #[allow(dead_code)]
1657    pub fn hit_rate(&self) -> f64 {
1658        let t = self.total_hits + self.total_misses;
1659        if t == 0 {
1660            0.0
1661        } else {
1662            self.total_hits as f64 / t as f64
1663        }
1664    }
1665    #[allow(dead_code)]
1666    pub fn live_count(&self) -> usize {
1667        self.entries.iter().filter(|e| e.2).count()
1668    }
1669}
1670/// Statistics for RLangExt passes.
1671#[allow(dead_code)]
1672#[derive(Debug, Clone, Default)]
1673pub struct RLangExtPassStats {
1674    pub iterations: usize,
1675    pub changed: bool,
1676    pub nodes_visited: usize,
1677    pub nodes_modified: usize,
1678    pub time_ms: u64,
1679    pub memory_bytes: usize,
1680    pub errors: usize,
1681}
1682impl RLangExtPassStats {
1683    #[allow(dead_code)]
1684    pub fn new() -> Self {
1685        Self::default()
1686    }
1687    #[allow(dead_code)]
1688    pub fn visit(&mut self) {
1689        self.nodes_visited += 1;
1690    }
1691    #[allow(dead_code)]
1692    pub fn modify(&mut self) {
1693        self.nodes_modified += 1;
1694        self.changed = true;
1695    }
1696    #[allow(dead_code)]
1697    pub fn iterate(&mut self) {
1698        self.iterations += 1;
1699    }
1700    #[allow(dead_code)]
1701    pub fn error(&mut self) {
1702        self.errors += 1;
1703    }
1704    #[allow(dead_code)]
1705    pub fn efficiency(&self) -> f64 {
1706        if self.nodes_visited == 0 {
1707            0.0
1708        } else {
1709            self.nodes_modified as f64 / self.nodes_visited as f64
1710        }
1711    }
1712    #[allow(dead_code)]
1713    pub fn merge(&mut self, o: &RLangExtPassStats) {
1714        self.iterations += o.iterations;
1715        self.changed |= o.changed;
1716        self.nodes_visited += o.nodes_visited;
1717        self.nodes_modified += o.nodes_modified;
1718        self.time_ms += o.time_ms;
1719        self.memory_bytes = self.memory_bytes.max(o.memory_bytes);
1720        self.errors += o.errors;
1721    }
1722}
1723/// Worklist for RLangExt.
1724#[allow(dead_code)]
1725#[derive(Debug, Clone)]
1726pub struct RLangExtWorklist {
1727    pub(super) items: std::collections::VecDeque<usize>,
1728    pub(super) present: Vec<bool>,
1729}
1730impl RLangExtWorklist {
1731    #[allow(dead_code)]
1732    pub fn new(capacity: usize) -> Self {
1733        Self {
1734            items: std::collections::VecDeque::new(),
1735            present: vec![false; capacity],
1736        }
1737    }
1738    #[allow(dead_code)]
1739    pub fn push(&mut self, id: usize) {
1740        if id < self.present.len() && !self.present[id] {
1741            self.present[id] = true;
1742            self.items.push_back(id);
1743        }
1744    }
1745    #[allow(dead_code)]
1746    pub fn push_front(&mut self, id: usize) {
1747        if id < self.present.len() && !self.present[id] {
1748            self.present[id] = true;
1749            self.items.push_front(id);
1750        }
1751    }
1752    #[allow(dead_code)]
1753    pub fn pop(&mut self) -> Option<usize> {
1754        let id = self.items.pop_front()?;
1755        if id < self.present.len() {
1756            self.present[id] = false;
1757        }
1758        Some(id)
1759    }
1760    #[allow(dead_code)]
1761    pub fn is_empty(&self) -> bool {
1762        self.items.is_empty()
1763    }
1764    #[allow(dead_code)]
1765    pub fn len(&self) -> usize {
1766        self.items.len()
1767    }
1768    #[allow(dead_code)]
1769    pub fn contains(&self, id: usize) -> bool {
1770        id < self.present.len() && self.present[id]
1771    }
1772    #[allow(dead_code)]
1773    pub fn drain_all(&mut self) -> Vec<usize> {
1774        let v: Vec<usize> = self.items.drain(..).collect();
1775        for &id in &v {
1776            if id < self.present.len() {
1777                self.present[id] = false;
1778            }
1779        }
1780        v
1781    }
1782}
1783/// Constant folding helper for RLangExt.
1784#[allow(dead_code)]
1785#[derive(Debug, Clone, Default)]
1786pub struct RLangExtConstFolder {
1787    pub(super) folds: usize,
1788    pub(super) failures: usize,
1789    pub(super) enabled: bool,
1790}
1791impl RLangExtConstFolder {
1792    #[allow(dead_code)]
1793    pub fn new() -> Self {
1794        Self {
1795            folds: 0,
1796            failures: 0,
1797            enabled: true,
1798        }
1799    }
1800    #[allow(dead_code)]
1801    pub fn add_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1802        self.folds += 1;
1803        a.checked_add(b)
1804    }
1805    #[allow(dead_code)]
1806    pub fn sub_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1807        self.folds += 1;
1808        a.checked_sub(b)
1809    }
1810    #[allow(dead_code)]
1811    pub fn mul_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1812        self.folds += 1;
1813        a.checked_mul(b)
1814    }
1815    #[allow(dead_code)]
1816    pub fn div_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1817        if b == 0 {
1818            self.failures += 1;
1819            None
1820        } else {
1821            self.folds += 1;
1822            a.checked_div(b)
1823        }
1824    }
1825    #[allow(dead_code)]
1826    pub fn rem_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1827        if b == 0 {
1828            self.failures += 1;
1829            None
1830        } else {
1831            self.folds += 1;
1832            a.checked_rem(b)
1833        }
1834    }
1835    #[allow(dead_code)]
1836    pub fn neg_i64(&mut self, a: i64) -> Option<i64> {
1837        self.folds += 1;
1838        a.checked_neg()
1839    }
1840    #[allow(dead_code)]
1841    pub fn shl_i64(&mut self, a: i64, s: u32) -> Option<i64> {
1842        if s >= 64 {
1843            self.failures += 1;
1844            None
1845        } else {
1846            self.folds += 1;
1847            a.checked_shl(s)
1848        }
1849    }
1850    #[allow(dead_code)]
1851    pub fn shr_i64(&mut self, a: i64, s: u32) -> Option<i64> {
1852        if s >= 64 {
1853            self.failures += 1;
1854            None
1855        } else {
1856            self.folds += 1;
1857            a.checked_shr(s)
1858        }
1859    }
1860    #[allow(dead_code)]
1861    pub fn and_i64(&mut self, a: i64, b: i64) -> i64 {
1862        self.folds += 1;
1863        a & b
1864    }
1865    #[allow(dead_code)]
1866    pub fn or_i64(&mut self, a: i64, b: i64) -> i64 {
1867        self.folds += 1;
1868        a | b
1869    }
1870    #[allow(dead_code)]
1871    pub fn xor_i64(&mut self, a: i64, b: i64) -> i64 {
1872        self.folds += 1;
1873        a ^ b
1874    }
1875    #[allow(dead_code)]
1876    pub fn not_i64(&mut self, a: i64) -> i64 {
1877        self.folds += 1;
1878        !a
1879    }
1880    #[allow(dead_code)]
1881    pub fn fold_count(&self) -> usize {
1882        self.folds
1883    }
1884    #[allow(dead_code)]
1885    pub fn failure_count(&self) -> usize {
1886        self.failures
1887    }
1888    #[allow(dead_code)]
1889    pub fn enable(&mut self) {
1890        self.enabled = true;
1891    }
1892    #[allow(dead_code)]
1893    pub fn disable(&mut self) {
1894        self.enabled = false;
1895    }
1896    #[allow(dead_code)]
1897    pub fn is_enabled(&self) -> bool {
1898        self.enabled
1899    }
1900}
1901#[allow(dead_code)]
1902#[derive(Debug, Clone, PartialEq)]
1903pub enum RLangPassPhase {
1904    Analysis,
1905    Transformation,
1906    Verification,
1907    Cleanup,
1908}
1909impl RLangPassPhase {
1910    #[allow(dead_code)]
1911    pub fn name(&self) -> &str {
1912        match self {
1913            RLangPassPhase::Analysis => "analysis",
1914            RLangPassPhase::Transformation => "transformation",
1915            RLangPassPhase::Verification => "verification",
1916            RLangPassPhase::Cleanup => "cleanup",
1917        }
1918    }
1919    #[allow(dead_code)]
1920    pub fn is_modifying(&self) -> bool {
1921        matches!(
1922            self,
1923            RLangPassPhase::Transformation | RLangPassPhase::Cleanup
1924        )
1925    }
1926}
1927/// Dependency graph for RLangExt.
1928#[allow(dead_code)]
1929#[derive(Debug, Clone)]
1930pub struct RLangExtDepGraph {
1931    pub(super) n: usize,
1932    pub(super) adj: Vec<Vec<usize>>,
1933    pub(super) rev: Vec<Vec<usize>>,
1934    pub(super) edge_count: usize,
1935}
1936impl RLangExtDepGraph {
1937    #[allow(dead_code)]
1938    pub fn new(n: usize) -> Self {
1939        Self {
1940            n,
1941            adj: vec![Vec::new(); n],
1942            rev: vec![Vec::new(); n],
1943            edge_count: 0,
1944        }
1945    }
1946    #[allow(dead_code)]
1947    pub fn add_edge(&mut self, from: usize, to: usize) {
1948        if from < self.n && to < self.n {
1949            if !self.adj[from].contains(&to) {
1950                self.adj[from].push(to);
1951                self.rev[to].push(from);
1952                self.edge_count += 1;
1953            }
1954        }
1955    }
1956    #[allow(dead_code)]
1957    pub fn succs(&self, n: usize) -> &[usize] {
1958        self.adj.get(n).map(|v| v.as_slice()).unwrap_or(&[])
1959    }
1960    #[allow(dead_code)]
1961    pub fn preds(&self, n: usize) -> &[usize] {
1962        self.rev.get(n).map(|v| v.as_slice()).unwrap_or(&[])
1963    }
1964    #[allow(dead_code)]
1965    pub fn topo_sort(&self) -> Option<Vec<usize>> {
1966        let mut deg: Vec<usize> = (0..self.n).map(|i| self.rev[i].len()).collect();
1967        let mut q: std::collections::VecDeque<usize> =
1968            (0..self.n).filter(|&i| deg[i] == 0).collect();
1969        let mut out = Vec::with_capacity(self.n);
1970        while let Some(u) = q.pop_front() {
1971            out.push(u);
1972            for &v in &self.adj[u] {
1973                deg[v] -= 1;
1974                if deg[v] == 0 {
1975                    q.push_back(v);
1976                }
1977            }
1978        }
1979        if out.len() == self.n {
1980            Some(out)
1981        } else {
1982            None
1983        }
1984    }
1985    #[allow(dead_code)]
1986    pub fn has_cycle(&self) -> bool {
1987        self.topo_sort().is_none()
1988    }
1989    #[allow(dead_code)]
1990    pub fn reachable(&self, start: usize) -> Vec<usize> {
1991        let mut vis = vec![false; self.n];
1992        let mut stk = vec![start];
1993        let mut out = Vec::new();
1994        while let Some(u) = stk.pop() {
1995            if u < self.n && !vis[u] {
1996                vis[u] = true;
1997                out.push(u);
1998                for &v in &self.adj[u] {
1999                    if !vis[v] {
2000                        stk.push(v);
2001                    }
2002                }
2003            }
2004        }
2005        out
2006    }
2007    #[allow(dead_code)]
2008    pub fn scc(&self) -> Vec<Vec<usize>> {
2009        let mut visited = vec![false; self.n];
2010        let mut order = Vec::new();
2011        for i in 0..self.n {
2012            if !visited[i] {
2013                let mut stk = vec![(i, 0usize)];
2014                while let Some((u, idx)) = stk.last_mut() {
2015                    if !visited[*u] {
2016                        visited[*u] = true;
2017                    }
2018                    if *idx < self.adj[*u].len() {
2019                        let v = self.adj[*u][*idx];
2020                        *idx += 1;
2021                        if !visited[v] {
2022                            stk.push((v, 0));
2023                        }
2024                    } else {
2025                        order.push(*u);
2026                        stk.pop();
2027                    }
2028                }
2029            }
2030        }
2031        let mut comp = vec![usize::MAX; self.n];
2032        let mut components: Vec<Vec<usize>> = Vec::new();
2033        for &start in order.iter().rev() {
2034            if comp[start] == usize::MAX {
2035                let cid = components.len();
2036                let mut component = Vec::new();
2037                let mut stk = vec![start];
2038                while let Some(u) = stk.pop() {
2039                    if comp[u] == usize::MAX {
2040                        comp[u] = cid;
2041                        component.push(u);
2042                        for &v in &self.rev[u] {
2043                            if comp[v] == usize::MAX {
2044                                stk.push(v);
2045                            }
2046                        }
2047                    }
2048                }
2049                components.push(component);
2050            }
2051        }
2052        components
2053    }
2054    #[allow(dead_code)]
2055    pub fn node_count(&self) -> usize {
2056        self.n
2057    }
2058    #[allow(dead_code)]
2059    pub fn edge_count(&self) -> usize {
2060        self.edge_count
2061    }
2062}
2063#[allow(dead_code)]
2064#[derive(Debug, Clone)]
2065pub struct RLangCacheEntry {
2066    pub key: String,
2067    pub data: Vec<u8>,
2068    pub timestamp: u64,
2069    pub valid: bool,
2070}
2071/// R expression.
2072#[derive(Debug, Clone, PartialEq)]
2073pub enum RExpr {
2074    /// Literal value
2075    Lit(RLiteral),
2076    /// Variable reference: `x`
2077    Var(String),
2078    /// Function call: `f(a, b, named = c)`
2079    Call(Box<RExpr>, Vec<RArg>),
2080    /// Infix operator: `a + b`, `a & b`, `a %in% b`
2081    InfixOp(String, Box<RExpr>, Box<RExpr>),
2082    /// Unary operator: `!x`, `-x`, `+x`
2083    UnaryOp(String, Box<RExpr>),
2084    /// Single-bracket index: `x[i]`
2085    IndexSingle(Box<RExpr>, Vec<RExpr>),
2086    /// Double-bracket index: `x[[i]]`
2087    IndexDouble(Box<RExpr>, Box<RExpr>),
2088    /// Dollar-sign access: `x$field`
2089    DollarAccess(Box<RExpr>, String),
2090    /// At-sign access: `x@slot` (S4)
2091    AtAccess(Box<RExpr>, String),
2092    /// Formula: `y ~ x + z`
2093    Formula(Option<Box<RExpr>>, Box<RExpr>),
2094    /// If-else expression: `if (cond) a else b`
2095    IfElse(Box<RExpr>, Box<RExpr>, Option<Box<RExpr>>),
2096    /// Anonymous function (lambda): `function(x, y) x + y`
2097    Lambda(Vec<RFormal>, Box<RExpr>),
2098    /// Native pipe: `x |> f()`
2099    Pipe(Box<RExpr>, Box<RExpr>),
2100    /// Magrittr pipe: `x %>% f()`
2101    MagrittrPipe(Box<RExpr>, Box<RExpr>),
2102    /// Sequence: `1:10`
2103    Seq(Box<RExpr>, Box<RExpr>),
2104    /// c() vector constructor
2105    CVec(Vec<RExpr>),
2106    /// list() constructor
2107    ListExpr(Vec<RArg>),
2108    /// Block expression: `{ stmt; ...; expr }`
2109    Block(Vec<RStmt>),
2110    /// Namespace access: `pkg::func`
2111    Namespace(String, String),
2112    /// Double-colon access: `pkg:::func` (internal)
2113    NamespaceInternal(String, String),
2114}