1use std::collections::HashMap;
6
7use super::functions::VYPER_RUNTIME;
8
9use std::collections::{HashSet, VecDeque};
10
11#[derive(Debug, Clone)]
13pub struct VyperFlagDef {
14 pub name: String,
15 pub variants: Vec<String>,
16 pub doc: Option<String>,
17}
18#[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#[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#[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 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 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 pub fn is_external(&self) -> bool {
196 self.decorators.contains(&VyperDecorator::External)
197 }
198 pub fn is_read_only(&self) -> bool {
200 self.decorators.contains(&VyperDecorator::View)
201 || self.decorators.contains(&VyperDecorator::Pure)
202 }
203}
204#[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#[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#[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#[derive(Debug, Default)]
396pub struct VyperBackend {
397 pub contract: Option<VyperContract>,
399 pub ctx: VyperCompilationCtx,
401 pub type_aliases: HashMap<String, VyperType>,
403 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 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 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#[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#[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#[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#[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#[derive(Debug, Clone)]
1024pub enum VyperStmt {
1025 VarDecl(String, VyperType, Option<VyperExpr>),
1027 Assign(VyperExpr, VyperExpr),
1029 AugAssign(String, VyperExpr, VyperExpr),
1031 ExprStmt(VyperExpr),
1033 Return(Option<VyperExpr>),
1035 If(VyperExpr, Vec<VyperStmt>, Vec<VyperStmt>),
1037 ForRange(String, VyperType, VyperExpr, Vec<VyperStmt>),
1039 ForIn(String, VyperType, VyperExpr, Vec<VyperStmt>),
1041 Log(String, Vec<VyperExpr>),
1043 Assert(VyperExpr, Option<String>),
1045 Raise(String),
1047 Pass,
1049 Break,
1051 Continue,
1053 Send(VyperExpr, VyperExpr),
1055 SelfDestruct(VyperExpr),
1057 Comment(String),
1059}
1060#[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#[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#[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#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1256pub enum VyperType {
1257 Uint256,
1259 Uint128,
1261 Uint64,
1263 Uint32,
1265 Uint8,
1267 Int256,
1269 Int128,
1271 Int64,
1273 Int32,
1275 Int8,
1277 Address,
1279 Bool,
1281 Bytes32,
1283 Bytes4,
1285 Bytes(u32),
1287 StringTy(u32),
1289 DynArray(Box<VyperType>, u32),
1291 FixedArray(Box<VyperType>, u32),
1293 HashMap(Box<VyperType>, Box<VyperType>),
1295 Struct(String),
1297 Decimal,
1299 Flag(String),
1301}
1302impl VyperType {
1303 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 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#[derive(Debug, Clone, PartialEq)]
1343pub enum VyperExpr {
1344 IntLit(i128),
1346 BoolLit(bool),
1348 StrLit(String),
1350 HexLit(String),
1352 Var(String),
1354 SelfField(String),
1356 MsgSender,
1358 MsgValue,
1360 BlockTimestamp,
1362 BlockNumber,
1364 ChainId,
1366 TxOrigin,
1368 Len(Box<VyperExpr>),
1370 Convert(Box<VyperExpr>, VyperType),
1372 Concat(Vec<VyperExpr>),
1374 Keccak256(Box<VyperExpr>),
1376 Sha256(Box<VyperExpr>),
1378 Ecrecover(
1380 Box<VyperExpr>,
1381 Box<VyperExpr>,
1382 Box<VyperExpr>,
1383 Box<VyperExpr>,
1384 ),
1385 Extract32(Box<VyperExpr>, Box<VyperExpr>),
1387 FieldAccess(Box<VyperExpr>, String),
1389 Index(Box<VyperExpr>, Box<VyperExpr>),
1391 Call(String, Vec<VyperExpr>),
1393 ExtCall(String, Box<VyperExpr>, String, Vec<VyperExpr>),
1395 BinOp(String, Box<VyperExpr>, Box<VyperExpr>),
1397 UnaryOp(String, Box<VyperExpr>),
1399 IfExpr(Box<VyperExpr>, Box<VyperExpr>, Box<VyperExpr>),
1401 StructLit(String, Vec<(String, VyperExpr)>),
1403 ListLit(Vec<VyperExpr>),
1405 Empty(VyperType),
1407 MaxValue(VyperType),
1409 MinValue(VyperType),
1411 Isqrt(Box<VyperExpr>),
1413 Uint2Str(Box<VyperExpr>),
1415 RawCall {
1417 addr: Box<VyperExpr>,
1418 data: Box<VyperExpr>,
1419 value: Option<Box<VyperExpr>>,
1420 gas: Option<Box<VyperExpr>>,
1421 },
1422 CreateMinimalProxy(Box<VyperExpr>),
1424 CreateCopyOf(Box<VyperExpr>),
1426 CreateFromBlueprint(Box<VyperExpr>, Vec<VyperExpr>),
1428}
1429#[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 pub constructor: Option<VyperFunction>,
1441 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#[derive(Debug, Clone, PartialEq, Eq)]
1465pub enum VyperDecorator {
1466 External,
1468 Internal,
1470 View,
1472 Pure,
1474 Payable,
1476 NonReentrant(String),
1478 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#[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#[derive(Debug, Clone)]
1741pub struct VyperEvent {
1742 pub name: String,
1743 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#[derive(Debug, Clone)]
1793pub struct VyperInterface {
1794 pub name: String,
1795 pub functions: Vec<VyperFunction>,
1796 pub doc: Option<String>,
1797}
1798#[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#[derive(Debug, Clone)]
1918pub struct VyperCompilationCtx {
1919 pub version: String,
1921 pub abi_v2: bool,
1923 pub include_runtime: bool,
1925 pub extra_pragmas: Vec<String>,
1927}