Skip to main content

oxilean_codegen/vyper_backend/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use std::collections::HashMap;
6
7use super::functions::VYPER_RUNTIME;
8
9use std::collections::{HashSet, VecDeque};
10
11/// A Vyper flag (bitset enum, Vyper 0.3.8+).
12#[derive(Debug, Clone)]
13pub struct VyperFlagDef {
14    pub name: String,
15    pub variants: Vec<String>,
16    pub doc: Option<String>,
17}
18/// Analysis cache for VyperExt.
19#[allow(dead_code)]
20#[derive(Debug)]
21pub struct VyperExtCache {
22    pub(super) entries: Vec<(u64, Vec<u8>, bool, u32)>,
23    pub(super) cap: usize,
24    pub(super) total_hits: u64,
25    pub(super) total_misses: u64,
26}
27impl VyperExtCache {
28    #[allow(dead_code)]
29    pub fn new(cap: usize) -> Self {
30        Self {
31            entries: Vec::new(),
32            cap,
33            total_hits: 0,
34            total_misses: 0,
35        }
36    }
37    #[allow(dead_code)]
38    pub fn get(&mut self, key: u64) -> Option<&[u8]> {
39        for e in self.entries.iter_mut() {
40            if e.0 == key && e.2 {
41                e.3 += 1;
42                self.total_hits += 1;
43                return Some(&e.1);
44            }
45        }
46        self.total_misses += 1;
47        None
48    }
49    #[allow(dead_code)]
50    pub fn put(&mut self, key: u64, data: Vec<u8>) {
51        if self.entries.len() >= self.cap {
52            self.entries.retain(|e| e.2);
53            if self.entries.len() >= self.cap {
54                self.entries.remove(0);
55            }
56        }
57        self.entries.push((key, data, true, 0));
58    }
59    #[allow(dead_code)]
60    pub fn invalidate(&mut self) {
61        for e in self.entries.iter_mut() {
62            e.2 = false;
63        }
64    }
65    #[allow(dead_code)]
66    pub fn hit_rate(&self) -> f64 {
67        let t = self.total_hits + self.total_misses;
68        if t == 0 {
69            0.0
70        } else {
71            self.total_hits as f64 / t as f64
72        }
73    }
74    #[allow(dead_code)]
75    pub fn live_count(&self) -> usize {
76        self.entries.iter().filter(|e| e.2).count()
77    }
78}
79/// Liveness analysis for VyperExt.
80#[allow(dead_code)]
81#[derive(Debug, Clone, Default)]
82pub struct VyperExtLiveness {
83    pub live_in: Vec<Vec<usize>>,
84    pub live_out: Vec<Vec<usize>>,
85    pub defs: Vec<Vec<usize>>,
86    pub uses: Vec<Vec<usize>>,
87}
88impl VyperExtLiveness {
89    #[allow(dead_code)]
90    pub fn new(n: usize) -> Self {
91        Self {
92            live_in: vec![Vec::new(); n],
93            live_out: vec![Vec::new(); n],
94            defs: vec![Vec::new(); n],
95            uses: vec![Vec::new(); n],
96        }
97    }
98    #[allow(dead_code)]
99    pub fn live_in(&self, b: usize, v: usize) -> bool {
100        self.live_in.get(b).map(|s| s.contains(&v)).unwrap_or(false)
101    }
102    #[allow(dead_code)]
103    pub fn live_out(&self, b: usize, v: usize) -> bool {
104        self.live_out
105            .get(b)
106            .map(|s| s.contains(&v))
107            .unwrap_or(false)
108    }
109    #[allow(dead_code)]
110    pub fn add_def(&mut self, b: usize, v: usize) {
111        if let Some(s) = self.defs.get_mut(b) {
112            if !s.contains(&v) {
113                s.push(v);
114            }
115        }
116    }
117    #[allow(dead_code)]
118    pub fn add_use(&mut self, b: usize, v: usize) {
119        if let Some(s) = self.uses.get_mut(b) {
120            if !s.contains(&v) {
121                s.push(v);
122            }
123        }
124    }
125    #[allow(dead_code)]
126    pub fn var_is_used_in_block(&self, b: usize, v: usize) -> bool {
127        self.uses.get(b).map(|s| s.contains(&v)).unwrap_or(false)
128    }
129    #[allow(dead_code)]
130    pub fn var_is_def_in_block(&self, b: usize, v: usize) -> bool {
131        self.defs.get(b).map(|s| s.contains(&v)).unwrap_or(false)
132    }
133}
134/// A Vyper function definition.
135#[derive(Debug, Clone)]
136pub struct VyperFunction {
137    pub name: String,
138    pub decorators: Vec<VyperDecorator>,
139    pub params: Vec<VyperParam>,
140    pub return_ty: Option<VyperType>,
141    pub body: Vec<VyperStmt>,
142    pub doc: Option<String>,
143}
144impl VyperFunction {
145    pub fn new(name: impl Into<String>) -> Self {
146        Self {
147            name: name.into(),
148            decorators: Vec::new(),
149            params: Vec::new(),
150            return_ty: None,
151            body: Vec::new(),
152            doc: None,
153        }
154    }
155    pub fn external(mut self) -> Self {
156        self.decorators.push(VyperDecorator::External);
157        self
158    }
159    pub fn internal(mut self) -> Self {
160        self.decorators.push(VyperDecorator::Internal);
161        self
162    }
163    pub fn view(mut self) -> Self {
164        self.decorators.push(VyperDecorator::View);
165        self
166    }
167    pub fn pure_fn(mut self) -> Self {
168        self.decorators.push(VyperDecorator::Pure);
169        self
170    }
171    pub fn payable(mut self) -> Self {
172        self.decorators.push(VyperDecorator::Payable);
173        self
174    }
175    pub fn nonreentrant(mut self, key: impl Into<String>) -> Self {
176        self.decorators
177            .push(VyperDecorator::NonReentrant(key.into()));
178        self
179    }
180    /// ABI signature for selector computation.
181    pub fn abi_signature(&self) -> String {
182        let params: Vec<String> = self.params.iter().map(|p| p.ty.abi_canonical()).collect();
183        format!("{}({})", self.name, params.join(","))
184    }
185    /// Simple 4-byte selector (djb2-based placeholder).
186    pub fn selector(&self) -> [u8; 4] {
187        let sig = self.abi_signature();
188        let mut h: u32 = 5381;
189        for b in sig.bytes() {
190            h = h.wrapping_shl(5).wrapping_add(h).wrapping_add(b as u32);
191        }
192        h.to_be_bytes()
193    }
194    /// Returns true if this function is `@external`.
195    pub fn is_external(&self) -> bool {
196        self.decorators.contains(&VyperDecorator::External)
197    }
198    /// Returns true if this function is `@view` or `@pure`.
199    pub fn is_read_only(&self) -> bool {
200        self.decorators.contains(&VyperDecorator::View)
201            || self.decorators.contains(&VyperDecorator::Pure)
202    }
203}
204/// Dependency graph for VyperExt.
205#[allow(dead_code)]
206#[derive(Debug, Clone)]
207pub struct VyperExtDepGraph {
208    pub(super) n: usize,
209    pub(super) adj: Vec<Vec<usize>>,
210    pub(super) rev: Vec<Vec<usize>>,
211    pub(super) edge_count: usize,
212}
213impl VyperExtDepGraph {
214    #[allow(dead_code)]
215    pub fn new(n: usize) -> Self {
216        Self {
217            n,
218            adj: vec![Vec::new(); n],
219            rev: vec![Vec::new(); n],
220            edge_count: 0,
221        }
222    }
223    #[allow(dead_code)]
224    pub fn add_edge(&mut self, from: usize, to: usize) {
225        if from < self.n && to < self.n {
226            if !self.adj[from].contains(&to) {
227                self.adj[from].push(to);
228                self.rev[to].push(from);
229                self.edge_count += 1;
230            }
231        }
232    }
233    #[allow(dead_code)]
234    pub fn succs(&self, n: usize) -> &[usize] {
235        self.adj.get(n).map(|v| v.as_slice()).unwrap_or(&[])
236    }
237    #[allow(dead_code)]
238    pub fn preds(&self, n: usize) -> &[usize] {
239        self.rev.get(n).map(|v| v.as_slice()).unwrap_or(&[])
240    }
241    #[allow(dead_code)]
242    pub fn topo_sort(&self) -> Option<Vec<usize>> {
243        let mut deg: Vec<usize> = (0..self.n).map(|i| self.rev[i].len()).collect();
244        let mut q: std::collections::VecDeque<usize> =
245            (0..self.n).filter(|&i| deg[i] == 0).collect();
246        let mut out = Vec::with_capacity(self.n);
247        while let Some(u) = q.pop_front() {
248            out.push(u);
249            for &v in &self.adj[u] {
250                deg[v] -= 1;
251                if deg[v] == 0 {
252                    q.push_back(v);
253                }
254            }
255        }
256        if out.len() == self.n {
257            Some(out)
258        } else {
259            None
260        }
261    }
262    #[allow(dead_code)]
263    pub fn has_cycle(&self) -> bool {
264        self.topo_sort().is_none()
265    }
266    #[allow(dead_code)]
267    pub fn reachable(&self, start: usize) -> Vec<usize> {
268        let mut vis = vec![false; self.n];
269        let mut stk = vec![start];
270        let mut out = Vec::new();
271        while let Some(u) = stk.pop() {
272            if u < self.n && !vis[u] {
273                vis[u] = true;
274                out.push(u);
275                for &v in &self.adj[u] {
276                    if !vis[v] {
277                        stk.push(v);
278                    }
279                }
280            }
281        }
282        out
283    }
284    #[allow(dead_code)]
285    pub fn scc(&self) -> Vec<Vec<usize>> {
286        let mut visited = vec![false; self.n];
287        let mut order = Vec::new();
288        for i in 0..self.n {
289            if !visited[i] {
290                let mut stk = vec![(i, 0usize)];
291                while let Some((u, idx)) = stk.last_mut() {
292                    if !visited[*u] {
293                        visited[*u] = true;
294                    }
295                    if *idx < self.adj[*u].len() {
296                        let v = self.adj[*u][*idx];
297                        *idx += 1;
298                        if !visited[v] {
299                            stk.push((v, 0));
300                        }
301                    } else {
302                        order.push(*u);
303                        stk.pop();
304                    }
305                }
306            }
307        }
308        let mut comp = vec![usize::MAX; self.n];
309        let mut components: Vec<Vec<usize>> = Vec::new();
310        for &start in order.iter().rev() {
311            if comp[start] == usize::MAX {
312                let cid = components.len();
313                let mut component = Vec::new();
314                let mut stk = vec![start];
315                while let Some(u) = stk.pop() {
316                    if comp[u] == usize::MAX {
317                        comp[u] = cid;
318                        component.push(u);
319                        for &v in &self.rev[u] {
320                            if comp[v] == usize::MAX {
321                                stk.push(v);
322                            }
323                        }
324                    }
325                }
326                components.push(component);
327            }
328        }
329        components
330    }
331    #[allow(dead_code)]
332    pub fn node_count(&self) -> usize {
333        self.n
334    }
335    #[allow(dead_code)]
336    pub fn edge_count(&self) -> usize {
337        self.edge_count
338    }
339}
340/// Pass execution phase for VyperExt.
341#[allow(dead_code)]
342#[derive(Debug, Clone, PartialEq, Eq, Hash)]
343pub enum VyperExtPassPhase {
344    Early,
345    Middle,
346    Late,
347    Finalize,
348}
349impl VyperExtPassPhase {
350    #[allow(dead_code)]
351    pub fn is_early(&self) -> bool {
352        matches!(self, Self::Early)
353    }
354    #[allow(dead_code)]
355    pub fn is_middle(&self) -> bool {
356        matches!(self, Self::Middle)
357    }
358    #[allow(dead_code)]
359    pub fn is_late(&self) -> bool {
360        matches!(self, Self::Late)
361    }
362    #[allow(dead_code)]
363    pub fn is_finalize(&self) -> bool {
364        matches!(self, Self::Finalize)
365    }
366    #[allow(dead_code)]
367    pub fn order(&self) -> u32 {
368        match self {
369            Self::Early => 0,
370            Self::Middle => 1,
371            Self::Late => 2,
372            Self::Finalize => 3,
373        }
374    }
375    #[allow(dead_code)]
376    pub fn from_order(n: u32) -> Option<Self> {
377        match n {
378            0 => Some(Self::Early),
379            1 => Some(Self::Middle),
380            2 => Some(Self::Late),
381            3 => Some(Self::Finalize),
382            _ => None,
383        }
384    }
385}
386/// A Vyper state variable (storage variable).
387#[derive(Debug, Clone)]
388pub struct VyperStorageVar {
389    pub name: String,
390    pub ty: VyperType,
391    pub is_public: bool,
392    pub doc: Option<String>,
393}
394/// The main Vyper code generation backend.
395#[derive(Debug, Default)]
396pub struct VyperBackend {
397    /// Emitted contract (only one per Vyper file).
398    pub contract: Option<VyperContract>,
399    /// Compilation context.
400    pub ctx: VyperCompilationCtx,
401    /// Type alias table.
402    pub type_aliases: HashMap<String, VyperType>,
403    /// Source buffer accumulated during emission.
404    pub source: String,
405}
406impl VyperBackend {
407    pub fn new() -> Self {
408        Self::default()
409    }
410    pub fn with_runtime(mut self) -> Self {
411        self.ctx.include_runtime = true;
412        self
413    }
414    pub fn with_version(mut self, version: impl Into<String>) -> Self {
415        self.ctx.version = version.into();
416        self
417    }
418    pub fn set_contract(&mut self, contract: VyperContract) {
419        self.contract = Some(contract);
420    }
421    /// Compile a single LCNF-style declaration into a Vyper storage variable.
422    pub fn compile_decl(&self, name: &str, ty: VyperType) -> VyperStorageVar {
423        VyperStorageVar {
424            name: name.into(),
425            ty,
426            is_public: false,
427            doc: None,
428        }
429    }
430    /// Emit the full Vyper source for the registered contract.
431    pub fn emit_contract(&mut self) -> String {
432        let mut out = String::new();
433        out.push_str(&format!("# @version {}\n", self.ctx.version));
434        if self.ctx.abi_v2 {
435            out.push_str("# pragma abicoder v2\n");
436        }
437        for p in &self.ctx.extra_pragmas {
438            out.push_str(&format!("# pragma {}\n", p));
439        }
440        out.push('\n');
441        if self.ctx.include_runtime {
442            out.push_str(VYPER_RUNTIME);
443            out.push('\n');
444        }
445        if let Some(contract) = &self.contract.clone() {
446            if let Some(doc) = &contract.doc {
447                out.push_str(&format!("\"\"\"\n@title {}\n\"\"\"\n\n", doc));
448            }
449            for iface in &contract.interfaces {
450                out.push_str(&Self::emit_interface(iface));
451                out.push('\n');
452            }
453            for s in &contract.structs {
454                out.push_str(&Self::emit_struct(s));
455                out.push('\n');
456            }
457            for fl in &contract.flags {
458                out.push_str(&Self::emit_flag(fl));
459                out.push('\n');
460            }
461            for ev in &contract.events {
462                out.push_str(&Self::emit_event(ev));
463                out.push('\n');
464            }
465            for c in &contract.constants {
466                out.push_str(&Self::emit_constant(c));
467            }
468            if !contract.constants.is_empty() {
469                out.push('\n');
470            }
471            for sv in &contract.storage {
472                out.push_str(&Self::emit_storage_var(sv));
473            }
474            if !contract.storage.is_empty() {
475                out.push('\n');
476            }
477            if let Some(ctor) = &contract.constructor.clone() {
478                out.push_str(&Self::emit_function(ctor, true));
479                out.push('\n');
480            }
481            if let Some(dflt) = &contract.default_fn.clone() {
482                out.push_str(&Self::emit_function(dflt, false));
483                out.push('\n');
484            }
485            for func in &contract.functions.clone() {
486                out.push_str(&Self::emit_function(func, false));
487                out.push('\n');
488            }
489        }
490        self.source = out.clone();
491        out
492    }
493    pub(super) fn emit_interface(iface: &VyperInterface) -> String {
494        let mut out = String::new();
495        if let Some(doc) = &iface.doc {
496            out.push_str(&format!("# {}\n", doc));
497        }
498        out.push_str(&format!("interface {}:\n", iface.name));
499        if iface.functions.is_empty() {
500            out.push_str("    pass\n");
501        } else {
502            for func in &iface.functions {
503                for dec in &func.decorators {
504                    out.push_str(&format!("    {}\n", dec));
505                }
506                let params: Vec<String> = func.params.iter().map(|p| p.to_string()).collect();
507                let ret = func
508                    .return_ty
509                    .as_ref()
510                    .map(|t| format!(" -> {}", t))
511                    .unwrap_or_default();
512                out.push_str(&format!(
513                    "    def {}({}){}:\n",
514                    func.name,
515                    params.join(", "),
516                    ret
517                ));
518                out.push_str("        ...\n");
519            }
520        }
521        out
522    }
523    pub(super) fn emit_struct(s: &VyperStruct) -> String {
524        let mut out = String::new();
525        if let Some(doc) = &s.doc {
526            out.push_str(&format!("# {}\n", doc));
527        }
528        out.push_str(&format!("struct {}:\n", s.name));
529        if s.fields.is_empty() {
530            out.push_str("    pass\n");
531        } else {
532            for (name, ty) in &s.fields {
533                out.push_str(&format!("    {}: {}\n", name, ty));
534            }
535        }
536        out
537    }
538    pub(super) fn emit_flag(fl: &VyperFlagDef) -> String {
539        let mut out = String::new();
540        if let Some(doc) = &fl.doc {
541            out.push_str(&format!("# {}\n", doc));
542        }
543        out.push_str(&format!("flag {}:\n", fl.name));
544        for v in &fl.variants {
545            out.push_str(&format!("    {}\n", v));
546        }
547        out
548    }
549    pub(super) fn emit_event(ev: &VyperEvent) -> String {
550        let mut out = String::new();
551        if let Some(doc) = &ev.doc {
552            out.push_str(&format!("# {}\n", doc));
553        }
554        out.push_str(&format!("event {}:\n", ev.name));
555        if ev.fields.is_empty() {
556            out.push_str("    pass\n");
557        } else {
558            for (name, ty, indexed) in &ev.fields {
559                if *indexed {
560                    out.push_str(&format!("    {}: indexed({})\n", name, ty));
561                } else {
562                    out.push_str(&format!("    {}: {}\n", name, ty));
563                }
564            }
565        }
566        out
567    }
568    pub(super) fn emit_constant(c: &VyperConstant) -> String {
569        if let Some(doc) = &c.doc {
570            format!("# {}\n{}: constant({}) = {}\n", doc, c.name, c.ty, c.value)
571        } else {
572            format!("{}: constant({}) = {}\n", c.name, c.ty, c.value)
573        }
574    }
575    pub(super) fn emit_storage_var(sv: &VyperStorageVar) -> String {
576        let pub_str = if sv.is_public { "(public)" } else { "" };
577        if let Some(doc) = &sv.doc {
578            format!("# {}\n{}: {}{}\n", doc, sv.name, sv.ty, pub_str)
579        } else {
580            format!("{}: {}{}\n", sv.name, sv.ty, pub_str)
581        }
582    }
583    pub(super) fn emit_function(func: &VyperFunction, is_init: bool) -> String {
584        let mut out = String::new();
585        if let Some(doc) = &func.doc {
586            out.push_str(&format!("# @notice {}\n", doc));
587        }
588        for dec in &func.decorators {
589            out.push_str(&format!("{}\n", dec));
590        }
591        let params: Vec<String> = func.params.iter().map(|p| p.to_string()).collect();
592        let fn_name = if is_init { "__init__" } else { &func.name };
593        let ret = func
594            .return_ty
595            .as_ref()
596            .map(|t| format!(" -> {}", t))
597            .unwrap_or_default();
598        out.push_str(&format!("def {}({}){}:\n", fn_name, params.join(", "), ret));
599        if func.body.is_empty() {
600            out.push_str("    pass\n");
601        } else {
602            for stmt in &func.body {
603                out.push_str(&Self::emit_stmt(stmt, 1));
604            }
605        }
606        out
607    }
608    pub(super) fn indent(level: usize) -> String {
609        "    ".repeat(level)
610    }
611    pub(super) fn emit_stmt(stmt: &VyperStmt, indent: usize) -> String {
612        let ind = Self::indent(indent);
613        match stmt {
614            VyperStmt::VarDecl(name, ty, init) => {
615                if let Some(expr) = init {
616                    format!("{}{}: {} = {}\n", ind, name, ty, expr)
617                } else {
618                    format!("{}{}: {}\n", ind, name, ty)
619                }
620            }
621            VyperStmt::Assign(lhs, rhs) => format!("{}{} = {}\n", ind, lhs, rhs),
622            VyperStmt::AugAssign(op, lhs, rhs) => {
623                format!("{}{} {}= {}\n", ind, lhs, op, rhs)
624            }
625            VyperStmt::ExprStmt(expr) => format!("{}{}\n", ind, expr),
626            VyperStmt::Return(None) => format!("{}return\n", ind),
627            VyperStmt::Return(Some(expr)) => format!("{}return {}\n", ind, expr),
628            VyperStmt::If(cond, then_stmts, else_stmts) => {
629                let mut out = format!("{}if {}:\n", ind, cond);
630                if then_stmts.is_empty() {
631                    out.push_str(&format!("{}    pass\n", ind));
632                } else {
633                    for s in then_stmts {
634                        out.push_str(&Self::emit_stmt(s, indent + 1));
635                    }
636                }
637                if !else_stmts.is_empty() {
638                    out.push_str(&format!("{}else:\n", ind));
639                    for s in else_stmts {
640                        out.push_str(&Self::emit_stmt(s, indent + 1));
641                    }
642                }
643                out
644            }
645            VyperStmt::ForRange(var, ty, bound, body) => {
646                let mut out = format!("{}for {}: {} in range({}):\n", ind, var, ty, bound);
647                if body.is_empty() {
648                    out.push_str(&format!("{}    pass\n", ind));
649                } else {
650                    for s in body {
651                        out.push_str(&Self::emit_stmt(s, indent + 1));
652                    }
653                }
654                out
655            }
656            VyperStmt::ForIn(var, ty, array, body) => {
657                let mut out = format!("{}for {}: {} in {}:\n", ind, var, ty, array);
658                if body.is_empty() {
659                    out.push_str(&format!("{}    pass\n", ind));
660                } else {
661                    for s in body {
662                        out.push_str(&Self::emit_stmt(s, indent + 1));
663                    }
664                }
665                out
666            }
667            VyperStmt::Log(name, args) => {
668                let strs: Vec<String> = args.iter().map(|a| a.to_string()).collect();
669                format!("{}log {}({})\n", ind, name, strs.join(", "))
670            }
671            VyperStmt::Assert(cond, msg) => {
672                if let Some(m) = msg {
673                    format!("{}assert {}, \"{}\"\n", ind, cond, m)
674                } else {
675                    format!("{}assert {}\n", ind, cond)
676                }
677            }
678            VyperStmt::Raise(msg) => format!("{}raise \"{}\"\n", ind, msg),
679            VyperStmt::Pass => format!("{}pass\n", ind),
680            VyperStmt::Break => format!("{}break\n", ind),
681            VyperStmt::Continue => format!("{}continue\n", ind),
682            VyperStmt::Send(addr, amount) => {
683                format!("{}send({}, {})\n", ind, addr, amount)
684            }
685            VyperStmt::SelfDestruct(to) => format!("{}selfdestruct({})\n", ind, to),
686            VyperStmt::Comment(text) => format!("{}# {}\n", ind, text),
687        }
688    }
689}
690#[allow(dead_code)]
691#[derive(Debug, Clone)]
692pub struct VypPassConfig {
693    pub phase: VypPassPhase,
694    pub enabled: bool,
695    pub max_iterations: u32,
696    pub debug_output: bool,
697    pub pass_name: String,
698}
699impl VypPassConfig {
700    #[allow(dead_code)]
701    pub fn new(name: impl Into<String>, phase: VypPassPhase) -> Self {
702        VypPassConfig {
703            phase,
704            enabled: true,
705            max_iterations: 10,
706            debug_output: false,
707            pass_name: name.into(),
708        }
709    }
710    #[allow(dead_code)]
711    pub fn disabled(mut self) -> Self {
712        self.enabled = false;
713        self
714    }
715    #[allow(dead_code)]
716    pub fn with_debug(mut self) -> Self {
717        self.debug_output = true;
718        self
719    }
720    #[allow(dead_code)]
721    pub fn max_iter(mut self, n: u32) -> Self {
722        self.max_iterations = n;
723        self
724    }
725}
726#[allow(dead_code)]
727#[derive(Debug, Clone)]
728pub struct VypWorklist {
729    pub(super) items: std::collections::VecDeque<u32>,
730    pub(super) in_worklist: std::collections::HashSet<u32>,
731}
732impl VypWorklist {
733    #[allow(dead_code)]
734    pub fn new() -> Self {
735        VypWorklist {
736            items: std::collections::VecDeque::new(),
737            in_worklist: std::collections::HashSet::new(),
738        }
739    }
740    #[allow(dead_code)]
741    pub fn push(&mut self, item: u32) -> bool {
742        if self.in_worklist.insert(item) {
743            self.items.push_back(item);
744            true
745        } else {
746            false
747        }
748    }
749    #[allow(dead_code)]
750    pub fn pop(&mut self) -> Option<u32> {
751        let item = self.items.pop_front()?;
752        self.in_worklist.remove(&item);
753        Some(item)
754    }
755    #[allow(dead_code)]
756    pub fn is_empty(&self) -> bool {
757        self.items.is_empty()
758    }
759    #[allow(dead_code)]
760    pub fn len(&self) -> usize {
761        self.items.len()
762    }
763    #[allow(dead_code)]
764    pub fn contains(&self, item: u32) -> bool {
765        self.in_worklist.contains(&item)
766    }
767}
768/// A function parameter.
769#[derive(Debug, Clone)]
770pub struct VyperParam {
771    pub name: String,
772    pub ty: VyperType,
773    pub default: Option<VyperExpr>,
774}
775impl VyperParam {
776    pub fn new(name: impl Into<String>, ty: VyperType) -> Self {
777        Self {
778            name: name.into(),
779            ty,
780            default: None,
781        }
782    }
783    pub fn with_default(mut self, default: VyperExpr) -> Self {
784        self.default = Some(default);
785        self
786    }
787}
788#[allow(dead_code)]
789#[derive(Debug, Clone)]
790pub struct VypLivenessInfo {
791    pub live_in: Vec<std::collections::HashSet<u32>>,
792    pub live_out: Vec<std::collections::HashSet<u32>>,
793    pub defs: Vec<std::collections::HashSet<u32>>,
794    pub uses: Vec<std::collections::HashSet<u32>>,
795}
796impl VypLivenessInfo {
797    #[allow(dead_code)]
798    pub fn new(block_count: usize) -> Self {
799        VypLivenessInfo {
800            live_in: vec![std::collections::HashSet::new(); block_count],
801            live_out: vec![std::collections::HashSet::new(); block_count],
802            defs: vec![std::collections::HashSet::new(); block_count],
803            uses: vec![std::collections::HashSet::new(); block_count],
804        }
805    }
806    #[allow(dead_code)]
807    pub fn add_def(&mut self, block: usize, var: u32) {
808        if block < self.defs.len() {
809            self.defs[block].insert(var);
810        }
811    }
812    #[allow(dead_code)]
813    pub fn add_use(&mut self, block: usize, var: u32) {
814        if block < self.uses.len() {
815            self.uses[block].insert(var);
816        }
817    }
818    #[allow(dead_code)]
819    pub fn is_live_in(&self, block: usize, var: u32) -> bool {
820        self.live_in
821            .get(block)
822            .map(|s| s.contains(&var))
823            .unwrap_or(false)
824    }
825    #[allow(dead_code)]
826    pub fn is_live_out(&self, block: usize, var: u32) -> bool {
827        self.live_out
828            .get(block)
829            .map(|s| s.contains(&var))
830            .unwrap_or(false)
831    }
832}
833#[allow(dead_code)]
834#[derive(Debug, Clone, PartialEq)]
835pub enum VypPassPhase {
836    Analysis,
837    Transformation,
838    Verification,
839    Cleanup,
840}
841impl VypPassPhase {
842    #[allow(dead_code)]
843    pub fn name(&self) -> &str {
844        match self {
845            VypPassPhase::Analysis => "analysis",
846            VypPassPhase::Transformation => "transformation",
847            VypPassPhase::Verification => "verification",
848            VypPassPhase::Cleanup => "cleanup",
849        }
850    }
851    #[allow(dead_code)]
852    pub fn is_modifying(&self) -> bool {
853        matches!(self, VypPassPhase::Transformation | VypPassPhase::Cleanup)
854    }
855}
856/// Statistics for VyperExt passes.
857#[allow(dead_code)]
858#[derive(Debug, Clone, Default)]
859pub struct VyperExtPassStats {
860    pub iterations: usize,
861    pub changed: bool,
862    pub nodes_visited: usize,
863    pub nodes_modified: usize,
864    pub time_ms: u64,
865    pub memory_bytes: usize,
866    pub errors: usize,
867}
868impl VyperExtPassStats {
869    #[allow(dead_code)]
870    pub fn new() -> Self {
871        Self::default()
872    }
873    #[allow(dead_code)]
874    pub fn visit(&mut self) {
875        self.nodes_visited += 1;
876    }
877    #[allow(dead_code)]
878    pub fn modify(&mut self) {
879        self.nodes_modified += 1;
880        self.changed = true;
881    }
882    #[allow(dead_code)]
883    pub fn iterate(&mut self) {
884        self.iterations += 1;
885    }
886    #[allow(dead_code)]
887    pub fn error(&mut self) {
888        self.errors += 1;
889    }
890    #[allow(dead_code)]
891    pub fn efficiency(&self) -> f64 {
892        if self.nodes_visited == 0 {
893            0.0
894        } else {
895            self.nodes_modified as f64 / self.nodes_visited as f64
896        }
897    }
898    #[allow(dead_code)]
899    pub fn merge(&mut self, o: &VyperExtPassStats) {
900        self.iterations += o.iterations;
901        self.changed |= o.changed;
902        self.nodes_visited += o.nodes_visited;
903        self.nodes_modified += o.nodes_modified;
904        self.time_ms += o.time_ms;
905        self.memory_bytes = self.memory_bytes.max(o.memory_bytes);
906        self.errors += o.errors;
907    }
908}
909/// Worklist for VyperExt.
910#[allow(dead_code)]
911#[derive(Debug, Clone)]
912pub struct VyperExtWorklist {
913    pub(super) items: std::collections::VecDeque<usize>,
914    pub(super) present: Vec<bool>,
915}
916impl VyperExtWorklist {
917    #[allow(dead_code)]
918    pub fn new(capacity: usize) -> Self {
919        Self {
920            items: std::collections::VecDeque::new(),
921            present: vec![false; capacity],
922        }
923    }
924    #[allow(dead_code)]
925    pub fn push(&mut self, id: usize) {
926        if id < self.present.len() && !self.present[id] {
927            self.present[id] = true;
928            self.items.push_back(id);
929        }
930    }
931    #[allow(dead_code)]
932    pub fn push_front(&mut self, id: usize) {
933        if id < self.present.len() && !self.present[id] {
934            self.present[id] = true;
935            self.items.push_front(id);
936        }
937    }
938    #[allow(dead_code)]
939    pub fn pop(&mut self) -> Option<usize> {
940        let id = self.items.pop_front()?;
941        if id < self.present.len() {
942            self.present[id] = false;
943        }
944        Some(id)
945    }
946    #[allow(dead_code)]
947    pub fn is_empty(&self) -> bool {
948        self.items.is_empty()
949    }
950    #[allow(dead_code)]
951    pub fn len(&self) -> usize {
952        self.items.len()
953    }
954    #[allow(dead_code)]
955    pub fn contains(&self, id: usize) -> bool {
956        id < self.present.len() && self.present[id]
957    }
958    #[allow(dead_code)]
959    pub fn drain_all(&mut self) -> Vec<usize> {
960        let v: Vec<usize> = self.items.drain(..).collect();
961        for &id in &v {
962            if id < self.present.len() {
963                self.present[id] = false;
964            }
965        }
966        v
967    }
968}
969/// Pass registry for VyperExt.
970#[allow(dead_code)]
971#[derive(Debug, Default)]
972pub struct VyperExtPassRegistry {
973    pub(super) configs: Vec<VyperExtPassConfig>,
974    pub(super) stats: Vec<VyperExtPassStats>,
975}
976impl VyperExtPassRegistry {
977    #[allow(dead_code)]
978    pub fn new() -> Self {
979        Self::default()
980    }
981    #[allow(dead_code)]
982    pub fn register(&mut self, c: VyperExtPassConfig) {
983        self.stats.push(VyperExtPassStats::new());
984        self.configs.push(c);
985    }
986    #[allow(dead_code)]
987    pub fn len(&self) -> usize {
988        self.configs.len()
989    }
990    #[allow(dead_code)]
991    pub fn is_empty(&self) -> bool {
992        self.configs.is_empty()
993    }
994    #[allow(dead_code)]
995    pub fn get(&self, i: usize) -> Option<&VyperExtPassConfig> {
996        self.configs.get(i)
997    }
998    #[allow(dead_code)]
999    pub fn get_stats(&self, i: usize) -> Option<&VyperExtPassStats> {
1000        self.stats.get(i)
1001    }
1002    #[allow(dead_code)]
1003    pub fn enabled_passes(&self) -> Vec<&VyperExtPassConfig> {
1004        self.configs.iter().filter(|c| c.enabled).collect()
1005    }
1006    #[allow(dead_code)]
1007    pub fn passes_in_phase(&self, ph: &VyperExtPassPhase) -> Vec<&VyperExtPassConfig> {
1008        self.configs
1009            .iter()
1010            .filter(|c| c.enabled && &c.phase == ph)
1011            .collect()
1012    }
1013    #[allow(dead_code)]
1014    pub fn total_nodes_visited(&self) -> usize {
1015        self.stats.iter().map(|s| s.nodes_visited).sum()
1016    }
1017    #[allow(dead_code)]
1018    pub fn any_changed(&self) -> bool {
1019        self.stats.iter().any(|s| s.changed)
1020    }
1021}
1022/// Vyper statement AST node.
1023#[derive(Debug, Clone)]
1024pub enum VyperStmt {
1025    /// `name: T = expr`
1026    VarDecl(String, VyperType, Option<VyperExpr>),
1027    /// `lhs = rhs`
1028    Assign(VyperExpr, VyperExpr),
1029    /// `lhs += rhs` / `lhs -= rhs` / etc.
1030    AugAssign(String, VyperExpr, VyperExpr),
1031    /// `expr` (function call as statement)
1032    ExprStmt(VyperExpr),
1033    /// `return expr`
1034    Return(Option<VyperExpr>),
1035    /// `if cond:\n  body\nelse:\n  else_`
1036    If(VyperExpr, Vec<VyperStmt>, Vec<VyperStmt>),
1037    /// `for var: T in range(n):\n  body`
1038    ForRange(String, VyperType, VyperExpr, Vec<VyperStmt>),
1039    /// `for var: T in array:\n  body`
1040    ForIn(String, VyperType, VyperExpr, Vec<VyperStmt>),
1041    /// `log EventName(args...)`
1042    Log(String, Vec<VyperExpr>),
1043    /// `assert cond, msg`
1044    Assert(VyperExpr, Option<String>),
1045    /// `raise "msg"`
1046    Raise(String),
1047    /// `pass`
1048    Pass,
1049    /// `break`
1050    Break,
1051    /// `continue`
1052    Continue,
1053    /// `send(addr, amount)`
1054    Send(VyperExpr, VyperExpr),
1055    /// `selfdestruct(to)`
1056    SelfDestruct(VyperExpr),
1057    /// Multi-line comment block (emitted as `# comment`)
1058    Comment(String),
1059}
1060/// A Vyper module-level constant.
1061#[derive(Debug, Clone)]
1062pub struct VyperConstant {
1063    pub name: String,
1064    pub ty: VyperType,
1065    pub value: VyperExpr,
1066    pub doc: Option<String>,
1067}
1068#[allow(dead_code)]
1069#[derive(Debug, Clone)]
1070pub struct VypDominatorTree {
1071    pub idom: Vec<Option<u32>>,
1072    pub dom_children: Vec<Vec<u32>>,
1073    pub dom_depth: Vec<u32>,
1074}
1075impl VypDominatorTree {
1076    #[allow(dead_code)]
1077    pub fn new(size: usize) -> Self {
1078        VypDominatorTree {
1079            idom: vec![None; size],
1080            dom_children: vec![Vec::new(); size],
1081            dom_depth: vec![0; size],
1082        }
1083    }
1084    #[allow(dead_code)]
1085    pub fn set_idom(&mut self, node: usize, idom: u32) {
1086        self.idom[node] = Some(idom);
1087    }
1088    #[allow(dead_code)]
1089    pub fn dominates(&self, a: usize, b: usize) -> bool {
1090        if a == b {
1091            return true;
1092        }
1093        let mut cur = b;
1094        loop {
1095            match self.idom[cur] {
1096                Some(parent) if parent as usize == a => return true,
1097                Some(parent) if parent as usize == cur => return false,
1098                Some(parent) => cur = parent as usize,
1099                None => return false,
1100            }
1101        }
1102    }
1103    #[allow(dead_code)]
1104    pub fn depth(&self, node: usize) -> u32 {
1105        self.dom_depth.get(node).copied().unwrap_or(0)
1106    }
1107}
1108/// A Vyper struct definition.
1109#[derive(Debug, Clone)]
1110pub struct VyperStruct {
1111    pub name: String,
1112    pub fields: Vec<(String, VyperType)>,
1113    pub doc: Option<String>,
1114}
1115#[allow(dead_code)]
1116#[derive(Debug, Clone)]
1117pub struct VypAnalysisCache {
1118    pub(super) entries: std::collections::HashMap<String, VypCacheEntry>,
1119    pub(super) max_size: usize,
1120    pub(super) hits: u64,
1121    pub(super) misses: u64,
1122}
1123impl VypAnalysisCache {
1124    #[allow(dead_code)]
1125    pub fn new(max_size: usize) -> Self {
1126        VypAnalysisCache {
1127            entries: std::collections::HashMap::new(),
1128            max_size,
1129            hits: 0,
1130            misses: 0,
1131        }
1132    }
1133    #[allow(dead_code)]
1134    pub fn get(&mut self, key: &str) -> Option<&VypCacheEntry> {
1135        if self.entries.contains_key(key) {
1136            self.hits += 1;
1137            self.entries.get(key)
1138        } else {
1139            self.misses += 1;
1140            None
1141        }
1142    }
1143    #[allow(dead_code)]
1144    pub fn insert(&mut self, key: String, data: Vec<u8>) {
1145        if self.entries.len() >= self.max_size {
1146            if let Some(oldest) = self.entries.keys().next().cloned() {
1147                self.entries.remove(&oldest);
1148            }
1149        }
1150        self.entries.insert(
1151            key.clone(),
1152            VypCacheEntry {
1153                key,
1154                data,
1155                timestamp: 0,
1156                valid: true,
1157            },
1158        );
1159    }
1160    #[allow(dead_code)]
1161    pub fn invalidate(&mut self, key: &str) {
1162        if let Some(entry) = self.entries.get_mut(key) {
1163            entry.valid = false;
1164        }
1165    }
1166    #[allow(dead_code)]
1167    pub fn clear(&mut self) {
1168        self.entries.clear();
1169    }
1170    #[allow(dead_code)]
1171    pub fn hit_rate(&self) -> f64 {
1172        let total = self.hits + self.misses;
1173        if total == 0 {
1174            return 0.0;
1175        }
1176        self.hits as f64 / total as f64
1177    }
1178    #[allow(dead_code)]
1179    pub fn size(&self) -> usize {
1180        self.entries.len()
1181    }
1182}
1183/// Dominator tree for VyperExt.
1184#[allow(dead_code)]
1185#[derive(Debug, Clone)]
1186pub struct VyperExtDomTree {
1187    pub(super) idom: Vec<Option<usize>>,
1188    pub(super) children: Vec<Vec<usize>>,
1189    pub(super) depth: Vec<usize>,
1190}
1191impl VyperExtDomTree {
1192    #[allow(dead_code)]
1193    pub fn new(n: usize) -> Self {
1194        Self {
1195            idom: vec![None; n],
1196            children: vec![Vec::new(); n],
1197            depth: vec![0; n],
1198        }
1199    }
1200    #[allow(dead_code)]
1201    pub fn set_idom(&mut self, node: usize, dom: usize) {
1202        if node < self.idom.len() {
1203            self.idom[node] = Some(dom);
1204            if dom < self.children.len() {
1205                self.children[dom].push(node);
1206            }
1207            self.depth[node] = if dom < self.depth.len() {
1208                self.depth[dom] + 1
1209            } else {
1210                1
1211            };
1212        }
1213    }
1214    #[allow(dead_code)]
1215    pub fn dominates(&self, a: usize, mut b: usize) -> bool {
1216        if a == b {
1217            return true;
1218        }
1219        let n = self.idom.len();
1220        for _ in 0..n {
1221            match self.idom.get(b).copied().flatten() {
1222                None => return false,
1223                Some(p) if p == a => return true,
1224                Some(p) if p == b => return false,
1225                Some(p) => b = p,
1226            }
1227        }
1228        false
1229    }
1230    #[allow(dead_code)]
1231    pub fn children_of(&self, n: usize) -> &[usize] {
1232        self.children.get(n).map(|v| v.as_slice()).unwrap_or(&[])
1233    }
1234    #[allow(dead_code)]
1235    pub fn depth_of(&self, n: usize) -> usize {
1236        self.depth.get(n).copied().unwrap_or(0)
1237    }
1238    #[allow(dead_code)]
1239    pub fn lca(&self, mut a: usize, mut b: usize) -> usize {
1240        let n = self.idom.len();
1241        for _ in 0..(2 * n) {
1242            if a == b {
1243                return a;
1244            }
1245            if self.depth_of(a) > self.depth_of(b) {
1246                a = self.idom.get(a).and_then(|x| *x).unwrap_or(a);
1247            } else {
1248                b = self.idom.get(b).and_then(|x| *x).unwrap_or(b);
1249            }
1250        }
1251        0
1252    }
1253}
1254/// Vyper type representation.
1255#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1256pub enum VyperType {
1257    /// `uint256`
1258    Uint256,
1259    /// `uint128`
1260    Uint128,
1261    /// `uint64`
1262    Uint64,
1263    /// `uint32`
1264    Uint32,
1265    /// `uint8`
1266    Uint8,
1267    /// `int256`
1268    Int256,
1269    /// `int128`
1270    Int128,
1271    /// `int64`
1272    Int64,
1273    /// `int32`
1274    Int32,
1275    /// `int8`
1276    Int8,
1277    /// `address`
1278    Address,
1279    /// `bool`
1280    Bool,
1281    /// `bytes32`
1282    Bytes32,
1283    /// `bytes4`
1284    Bytes4,
1285    /// `Bytes[N]` — bounded byte array
1286    Bytes(u32),
1287    /// `String[N]` — bounded string
1288    StringTy(u32),
1289    /// `DynArray[T, N]` — dynamic array with max length
1290    DynArray(Box<VyperType>, u32),
1291    /// `T[N]` — fixed-size array
1292    FixedArray(Box<VyperType>, u32),
1293    /// `HashMap[K, V]`
1294    HashMap(Box<VyperType>, Box<VyperType>),
1295    /// A named struct type
1296    Struct(String),
1297    /// `decimal` (Vyper fixed-point)
1298    Decimal,
1299    /// `flag` type (Vyper 0.3.8+, bitset enum)
1300    Flag(String),
1301}
1302impl VyperType {
1303    /// Returns the ABI-canonical type string for selector computation.
1304    pub fn abi_canonical(&self) -> String {
1305        match self {
1306            VyperType::Uint256 => "uint256".into(),
1307            VyperType::Uint128 => "uint128".into(),
1308            VyperType::Uint64 => "uint64".into(),
1309            VyperType::Uint32 => "uint32".into(),
1310            VyperType::Uint8 => "uint8".into(),
1311            VyperType::Int256 => "int256".into(),
1312            VyperType::Int128 => "int128".into(),
1313            VyperType::Int64 => "int64".into(),
1314            VyperType::Int32 => "int32".into(),
1315            VyperType::Int8 => "int8".into(),
1316            VyperType::Address => "address".into(),
1317            VyperType::Bool => "bool".into(),
1318            VyperType::Bytes32 => "bytes32".into(),
1319            VyperType::Bytes4 => "bytes4".into(),
1320            VyperType::Bytes(n) => format!("bytes{}", n),
1321            VyperType::StringTy(_) => "string".into(),
1322            VyperType::DynArray(elem, _) => format!("{}[]", elem.abi_canonical()),
1323            VyperType::FixedArray(elem, n) => format!("{}[{}]", elem.abi_canonical(), n),
1324            VyperType::HashMap(_, _) => "bytes32".into(),
1325            VyperType::Struct(name) => name.clone(),
1326            VyperType::Decimal => "int128".into(),
1327            VyperType::Flag(name) => name.clone(),
1328        }
1329    }
1330    /// Returns true if this type is a storage/memory type needing initialization.
1331    pub fn needs_init(&self) -> bool {
1332        matches!(
1333            self,
1334            VyperType::DynArray(_, _)
1335                | VyperType::HashMap(_, _)
1336                | VyperType::Bytes(_)
1337                | VyperType::StringTy(_)
1338        )
1339    }
1340}
1341/// Vyper expression AST node.
1342#[derive(Debug, Clone, PartialEq)]
1343pub enum VyperExpr {
1344    /// Integer literal: `42`
1345    IntLit(i128),
1346    /// Boolean literal: `True` / `False`
1347    BoolLit(bool),
1348    /// String literal: `"hello"`
1349    StrLit(String),
1350    /// Hex literal: `0xdeadbeef`
1351    HexLit(String),
1352    /// Variable reference: `my_var`
1353    Var(String),
1354    /// `self.field` — storage variable access
1355    SelfField(String),
1356    /// `msg.sender`
1357    MsgSender,
1358    /// `msg.value`
1359    MsgValue,
1360    /// `block.timestamp`
1361    BlockTimestamp,
1362    /// `block.number`
1363    BlockNumber,
1364    /// `chain.id`
1365    ChainId,
1366    /// `tx.origin`
1367    TxOrigin,
1368    /// `len(expr)`
1369    Len(Box<VyperExpr>),
1370    /// `convert(expr, T)`
1371    Convert(Box<VyperExpr>, VyperType),
1372    /// `concat(a, b, ...)`
1373    Concat(Vec<VyperExpr>),
1374    /// `keccak256(expr)`
1375    Keccak256(Box<VyperExpr>),
1376    /// `sha256(expr)`
1377    Sha256(Box<VyperExpr>),
1378    /// `ecrecover(hash, v, r, s)`
1379    Ecrecover(
1380        Box<VyperExpr>,
1381        Box<VyperExpr>,
1382        Box<VyperExpr>,
1383        Box<VyperExpr>,
1384    ),
1385    /// `extract32(expr, start)`
1386    Extract32(Box<VyperExpr>, Box<VyperExpr>),
1387    /// Field access on a struct: `expr.field`
1388    FieldAccess(Box<VyperExpr>, String),
1389    /// `expr[index]`
1390    Index(Box<VyperExpr>, Box<VyperExpr>),
1391    /// Function call: `f(args...)`
1392    Call(String, Vec<VyperExpr>),
1393    /// External call: `Interface(addr).method(args...)`
1394    ExtCall(String, Box<VyperExpr>, String, Vec<VyperExpr>),
1395    /// Binary operation: `a + b`
1396    BinOp(String, Box<VyperExpr>, Box<VyperExpr>),
1397    /// Unary operation: `not a`, `-a`
1398    UnaryOp(String, Box<VyperExpr>),
1399    /// Ternary: `value if cond else default`
1400    IfExpr(Box<VyperExpr>, Box<VyperExpr>, Box<VyperExpr>),
1401    /// Struct literal: `MyStruct({field: val, ...})`
1402    StructLit(String, Vec<(String, VyperExpr)>),
1403    /// List literal: `[a, b, c]`
1404    ListLit(Vec<VyperExpr>),
1405    /// `empty(T)` — zero value
1406    Empty(VyperType),
1407    /// `max_value(T)`
1408    MaxValue(VyperType),
1409    /// `min_value(T)`
1410    MinValue(VyperType),
1411    /// `isqrt(n)`
1412    Isqrt(Box<VyperExpr>),
1413    /// `uint2str(n)` (Vyper 0.3+)
1414    Uint2Str(Box<VyperExpr>),
1415    /// `raw_call(addr, data, value=v, gas=g)`
1416    RawCall {
1417        addr: Box<VyperExpr>,
1418        data: Box<VyperExpr>,
1419        value: Option<Box<VyperExpr>>,
1420        gas: Option<Box<VyperExpr>>,
1421    },
1422    /// `create_minimal_proxy_to(target)`
1423    CreateMinimalProxy(Box<VyperExpr>),
1424    /// `create_copy_of(target)`
1425    CreateCopyOf(Box<VyperExpr>),
1426    /// `create_from_blueprint(blueprint, args...)`
1427    CreateFromBlueprint(Box<VyperExpr>, Vec<VyperExpr>),
1428}
1429/// A complete Vyper contract (module).
1430#[derive(Debug, Clone)]
1431pub struct VyperContract {
1432    pub name: String,
1433    pub structs: Vec<VyperStruct>,
1434    pub flags: Vec<VyperFlagDef>,
1435    pub interfaces: Vec<VyperInterface>,
1436    pub constants: Vec<VyperConstant>,
1437    pub storage: Vec<VyperStorageVar>,
1438    pub events: Vec<VyperEvent>,
1439    /// `__init__` function (constructor).
1440    pub constructor: Option<VyperFunction>,
1441    /// `__default__` function (fallback).
1442    pub default_fn: Option<VyperFunction>,
1443    pub functions: Vec<VyperFunction>,
1444    pub doc: Option<String>,
1445}
1446impl VyperContract {
1447    pub fn new(name: impl Into<String>) -> Self {
1448        Self {
1449            name: name.into(),
1450            structs: Vec::new(),
1451            flags: Vec::new(),
1452            interfaces: Vec::new(),
1453            constants: Vec::new(),
1454            storage: Vec::new(),
1455            events: Vec::new(),
1456            constructor: None,
1457            default_fn: None,
1458            functions: Vec::new(),
1459            doc: None,
1460        }
1461    }
1462}
1463/// Vyper function decorator.
1464#[derive(Debug, Clone, PartialEq, Eq)]
1465pub enum VyperDecorator {
1466    /// `@external`
1467    External,
1468    /// `@internal`
1469    Internal,
1470    /// `@view`
1471    View,
1472    /// `@pure`
1473    Pure,
1474    /// `@payable`
1475    Payable,
1476    /// `@nonreentrant("lock")`
1477    NonReentrant(String),
1478    /// `@deploy` (constructor in Vyper 0.4+)
1479    Deploy,
1480}
1481#[allow(dead_code)]
1482pub struct VypPassRegistry {
1483    pub(super) configs: Vec<VypPassConfig>,
1484    pub(super) stats: std::collections::HashMap<String, VypPassStats>,
1485}
1486impl VypPassRegistry {
1487    #[allow(dead_code)]
1488    pub fn new() -> Self {
1489        VypPassRegistry {
1490            configs: Vec::new(),
1491            stats: std::collections::HashMap::new(),
1492        }
1493    }
1494    #[allow(dead_code)]
1495    pub fn register(&mut self, config: VypPassConfig) {
1496        self.stats
1497            .insert(config.pass_name.clone(), VypPassStats::new());
1498        self.configs.push(config);
1499    }
1500    #[allow(dead_code)]
1501    pub fn enabled_passes(&self) -> Vec<&VypPassConfig> {
1502        self.configs.iter().filter(|c| c.enabled).collect()
1503    }
1504    #[allow(dead_code)]
1505    pub fn get_stats(&self, name: &str) -> Option<&VypPassStats> {
1506        self.stats.get(name)
1507    }
1508    #[allow(dead_code)]
1509    pub fn total_passes(&self) -> usize {
1510        self.configs.len()
1511    }
1512    #[allow(dead_code)]
1513    pub fn enabled_count(&self) -> usize {
1514        self.enabled_passes().len()
1515    }
1516    #[allow(dead_code)]
1517    pub fn update_stats(&mut self, name: &str, changes: u64, time_ms: u64, iter: u32) {
1518        if let Some(stats) = self.stats.get_mut(name) {
1519            stats.record_run(changes, time_ms, iter);
1520        }
1521    }
1522}
1523#[allow(dead_code)]
1524pub struct VypConstantFoldingHelper;
1525impl VypConstantFoldingHelper {
1526    #[allow(dead_code)]
1527    pub fn fold_add_i64(a: i64, b: i64) -> Option<i64> {
1528        a.checked_add(b)
1529    }
1530    #[allow(dead_code)]
1531    pub fn fold_sub_i64(a: i64, b: i64) -> Option<i64> {
1532        a.checked_sub(b)
1533    }
1534    #[allow(dead_code)]
1535    pub fn fold_mul_i64(a: i64, b: i64) -> Option<i64> {
1536        a.checked_mul(b)
1537    }
1538    #[allow(dead_code)]
1539    pub fn fold_div_i64(a: i64, b: i64) -> Option<i64> {
1540        if b == 0 {
1541            None
1542        } else {
1543            a.checked_div(b)
1544        }
1545    }
1546    #[allow(dead_code)]
1547    pub fn fold_add_f64(a: f64, b: f64) -> f64 {
1548        a + b
1549    }
1550    #[allow(dead_code)]
1551    pub fn fold_mul_f64(a: f64, b: f64) -> f64 {
1552        a * b
1553    }
1554    #[allow(dead_code)]
1555    pub fn fold_neg_i64(a: i64) -> Option<i64> {
1556        a.checked_neg()
1557    }
1558    #[allow(dead_code)]
1559    pub fn fold_not_bool(a: bool) -> bool {
1560        !a
1561    }
1562    #[allow(dead_code)]
1563    pub fn fold_and_bool(a: bool, b: bool) -> bool {
1564        a && b
1565    }
1566    #[allow(dead_code)]
1567    pub fn fold_or_bool(a: bool, b: bool) -> bool {
1568        a || b
1569    }
1570    #[allow(dead_code)]
1571    pub fn fold_shl_i64(a: i64, b: u32) -> Option<i64> {
1572        a.checked_shl(b)
1573    }
1574    #[allow(dead_code)]
1575    pub fn fold_shr_i64(a: i64, b: u32) -> Option<i64> {
1576        a.checked_shr(b)
1577    }
1578    #[allow(dead_code)]
1579    pub fn fold_rem_i64(a: i64, b: i64) -> Option<i64> {
1580        if b == 0 {
1581            None
1582        } else {
1583            Some(a % b)
1584        }
1585    }
1586    #[allow(dead_code)]
1587    pub fn fold_bitand_i64(a: i64, b: i64) -> i64 {
1588        a & b
1589    }
1590    #[allow(dead_code)]
1591    pub fn fold_bitor_i64(a: i64, b: i64) -> i64 {
1592        a | b
1593    }
1594    #[allow(dead_code)]
1595    pub fn fold_bitxor_i64(a: i64, b: i64) -> i64 {
1596        a ^ b
1597    }
1598    #[allow(dead_code)]
1599    pub fn fold_bitnot_i64(a: i64) -> i64 {
1600        !a
1601    }
1602}
1603#[allow(dead_code)]
1604#[derive(Debug, Clone)]
1605pub struct VypCacheEntry {
1606    pub key: String,
1607    pub data: Vec<u8>,
1608    pub timestamp: u64,
1609    pub valid: bool,
1610}
1611#[allow(dead_code)]
1612#[derive(Debug, Clone)]
1613pub struct VypDepGraph {
1614    pub(super) nodes: Vec<u32>,
1615    pub(super) edges: Vec<(u32, u32)>,
1616}
1617impl VypDepGraph {
1618    #[allow(dead_code)]
1619    pub fn new() -> Self {
1620        VypDepGraph {
1621            nodes: Vec::new(),
1622            edges: Vec::new(),
1623        }
1624    }
1625    #[allow(dead_code)]
1626    pub fn add_node(&mut self, id: u32) {
1627        if !self.nodes.contains(&id) {
1628            self.nodes.push(id);
1629        }
1630    }
1631    #[allow(dead_code)]
1632    pub fn add_dep(&mut self, dep: u32, dependent: u32) {
1633        self.add_node(dep);
1634        self.add_node(dependent);
1635        self.edges.push((dep, dependent));
1636    }
1637    #[allow(dead_code)]
1638    pub fn dependents_of(&self, node: u32) -> Vec<u32> {
1639        self.edges
1640            .iter()
1641            .filter(|(d, _)| *d == node)
1642            .map(|(_, dep)| *dep)
1643            .collect()
1644    }
1645    #[allow(dead_code)]
1646    pub fn dependencies_of(&self, node: u32) -> Vec<u32> {
1647        self.edges
1648            .iter()
1649            .filter(|(_, dep)| *dep == node)
1650            .map(|(d, _)| *d)
1651            .collect()
1652    }
1653    #[allow(dead_code)]
1654    pub fn topological_sort(&self) -> Vec<u32> {
1655        let mut in_degree: std::collections::HashMap<u32, u32> = std::collections::HashMap::new();
1656        for &n in &self.nodes {
1657            in_degree.insert(n, 0);
1658        }
1659        for (_, dep) in &self.edges {
1660            *in_degree.entry(*dep).or_insert(0) += 1;
1661        }
1662        let mut queue: std::collections::VecDeque<u32> = self
1663            .nodes
1664            .iter()
1665            .filter(|&&n| in_degree[&n] == 0)
1666            .copied()
1667            .collect();
1668        let mut result = Vec::new();
1669        while let Some(node) = queue.pop_front() {
1670            result.push(node);
1671            for dep in self.dependents_of(node) {
1672                let cnt = in_degree.entry(dep).or_insert(0);
1673                *cnt = cnt.saturating_sub(1);
1674                if *cnt == 0 {
1675                    queue.push_back(dep);
1676                }
1677            }
1678        }
1679        result
1680    }
1681    #[allow(dead_code)]
1682    pub fn has_cycle(&self) -> bool {
1683        self.topological_sort().len() < self.nodes.len()
1684    }
1685}
1686/// Configuration for VyperExt passes.
1687#[allow(dead_code)]
1688#[derive(Debug, Clone)]
1689pub struct VyperExtPassConfig {
1690    pub name: String,
1691    pub phase: VyperExtPassPhase,
1692    pub enabled: bool,
1693    pub max_iterations: usize,
1694    pub debug: u32,
1695    pub timeout_ms: Option<u64>,
1696}
1697impl VyperExtPassConfig {
1698    #[allow(dead_code)]
1699    pub fn new(name: impl Into<String>) -> Self {
1700        Self {
1701            name: name.into(),
1702            phase: VyperExtPassPhase::Middle,
1703            enabled: true,
1704            max_iterations: 100,
1705            debug: 0,
1706            timeout_ms: None,
1707        }
1708    }
1709    #[allow(dead_code)]
1710    pub fn with_phase(mut self, phase: VyperExtPassPhase) -> Self {
1711        self.phase = phase;
1712        self
1713    }
1714    #[allow(dead_code)]
1715    pub fn with_max_iter(mut self, n: usize) -> Self {
1716        self.max_iterations = n;
1717        self
1718    }
1719    #[allow(dead_code)]
1720    pub fn with_debug(mut self, d: u32) -> Self {
1721        self.debug = d;
1722        self
1723    }
1724    #[allow(dead_code)]
1725    pub fn disabled(mut self) -> Self {
1726        self.enabled = false;
1727        self
1728    }
1729    #[allow(dead_code)]
1730    pub fn with_timeout(mut self, ms: u64) -> Self {
1731        self.timeout_ms = Some(ms);
1732        self
1733    }
1734    #[allow(dead_code)]
1735    pub fn is_debug_enabled(&self) -> bool {
1736        self.debug > 0
1737    }
1738}
1739/// A Vyper event definition.
1740#[derive(Debug, Clone)]
1741pub struct VyperEvent {
1742    pub name: String,
1743    /// `(name, ty, indexed)`
1744    pub fields: Vec<(String, VyperType, bool)>,
1745    pub doc: Option<String>,
1746}
1747#[allow(dead_code)]
1748#[derive(Debug, Clone, Default)]
1749pub struct VypPassStats {
1750    pub total_runs: u32,
1751    pub successful_runs: u32,
1752    pub total_changes: u64,
1753    pub time_ms: u64,
1754    pub iterations_used: u32,
1755}
1756impl VypPassStats {
1757    #[allow(dead_code)]
1758    pub fn new() -> Self {
1759        Self::default()
1760    }
1761    #[allow(dead_code)]
1762    pub fn record_run(&mut self, changes: u64, time_ms: u64, iterations: u32) {
1763        self.total_runs += 1;
1764        self.successful_runs += 1;
1765        self.total_changes += changes;
1766        self.time_ms += time_ms;
1767        self.iterations_used = iterations;
1768    }
1769    #[allow(dead_code)]
1770    pub fn average_changes_per_run(&self) -> f64 {
1771        if self.total_runs == 0 {
1772            return 0.0;
1773        }
1774        self.total_changes as f64 / self.total_runs as f64
1775    }
1776    #[allow(dead_code)]
1777    pub fn success_rate(&self) -> f64 {
1778        if self.total_runs == 0 {
1779            return 0.0;
1780        }
1781        self.successful_runs as f64 / self.total_runs as f64
1782    }
1783    #[allow(dead_code)]
1784    pub fn format_summary(&self) -> String {
1785        format!(
1786            "Runs: {}/{}, Changes: {}, Time: {}ms",
1787            self.successful_runs, self.total_runs, self.total_changes, self.time_ms
1788        )
1789    }
1790}
1791/// A Vyper interface definition.
1792#[derive(Debug, Clone)]
1793pub struct VyperInterface {
1794    pub name: String,
1795    pub functions: Vec<VyperFunction>,
1796    pub doc: Option<String>,
1797}
1798/// Constant folding helper for VyperExt.
1799#[allow(dead_code)]
1800#[derive(Debug, Clone, Default)]
1801pub struct VyperExtConstFolder {
1802    pub(super) folds: usize,
1803    pub(super) failures: usize,
1804    pub(super) enabled: bool,
1805}
1806impl VyperExtConstFolder {
1807    #[allow(dead_code)]
1808    pub fn new() -> Self {
1809        Self {
1810            folds: 0,
1811            failures: 0,
1812            enabled: true,
1813        }
1814    }
1815    #[allow(dead_code)]
1816    pub fn add_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1817        self.folds += 1;
1818        a.checked_add(b)
1819    }
1820    #[allow(dead_code)]
1821    pub fn sub_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1822        self.folds += 1;
1823        a.checked_sub(b)
1824    }
1825    #[allow(dead_code)]
1826    pub fn mul_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1827        self.folds += 1;
1828        a.checked_mul(b)
1829    }
1830    #[allow(dead_code)]
1831    pub fn div_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1832        if b == 0 {
1833            self.failures += 1;
1834            None
1835        } else {
1836            self.folds += 1;
1837            a.checked_div(b)
1838        }
1839    }
1840    #[allow(dead_code)]
1841    pub fn rem_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1842        if b == 0 {
1843            self.failures += 1;
1844            None
1845        } else {
1846            self.folds += 1;
1847            a.checked_rem(b)
1848        }
1849    }
1850    #[allow(dead_code)]
1851    pub fn neg_i64(&mut self, a: i64) -> Option<i64> {
1852        self.folds += 1;
1853        a.checked_neg()
1854    }
1855    #[allow(dead_code)]
1856    pub fn shl_i64(&mut self, a: i64, s: u32) -> Option<i64> {
1857        if s >= 64 {
1858            self.failures += 1;
1859            None
1860        } else {
1861            self.folds += 1;
1862            a.checked_shl(s)
1863        }
1864    }
1865    #[allow(dead_code)]
1866    pub fn shr_i64(&mut self, a: i64, s: u32) -> Option<i64> {
1867        if s >= 64 {
1868            self.failures += 1;
1869            None
1870        } else {
1871            self.folds += 1;
1872            a.checked_shr(s)
1873        }
1874    }
1875    #[allow(dead_code)]
1876    pub fn and_i64(&mut self, a: i64, b: i64) -> i64 {
1877        self.folds += 1;
1878        a & b
1879    }
1880    #[allow(dead_code)]
1881    pub fn or_i64(&mut self, a: i64, b: i64) -> i64 {
1882        self.folds += 1;
1883        a | b
1884    }
1885    #[allow(dead_code)]
1886    pub fn xor_i64(&mut self, a: i64, b: i64) -> i64 {
1887        self.folds += 1;
1888        a ^ b
1889    }
1890    #[allow(dead_code)]
1891    pub fn not_i64(&mut self, a: i64) -> i64 {
1892        self.folds += 1;
1893        !a
1894    }
1895    #[allow(dead_code)]
1896    pub fn fold_count(&self) -> usize {
1897        self.folds
1898    }
1899    #[allow(dead_code)]
1900    pub fn failure_count(&self) -> usize {
1901        self.failures
1902    }
1903    #[allow(dead_code)]
1904    pub fn enable(&mut self) {
1905        self.enabled = true;
1906    }
1907    #[allow(dead_code)]
1908    pub fn disable(&mut self) {
1909        self.enabled = false;
1910    }
1911    #[allow(dead_code)]
1912    pub fn is_enabled(&self) -> bool {
1913        self.enabled
1914    }
1915}
1916/// Compilation context for a single Vyper source file.
1917#[derive(Debug, Clone)]
1918pub struct VyperCompilationCtx {
1919    /// Vyper version pragma (e.g., `"0.3.10"`).
1920    pub version: String,
1921    /// Whether ABI v2 is enabled.
1922    pub abi_v2: bool,
1923    /// Whether to include runtime helpers.
1924    pub include_runtime: bool,
1925    /// Extra `# pragma` lines.
1926    pub extra_pragmas: Vec<String>,
1927}