1use super::functions::*;
6use std::collections::{HashMap, HashSet, VecDeque};
7
8#[allow(dead_code)]
9#[derive(Debug, Clone)]
10pub struct AgdaAnalysisCache {
11 pub(super) entries: std::collections::HashMap<String, AgdaCacheEntry>,
12 pub(super) max_size: usize,
13 pub(super) hits: u64,
14 pub(super) misses: u64,
15}
16impl AgdaAnalysisCache {
17 #[allow(dead_code)]
18 pub fn new(max_size: usize) -> Self {
19 AgdaAnalysisCache {
20 entries: std::collections::HashMap::new(),
21 max_size,
22 hits: 0,
23 misses: 0,
24 }
25 }
26 #[allow(dead_code)]
27 pub fn get(&mut self, key: &str) -> Option<&AgdaCacheEntry> {
28 if self.entries.contains_key(key) {
29 self.hits += 1;
30 self.entries.get(key)
31 } else {
32 self.misses += 1;
33 None
34 }
35 }
36 #[allow(dead_code)]
37 pub fn insert(&mut self, key: String, data: Vec<u8>) {
38 if self.entries.len() >= self.max_size {
39 if let Some(oldest) = self.entries.keys().next().cloned() {
40 self.entries.remove(&oldest);
41 }
42 }
43 self.entries.insert(
44 key.clone(),
45 AgdaCacheEntry {
46 key,
47 data,
48 timestamp: 0,
49 valid: true,
50 },
51 );
52 }
53 #[allow(dead_code)]
54 pub fn invalidate(&mut self, key: &str) {
55 if let Some(entry) = self.entries.get_mut(key) {
56 entry.valid = false;
57 }
58 }
59 #[allow(dead_code)]
60 pub fn clear(&mut self) {
61 self.entries.clear();
62 }
63 #[allow(dead_code)]
64 pub fn hit_rate(&self) -> f64 {
65 let total = self.hits + self.misses;
66 if total == 0 {
67 return 0.0;
68 }
69 self.hits as f64 / total as f64
70 }
71 #[allow(dead_code)]
72 pub fn size(&self) -> usize {
73 self.entries.len()
74 }
75}
76#[derive(Debug, Clone, PartialEq)]
78pub struct AgdaRecord {
79 pub name: String,
81 pub params: Vec<(String, AgdaExpr)>,
83 pub universe: AgdaExpr,
85 pub constructor: Option<String>,
87 pub fields: Vec<AgdaField>,
89 pub copattern_defs: Vec<AgdaClause>,
91}
92#[allow(dead_code)]
93#[derive(Debug, Clone)]
94pub struct AgdaDepGraph {
95 pub(super) nodes: Vec<u32>,
96 pub(super) edges: Vec<(u32, u32)>,
97}
98impl AgdaDepGraph {
99 #[allow(dead_code)]
100 pub fn new() -> Self {
101 AgdaDepGraph {
102 nodes: Vec::new(),
103 edges: Vec::new(),
104 }
105 }
106 #[allow(dead_code)]
107 pub fn add_node(&mut self, id: u32) {
108 if !self.nodes.contains(&id) {
109 self.nodes.push(id);
110 }
111 }
112 #[allow(dead_code)]
113 pub fn add_dep(&mut self, dep: u32, dependent: u32) {
114 self.add_node(dep);
115 self.add_node(dependent);
116 self.edges.push((dep, dependent));
117 }
118 #[allow(dead_code)]
119 pub fn dependents_of(&self, node: u32) -> Vec<u32> {
120 self.edges
121 .iter()
122 .filter(|(d, _)| *d == node)
123 .map(|(_, dep)| *dep)
124 .collect()
125 }
126 #[allow(dead_code)]
127 pub fn dependencies_of(&self, node: u32) -> Vec<u32> {
128 self.edges
129 .iter()
130 .filter(|(_, dep)| *dep == node)
131 .map(|(d, _)| *d)
132 .collect()
133 }
134 #[allow(dead_code)]
135 pub fn topological_sort(&self) -> Vec<u32> {
136 let mut in_degree: std::collections::HashMap<u32, u32> = std::collections::HashMap::new();
137 for &n in &self.nodes {
138 in_degree.insert(n, 0);
139 }
140 for (_, dep) in &self.edges {
141 *in_degree.entry(*dep).or_insert(0) += 1;
142 }
143 let mut queue: std::collections::VecDeque<u32> = self
144 .nodes
145 .iter()
146 .filter(|&&n| in_degree[&n] == 0)
147 .copied()
148 .collect();
149 let mut result = Vec::new();
150 while let Some(node) = queue.pop_front() {
151 result.push(node);
152 for dep in self.dependents_of(node) {
153 let cnt = in_degree.entry(dep).or_insert(0);
154 *cnt = cnt.saturating_sub(1);
155 if *cnt == 0 {
156 queue.push_back(dep);
157 }
158 }
159 }
160 result
161 }
162 #[allow(dead_code)]
163 pub fn has_cycle(&self) -> bool {
164 self.topological_sort().len() < self.nodes.len()
165 }
166}
167#[derive(Debug, Clone, PartialEq)]
169pub struct AgdaConstructor {
170 pub name: String,
172 pub ty: AgdaExpr,
174}
175#[allow(dead_code)]
177#[derive(Debug)]
178pub struct AgdaX2Cache {
179 pub(super) entries: Vec<(u64, Vec<u8>, bool, u32)>,
180 pub(super) cap: usize,
181 pub(super) total_hits: u64,
182 pub(super) total_misses: u64,
183}
184impl AgdaX2Cache {
185 #[allow(dead_code)]
186 pub fn new(cap: usize) -> Self {
187 Self {
188 entries: Vec::new(),
189 cap,
190 total_hits: 0,
191 total_misses: 0,
192 }
193 }
194 #[allow(dead_code)]
195 pub fn get(&mut self, key: u64) -> Option<&[u8]> {
196 for e in self.entries.iter_mut() {
197 if e.0 == key && e.2 {
198 e.3 += 1;
199 self.total_hits += 1;
200 return Some(&e.1);
201 }
202 }
203 self.total_misses += 1;
204 None
205 }
206 #[allow(dead_code)]
207 pub fn put(&mut self, key: u64, data: Vec<u8>) {
208 if self.entries.len() >= self.cap {
209 self.entries.retain(|e| e.2);
210 if self.entries.len() >= self.cap {
211 self.entries.remove(0);
212 }
213 }
214 self.entries.push((key, data, true, 0));
215 }
216 #[allow(dead_code)]
217 pub fn invalidate(&mut self) {
218 for e in self.entries.iter_mut() {
219 e.2 = false;
220 }
221 }
222 #[allow(dead_code)]
223 pub fn hit_rate(&self) -> f64 {
224 let t = self.total_hits + self.total_misses;
225 if t == 0 {
226 0.0
227 } else {
228 self.total_hits as f64 / t as f64
229 }
230 }
231 #[allow(dead_code)]
232 pub fn live_count(&self) -> usize {
233 self.entries.iter().filter(|e| e.2).count()
234 }
235}
236#[allow(dead_code)]
238#[derive(Debug, Clone)]
239pub struct AgdaX2DomTree {
240 pub(super) idom: Vec<Option<usize>>,
241 pub(super) children: Vec<Vec<usize>>,
242 pub(super) depth: Vec<usize>,
243}
244impl AgdaX2DomTree {
245 #[allow(dead_code)]
246 pub fn new(n: usize) -> Self {
247 Self {
248 idom: vec![None; n],
249 children: vec![Vec::new(); n],
250 depth: vec![0; n],
251 }
252 }
253 #[allow(dead_code)]
254 pub fn set_idom(&mut self, node: usize, dom: usize) {
255 if node < self.idom.len() {
256 self.idom[node] = Some(dom);
257 if dom < self.children.len() {
258 self.children[dom].push(node);
259 }
260 self.depth[node] = if dom < self.depth.len() {
261 self.depth[dom] + 1
262 } else {
263 1
264 };
265 }
266 }
267 #[allow(dead_code)]
268 pub fn dominates(&self, a: usize, mut b: usize) -> bool {
269 if a == b {
270 return true;
271 }
272 let n = self.idom.len();
273 for _ in 0..n {
274 match self.idom.get(b).copied().flatten() {
275 None => return false,
276 Some(p) if p == a => return true,
277 Some(p) if p == b => return false,
278 Some(p) => b = p,
279 }
280 }
281 false
282 }
283 #[allow(dead_code)]
284 pub fn children_of(&self, n: usize) -> &[usize] {
285 self.children.get(n).map(|v| v.as_slice()).unwrap_or(&[])
286 }
287 #[allow(dead_code)]
288 pub fn depth_of(&self, n: usize) -> usize {
289 self.depth.get(n).copied().unwrap_or(0)
290 }
291 #[allow(dead_code)]
292 pub fn lca(&self, mut a: usize, mut b: usize) -> usize {
293 let n = self.idom.len();
294 for _ in 0..(2 * n) {
295 if a == b {
296 return a;
297 }
298 if self.depth_of(a) > self.depth_of(b) {
299 a = self.idom.get(a).and_then(|x| *x).unwrap_or(a);
300 } else {
301 b = self.idom.get(b).and_then(|x| *x).unwrap_or(b);
302 }
303 }
304 0
305 }
306}
307#[allow(dead_code)]
308#[derive(Debug, Clone)]
309pub struct AgdaCacheEntry {
310 pub key: String,
311 pub data: Vec<u8>,
312 pub timestamp: u64,
313 pub valid: bool,
314}
315#[allow(dead_code)]
316#[derive(Debug, Clone, Default)]
317pub struct AgdaPassStats {
318 pub total_runs: u32,
319 pub successful_runs: u32,
320 pub total_changes: u64,
321 pub time_ms: u64,
322 pub iterations_used: u32,
323}
324impl AgdaPassStats {
325 #[allow(dead_code)]
326 pub fn new() -> Self {
327 Self::default()
328 }
329 #[allow(dead_code)]
330 pub fn record_run(&mut self, changes: u64, time_ms: u64, iterations: u32) {
331 self.total_runs += 1;
332 self.successful_runs += 1;
333 self.total_changes += changes;
334 self.time_ms += time_ms;
335 self.iterations_used = iterations;
336 }
337 #[allow(dead_code)]
338 pub fn average_changes_per_run(&self) -> f64 {
339 if self.total_runs == 0 {
340 return 0.0;
341 }
342 self.total_changes as f64 / self.total_runs as f64
343 }
344 #[allow(dead_code)]
345 pub fn success_rate(&self) -> f64 {
346 if self.total_runs == 0 {
347 return 0.0;
348 }
349 self.successful_runs as f64 / self.total_runs as f64
350 }
351 #[allow(dead_code)]
352 pub fn format_summary(&self) -> String {
353 format!(
354 "Runs: {}/{}, Changes: {}, Time: {}ms",
355 self.successful_runs, self.total_runs, self.total_changes, self.time_ms
356 )
357 }
358}
359#[allow(dead_code)]
360#[derive(Debug, Clone)]
361pub struct AgdaPassConfig {
362 pub phase: AgdaPassPhase,
363 pub enabled: bool,
364 pub max_iterations: u32,
365 pub debug_output: bool,
366 pub pass_name: String,
367}
368impl AgdaPassConfig {
369 #[allow(dead_code)]
370 pub fn new(name: impl Into<String>, phase: AgdaPassPhase) -> Self {
371 AgdaPassConfig {
372 phase,
373 enabled: true,
374 max_iterations: 10,
375 debug_output: false,
376 pass_name: name.into(),
377 }
378 }
379 #[allow(dead_code)]
380 pub fn disabled(mut self) -> Self {
381 self.enabled = false;
382 self
383 }
384 #[allow(dead_code)]
385 pub fn with_debug(mut self) -> Self {
386 self.debug_output = true;
387 self
388 }
389 #[allow(dead_code)]
390 pub fn max_iter(mut self, n: u32) -> Self {
391 self.max_iterations = n;
392 self
393 }
394}
395#[derive(Debug, Clone, PartialEq)]
397pub enum AgdaDecl {
398 FuncType { name: String, ty: AgdaExpr },
400 FuncDef {
402 name: String,
403 clauses: Vec<AgdaClause>,
404 },
405 DataDecl(AgdaData),
407 RecordDecl(AgdaRecord),
409 ModuleDecl {
411 name: String,
412 params: Vec<(String, AgdaExpr)>,
413 body: Vec<AgdaDecl>,
414 },
415 Import(String),
417 Open(String),
419 Variable(Vec<(String, AgdaExpr)>),
421 Postulate(Vec<(String, AgdaExpr)>),
423 Pragma(String),
425 Comment(String),
427 Raw(String),
429}
430impl AgdaDecl {
431 pub fn emit(&self, indent: usize) -> String {
433 let pad = " ".repeat(indent);
434 match self {
435 AgdaDecl::FuncType { name, ty } => {
436 format!("{}{} : {}", pad, name, ty.emit(indent))
437 }
438 AgdaDecl::FuncDef { name, clauses } => clauses
439 .iter()
440 .map(|c| c.emit_clause(name, indent))
441 .collect::<Vec<_>>()
442 .join("\n"),
443 AgdaDecl::DataDecl(data) => {
444 let ps = emit_agda_params(&data.params, indent);
445 let ps_str = if ps.is_empty() {
446 String::new()
447 } else {
448 format!(" {}", ps)
449 };
450 let mut out = format!(
451 "{}data {}{} : {} where\n",
452 pad,
453 data.name,
454 ps_str,
455 data.indices.emit(indent)
456 );
457 for ctor in &data.constructors {
458 out.push_str(&format!(
459 "{} {} : {}\n",
460 pad,
461 ctor.name,
462 ctor.ty.emit(indent + 1)
463 ));
464 }
465 out
466 }
467 AgdaDecl::RecordDecl(rec) => {
468 let ps = emit_agda_params(&rec.params, indent);
469 let ps_str = if ps.is_empty() {
470 String::new()
471 } else {
472 format!(" {}", ps)
473 };
474 let mut out = format!(
475 "{}record {}{} : {} where\n",
476 pad,
477 rec.name,
478 ps_str,
479 rec.universe.emit(indent)
480 );
481 if let Some(ctor) = &rec.constructor {
482 out.push_str(&format!("{} constructor {}\n", pad, ctor));
483 }
484 out.push_str(&format!("{} field\n", pad));
485 for field in &rec.fields {
486 out.push_str(&format!(
487 "{} {} : {}\n",
488 pad,
489 field.name,
490 field.ty.emit(indent + 2)
491 ));
492 }
493 for clause in &rec.copattern_defs {
494 out.push_str(&clause.emit_clause(&rec.name, indent + 1));
495 out.push('\n');
496 }
497 out
498 }
499 AgdaDecl::ModuleDecl { name, params, body } => {
500 let ps = emit_agda_params(params, indent);
501 let ps_str = if ps.is_empty() {
502 String::new()
503 } else {
504 format!(" {}", ps)
505 };
506 let mut out = format!("{}module {}{} where\n", pad, name, ps_str);
507 for decl in body {
508 out.push_str(&decl.emit(indent + 1));
509 out.push('\n');
510 }
511 out
512 }
513 AgdaDecl::Import(module) => format!("{}import {}", pad, module),
514 AgdaDecl::Open(module) => format!("{}open {}", pad, module),
515 AgdaDecl::Variable(vars) => {
516 let vs: Vec<String> = vars
517 .iter()
518 .map(|(x, ty)| format!("{{{} : {}}}", x, ty.emit(indent)))
519 .collect();
520 format!("{}variable {}", pad, vs.join(" "))
521 }
522 AgdaDecl::Postulate(sigs) => {
523 let mut out = format!("{}postulate\n", pad);
524 for (name, ty) in sigs {
525 out.push_str(&format!("{} {} : {}\n", pad, name, ty.emit(indent + 1)));
526 }
527 out
528 }
529 AgdaDecl::Pragma(text) => format!("{{-# {} #-}}", text),
530 AgdaDecl::Comment(text) => format!("{}-- {}", pad, text),
531 AgdaDecl::Raw(s) => s.clone(),
532 }
533 }
534}
535#[allow(dead_code)]
537#[derive(Debug, Clone)]
538pub struct AgdaExtPassConfig {
539 pub name: String,
540 pub phase: AgdaExtPassPhase,
541 pub enabled: bool,
542 pub max_iterations: usize,
543 pub debug: u32,
544 pub timeout_ms: Option<u64>,
545}
546impl AgdaExtPassConfig {
547 #[allow(dead_code)]
548 pub fn new(name: impl Into<String>) -> Self {
549 Self {
550 name: name.into(),
551 phase: AgdaExtPassPhase::Middle,
552 enabled: true,
553 max_iterations: 100,
554 debug: 0,
555 timeout_ms: None,
556 }
557 }
558 #[allow(dead_code)]
559 pub fn with_phase(mut self, phase: AgdaExtPassPhase) -> Self {
560 self.phase = phase;
561 self
562 }
563 #[allow(dead_code)]
564 pub fn with_max_iter(mut self, n: usize) -> Self {
565 self.max_iterations = n;
566 self
567 }
568 #[allow(dead_code)]
569 pub fn with_debug(mut self, d: u32) -> Self {
570 self.debug = d;
571 self
572 }
573 #[allow(dead_code)]
574 pub fn disabled(mut self) -> Self {
575 self.enabled = false;
576 self
577 }
578 #[allow(dead_code)]
579 pub fn with_timeout(mut self, ms: u64) -> Self {
580 self.timeout_ms = Some(ms);
581 self
582 }
583 #[allow(dead_code)]
584 pub fn is_debug_enabled(&self) -> bool {
585 self.debug > 0
586 }
587}
588#[allow(dead_code)]
590#[derive(Debug, Clone, Default)]
591pub struct AgdaX2PassStats {
592 pub iterations: usize,
593 pub changed: bool,
594 pub nodes_visited: usize,
595 pub nodes_modified: usize,
596 pub time_ms: u64,
597 pub memory_bytes: usize,
598 pub errors: usize,
599}
600impl AgdaX2PassStats {
601 #[allow(dead_code)]
602 pub fn new() -> Self {
603 Self::default()
604 }
605 #[allow(dead_code)]
606 pub fn visit(&mut self) {
607 self.nodes_visited += 1;
608 }
609 #[allow(dead_code)]
610 pub fn modify(&mut self) {
611 self.nodes_modified += 1;
612 self.changed = true;
613 }
614 #[allow(dead_code)]
615 pub fn iterate(&mut self) {
616 self.iterations += 1;
617 }
618 #[allow(dead_code)]
619 pub fn error(&mut self) {
620 self.errors += 1;
621 }
622 #[allow(dead_code)]
623 pub fn efficiency(&self) -> f64 {
624 if self.nodes_visited == 0 {
625 0.0
626 } else {
627 self.nodes_modified as f64 / self.nodes_visited as f64
628 }
629 }
630 #[allow(dead_code)]
631 pub fn merge(&mut self, o: &AgdaX2PassStats) {
632 self.iterations += o.iterations;
633 self.changed |= o.changed;
634 self.nodes_visited += o.nodes_visited;
635 self.nodes_modified += o.nodes_modified;
636 self.time_ms += o.time_ms;
637 self.memory_bytes = self.memory_bytes.max(o.memory_bytes);
638 self.errors += o.errors;
639 }
640}
641#[allow(dead_code)]
642#[derive(Debug, Clone, PartialEq)]
643pub enum AgdaPassPhase {
644 Analysis,
645 Transformation,
646 Verification,
647 Cleanup,
648}
649impl AgdaPassPhase {
650 #[allow(dead_code)]
651 pub fn name(&self) -> &str {
652 match self {
653 AgdaPassPhase::Analysis => "analysis",
654 AgdaPassPhase::Transformation => "transformation",
655 AgdaPassPhase::Verification => "verification",
656 AgdaPassPhase::Cleanup => "cleanup",
657 }
658 }
659 #[allow(dead_code)]
660 pub fn is_modifying(&self) -> bool {
661 matches!(self, AgdaPassPhase::Transformation | AgdaPassPhase::Cleanup)
662 }
663}
664#[derive(Debug, Clone, PartialEq)]
666pub enum AgdaPattern {
667 Var(String),
669 Con(String, Vec<AgdaPattern>),
671 Wildcard,
673 Num(i64),
675 Dot(Box<AgdaPattern>),
677 Absurd,
679 As(String, Box<AgdaPattern>),
681 Implicit(Box<AgdaPattern>),
683}
684#[allow(dead_code)]
686#[derive(Debug, Clone)]
687pub struct AgdaExtWorklist {
688 pub(super) items: std::collections::VecDeque<usize>,
689 pub(super) present: Vec<bool>,
690}
691impl AgdaExtWorklist {
692 #[allow(dead_code)]
693 pub fn new(capacity: usize) -> Self {
694 Self {
695 items: std::collections::VecDeque::new(),
696 present: vec![false; capacity],
697 }
698 }
699 #[allow(dead_code)]
700 pub fn push(&mut self, id: usize) {
701 if id < self.present.len() && !self.present[id] {
702 self.present[id] = true;
703 self.items.push_back(id);
704 }
705 }
706 #[allow(dead_code)]
707 pub fn push_front(&mut self, id: usize) {
708 if id < self.present.len() && !self.present[id] {
709 self.present[id] = true;
710 self.items.push_front(id);
711 }
712 }
713 #[allow(dead_code)]
714 pub fn pop(&mut self) -> Option<usize> {
715 let id = self.items.pop_front()?;
716 if id < self.present.len() {
717 self.present[id] = false;
718 }
719 Some(id)
720 }
721 #[allow(dead_code)]
722 pub fn is_empty(&self) -> bool {
723 self.items.is_empty()
724 }
725 #[allow(dead_code)]
726 pub fn len(&self) -> usize {
727 self.items.len()
728 }
729 #[allow(dead_code)]
730 pub fn contains(&self, id: usize) -> bool {
731 id < self.present.len() && self.present[id]
732 }
733 #[allow(dead_code)]
734 pub fn drain_all(&mut self) -> Vec<usize> {
735 let v: Vec<usize> = self.items.drain(..).collect();
736 for &id in &v {
737 if id < self.present.len() {
738 self.present[id] = false;
739 }
740 }
741 v
742 }
743}
744#[allow(dead_code)]
745#[derive(Debug, Clone)]
746pub struct AgdaLivenessInfo {
747 pub live_in: Vec<std::collections::HashSet<u32>>,
748 pub live_out: Vec<std::collections::HashSet<u32>>,
749 pub defs: Vec<std::collections::HashSet<u32>>,
750 pub uses: Vec<std::collections::HashSet<u32>>,
751}
752impl AgdaLivenessInfo {
753 #[allow(dead_code)]
754 pub fn new(block_count: usize) -> Self {
755 AgdaLivenessInfo {
756 live_in: vec![std::collections::HashSet::new(); block_count],
757 live_out: vec![std::collections::HashSet::new(); block_count],
758 defs: vec![std::collections::HashSet::new(); block_count],
759 uses: vec![std::collections::HashSet::new(); block_count],
760 }
761 }
762 #[allow(dead_code)]
763 pub fn add_def(&mut self, block: usize, var: u32) {
764 if block < self.defs.len() {
765 self.defs[block].insert(var);
766 }
767 }
768 #[allow(dead_code)]
769 pub fn add_use(&mut self, block: usize, var: u32) {
770 if block < self.uses.len() {
771 self.uses[block].insert(var);
772 }
773 }
774 #[allow(dead_code)]
775 pub fn is_live_in(&self, block: usize, var: u32) -> bool {
776 self.live_in
777 .get(block)
778 .map(|s| s.contains(&var))
779 .unwrap_or(false)
780 }
781 #[allow(dead_code)]
782 pub fn is_live_out(&self, block: usize, var: u32) -> bool {
783 self.live_out
784 .get(block)
785 .map(|s| s.contains(&var))
786 .unwrap_or(false)
787 }
788}
789#[allow(dead_code)]
791#[derive(Debug, Clone, PartialEq, Eq, Hash)]
792pub enum AgdaExtPassPhase {
793 Early,
794 Middle,
795 Late,
796 Finalize,
797}
798impl AgdaExtPassPhase {
799 #[allow(dead_code)]
800 pub fn is_early(&self) -> bool {
801 matches!(self, Self::Early)
802 }
803 #[allow(dead_code)]
804 pub fn is_middle(&self) -> bool {
805 matches!(self, Self::Middle)
806 }
807 #[allow(dead_code)]
808 pub fn is_late(&self) -> bool {
809 matches!(self, Self::Late)
810 }
811 #[allow(dead_code)]
812 pub fn is_finalize(&self) -> bool {
813 matches!(self, Self::Finalize)
814 }
815 #[allow(dead_code)]
816 pub fn order(&self) -> u32 {
817 match self {
818 Self::Early => 0,
819 Self::Middle => 1,
820 Self::Late => 2,
821 Self::Finalize => 3,
822 }
823 }
824 #[allow(dead_code)]
825 pub fn from_order(n: u32) -> Option<Self> {
826 match n {
827 0 => Some(Self::Early),
828 1 => Some(Self::Middle),
829 2 => Some(Self::Late),
830 3 => Some(Self::Finalize),
831 _ => None,
832 }
833 }
834}
835#[allow(dead_code)]
837#[derive(Debug, Default)]
838pub struct AgdaExtPassRegistry {
839 pub(super) configs: Vec<AgdaExtPassConfig>,
840 pub(super) stats: Vec<AgdaExtPassStats>,
841}
842impl AgdaExtPassRegistry {
843 #[allow(dead_code)]
844 pub fn new() -> Self {
845 Self::default()
846 }
847 #[allow(dead_code)]
848 pub fn register(&mut self, c: AgdaExtPassConfig) {
849 self.stats.push(AgdaExtPassStats::new());
850 self.configs.push(c);
851 }
852 #[allow(dead_code)]
853 pub fn len(&self) -> usize {
854 self.configs.len()
855 }
856 #[allow(dead_code)]
857 pub fn is_empty(&self) -> bool {
858 self.configs.is_empty()
859 }
860 #[allow(dead_code)]
861 pub fn get(&self, i: usize) -> Option<&AgdaExtPassConfig> {
862 self.configs.get(i)
863 }
864 #[allow(dead_code)]
865 pub fn get_stats(&self, i: usize) -> Option<&AgdaExtPassStats> {
866 self.stats.get(i)
867 }
868 #[allow(dead_code)]
869 pub fn enabled_passes(&self) -> Vec<&AgdaExtPassConfig> {
870 self.configs.iter().filter(|c| c.enabled).collect()
871 }
872 #[allow(dead_code)]
873 pub fn passes_in_phase(&self, ph: &AgdaExtPassPhase) -> Vec<&AgdaExtPassConfig> {
874 self.configs
875 .iter()
876 .filter(|c| c.enabled && &c.phase == ph)
877 .collect()
878 }
879 #[allow(dead_code)]
880 pub fn total_nodes_visited(&self) -> usize {
881 self.stats.iter().map(|s| s.nodes_visited).sum()
882 }
883 #[allow(dead_code)]
884 pub fn any_changed(&self) -> bool {
885 self.stats.iter().any(|s| s.changed)
886 }
887}
888#[allow(dead_code)]
890#[derive(Debug, Clone, Default)]
891pub struct AgdaExtConstFolder {
892 pub(super) folds: usize,
893 pub(super) failures: usize,
894 pub(super) enabled: bool,
895}
896impl AgdaExtConstFolder {
897 #[allow(dead_code)]
898 pub fn new() -> Self {
899 Self {
900 folds: 0,
901 failures: 0,
902 enabled: true,
903 }
904 }
905 #[allow(dead_code)]
906 pub fn add_i64(&mut self, a: i64, b: i64) -> Option<i64> {
907 self.folds += 1;
908 a.checked_add(b)
909 }
910 #[allow(dead_code)]
911 pub fn sub_i64(&mut self, a: i64, b: i64) -> Option<i64> {
912 self.folds += 1;
913 a.checked_sub(b)
914 }
915 #[allow(dead_code)]
916 pub fn mul_i64(&mut self, a: i64, b: i64) -> Option<i64> {
917 self.folds += 1;
918 a.checked_mul(b)
919 }
920 #[allow(dead_code)]
921 pub fn div_i64(&mut self, a: i64, b: i64) -> Option<i64> {
922 if b == 0 {
923 self.failures += 1;
924 None
925 } else {
926 self.folds += 1;
927 a.checked_div(b)
928 }
929 }
930 #[allow(dead_code)]
931 pub fn rem_i64(&mut self, a: i64, b: i64) -> Option<i64> {
932 if b == 0 {
933 self.failures += 1;
934 None
935 } else {
936 self.folds += 1;
937 a.checked_rem(b)
938 }
939 }
940 #[allow(dead_code)]
941 pub fn neg_i64(&mut self, a: i64) -> Option<i64> {
942 self.folds += 1;
943 a.checked_neg()
944 }
945 #[allow(dead_code)]
946 pub fn shl_i64(&mut self, a: i64, s: u32) -> Option<i64> {
947 if s >= 64 {
948 self.failures += 1;
949 None
950 } else {
951 self.folds += 1;
952 a.checked_shl(s)
953 }
954 }
955 #[allow(dead_code)]
956 pub fn shr_i64(&mut self, a: i64, s: u32) -> Option<i64> {
957 if s >= 64 {
958 self.failures += 1;
959 None
960 } else {
961 self.folds += 1;
962 a.checked_shr(s)
963 }
964 }
965 #[allow(dead_code)]
966 pub fn and_i64(&mut self, a: i64, b: i64) -> i64 {
967 self.folds += 1;
968 a & b
969 }
970 #[allow(dead_code)]
971 pub fn or_i64(&mut self, a: i64, b: i64) -> i64 {
972 self.folds += 1;
973 a | b
974 }
975 #[allow(dead_code)]
976 pub fn xor_i64(&mut self, a: i64, b: i64) -> i64 {
977 self.folds += 1;
978 a ^ b
979 }
980 #[allow(dead_code)]
981 pub fn not_i64(&mut self, a: i64) -> i64 {
982 self.folds += 1;
983 !a
984 }
985 #[allow(dead_code)]
986 pub fn fold_count(&self) -> usize {
987 self.folds
988 }
989 #[allow(dead_code)]
990 pub fn failure_count(&self) -> usize {
991 self.failures
992 }
993 #[allow(dead_code)]
994 pub fn enable(&mut self) {
995 self.enabled = true;
996 }
997 #[allow(dead_code)]
998 pub fn disable(&mut self) {
999 self.enabled = false;
1000 }
1001 #[allow(dead_code)]
1002 pub fn is_enabled(&self) -> bool {
1003 self.enabled
1004 }
1005}
1006#[allow(dead_code)]
1007pub struct AgdaPassRegistry {
1008 pub(super) configs: Vec<AgdaPassConfig>,
1009 pub(super) stats: std::collections::HashMap<String, AgdaPassStats>,
1010}
1011impl AgdaPassRegistry {
1012 #[allow(dead_code)]
1013 pub fn new() -> Self {
1014 AgdaPassRegistry {
1015 configs: Vec::new(),
1016 stats: std::collections::HashMap::new(),
1017 }
1018 }
1019 #[allow(dead_code)]
1020 pub fn register(&mut self, config: AgdaPassConfig) {
1021 self.stats
1022 .insert(config.pass_name.clone(), AgdaPassStats::new());
1023 self.configs.push(config);
1024 }
1025 #[allow(dead_code)]
1026 pub fn enabled_passes(&self) -> Vec<&AgdaPassConfig> {
1027 self.configs.iter().filter(|c| c.enabled).collect()
1028 }
1029 #[allow(dead_code)]
1030 pub fn get_stats(&self, name: &str) -> Option<&AgdaPassStats> {
1031 self.stats.get(name)
1032 }
1033 #[allow(dead_code)]
1034 pub fn total_passes(&self) -> usize {
1035 self.configs.len()
1036 }
1037 #[allow(dead_code)]
1038 pub fn enabled_count(&self) -> usize {
1039 self.enabled_passes().len()
1040 }
1041 #[allow(dead_code)]
1042 pub fn update_stats(&mut self, name: &str, changes: u64, time_ms: u64, iter: u32) {
1043 if let Some(stats) = self.stats.get_mut(name) {
1044 stats.record_run(changes, time_ms, iter);
1045 }
1046 }
1047}
1048#[derive(Debug, Clone, PartialEq)]
1051pub struct AgdaClause {
1052 pub patterns: Vec<AgdaPattern>,
1054 pub rhs: Option<AgdaExpr>,
1056 pub where_decls: Vec<AgdaDecl>,
1058}
1059impl AgdaClause {
1060 pub fn emit_patterns(&self) -> String {
1062 self.patterns
1063 .iter()
1064 .map(|p| p.to_string())
1065 .collect::<Vec<_>>()
1066 .join(" ")
1067 }
1068 pub fn emit_clause(&self, func_name: &str, indent: usize) -> String {
1070 let pad = " ".repeat(indent);
1071 let pats = self.emit_patterns();
1072 let lhs = if pats.is_empty() {
1073 func_name.to_string()
1074 } else {
1075 format!("{} {}", func_name, pats)
1076 };
1077 match &self.rhs {
1078 None => format!("{}{}", pad, lhs),
1079 Some(rhs) => {
1080 let mut out = format!("{}{} = {}", pad, lhs, rhs.emit(indent));
1081 if !self.where_decls.is_empty() {
1082 out.push_str(&format!("\n{} where", pad));
1083 for w in &self.where_decls {
1084 for line in w.emit(indent + 2).lines() {
1085 out.push_str(&format!("\n{} {}", pad, line));
1086 }
1087 }
1088 }
1089 out
1090 }
1091 }
1092 }
1093}
1094#[allow(dead_code)]
1096#[derive(Debug, Clone)]
1097pub struct AgdaExtDepGraph {
1098 pub(super) n: usize,
1099 pub(super) adj: Vec<Vec<usize>>,
1100 pub(super) rev: Vec<Vec<usize>>,
1101 pub(super) edge_count: usize,
1102}
1103impl AgdaExtDepGraph {
1104 #[allow(dead_code)]
1105 pub fn new(n: usize) -> Self {
1106 Self {
1107 n,
1108 adj: vec![Vec::new(); n],
1109 rev: vec![Vec::new(); n],
1110 edge_count: 0,
1111 }
1112 }
1113 #[allow(dead_code)]
1114 pub fn add_edge(&mut self, from: usize, to: usize) {
1115 if from < self.n && to < self.n {
1116 if !self.adj[from].contains(&to) {
1117 self.adj[from].push(to);
1118 self.rev[to].push(from);
1119 self.edge_count += 1;
1120 }
1121 }
1122 }
1123 #[allow(dead_code)]
1124 pub fn succs(&self, n: usize) -> &[usize] {
1125 self.adj.get(n).map(|v| v.as_slice()).unwrap_or(&[])
1126 }
1127 #[allow(dead_code)]
1128 pub fn preds(&self, n: usize) -> &[usize] {
1129 self.rev.get(n).map(|v| v.as_slice()).unwrap_or(&[])
1130 }
1131 #[allow(dead_code)]
1132 pub fn topo_sort(&self) -> Option<Vec<usize>> {
1133 let mut deg: Vec<usize> = (0..self.n).map(|i| self.rev[i].len()).collect();
1134 let mut q: std::collections::VecDeque<usize> =
1135 (0..self.n).filter(|&i| deg[i] == 0).collect();
1136 let mut out = Vec::with_capacity(self.n);
1137 while let Some(u) = q.pop_front() {
1138 out.push(u);
1139 for &v in &self.adj[u] {
1140 deg[v] -= 1;
1141 if deg[v] == 0 {
1142 q.push_back(v);
1143 }
1144 }
1145 }
1146 if out.len() == self.n {
1147 Some(out)
1148 } else {
1149 None
1150 }
1151 }
1152 #[allow(dead_code)]
1153 pub fn has_cycle(&self) -> bool {
1154 self.topo_sort().is_none()
1155 }
1156 #[allow(dead_code)]
1157 pub fn reachable(&self, start: usize) -> Vec<usize> {
1158 let mut vis = vec![false; self.n];
1159 let mut stk = vec![start];
1160 let mut out = Vec::new();
1161 while let Some(u) = stk.pop() {
1162 if u < self.n && !vis[u] {
1163 vis[u] = true;
1164 out.push(u);
1165 for &v in &self.adj[u] {
1166 if !vis[v] {
1167 stk.push(v);
1168 }
1169 }
1170 }
1171 }
1172 out
1173 }
1174 #[allow(dead_code)]
1175 pub fn scc(&self) -> Vec<Vec<usize>> {
1176 let mut visited = vec![false; self.n];
1177 let mut order = Vec::new();
1178 for i in 0..self.n {
1179 if !visited[i] {
1180 let mut stk = vec![(i, 0usize)];
1181 while let Some((u, idx)) = stk.last_mut() {
1182 if !visited[*u] {
1183 visited[*u] = true;
1184 }
1185 if *idx < self.adj[*u].len() {
1186 let v = self.adj[*u][*idx];
1187 *idx += 1;
1188 if !visited[v] {
1189 stk.push((v, 0));
1190 }
1191 } else {
1192 order.push(*u);
1193 stk.pop();
1194 }
1195 }
1196 }
1197 }
1198 let mut comp = vec![usize::MAX; self.n];
1199 let mut components: Vec<Vec<usize>> = Vec::new();
1200 for &start in order.iter().rev() {
1201 if comp[start] == usize::MAX {
1202 let cid = components.len();
1203 let mut component = Vec::new();
1204 let mut stk = vec![start];
1205 while let Some(u) = stk.pop() {
1206 if comp[u] == usize::MAX {
1207 comp[u] = cid;
1208 component.push(u);
1209 for &v in &self.rev[u] {
1210 if comp[v] == usize::MAX {
1211 stk.push(v);
1212 }
1213 }
1214 }
1215 }
1216 components.push(component);
1217 }
1218 }
1219 components
1220 }
1221 #[allow(dead_code)]
1222 pub fn node_count(&self) -> usize {
1223 self.n
1224 }
1225 #[allow(dead_code)]
1226 pub fn edge_count(&self) -> usize {
1227 self.edge_count
1228 }
1229}
1230#[allow(dead_code)]
1231#[derive(Debug, Clone)]
1232pub struct AgdaDominatorTree {
1233 pub idom: Vec<Option<u32>>,
1234 pub dom_children: Vec<Vec<u32>>,
1235 pub dom_depth: Vec<u32>,
1236}
1237impl AgdaDominatorTree {
1238 #[allow(dead_code)]
1239 pub fn new(size: usize) -> Self {
1240 AgdaDominatorTree {
1241 idom: vec![None; size],
1242 dom_children: vec![Vec::new(); size],
1243 dom_depth: vec![0; size],
1244 }
1245 }
1246 #[allow(dead_code)]
1247 pub fn set_idom(&mut self, node: usize, idom: u32) {
1248 self.idom[node] = Some(idom);
1249 }
1250 #[allow(dead_code)]
1251 pub fn dominates(&self, a: usize, b: usize) -> bool {
1252 if a == b {
1253 return true;
1254 }
1255 let mut cur = b;
1256 loop {
1257 match self.idom[cur] {
1258 Some(parent) if parent as usize == a => return true,
1259 Some(parent) if parent as usize == cur => return false,
1260 Some(parent) => cur = parent as usize,
1261 None => return false,
1262 }
1263 }
1264 }
1265 #[allow(dead_code)]
1266 pub fn depth(&self, node: usize) -> u32 {
1267 self.dom_depth.get(node).copied().unwrap_or(0)
1268 }
1269}
1270#[allow(dead_code)]
1272#[derive(Debug, Clone)]
1273pub struct AgdaExtDomTree {
1274 pub(super) idom: Vec<Option<usize>>,
1275 pub(super) children: Vec<Vec<usize>>,
1276 pub(super) depth: Vec<usize>,
1277}
1278impl AgdaExtDomTree {
1279 #[allow(dead_code)]
1280 pub fn new(n: usize) -> Self {
1281 Self {
1282 idom: vec![None; n],
1283 children: vec![Vec::new(); n],
1284 depth: vec![0; n],
1285 }
1286 }
1287 #[allow(dead_code)]
1288 pub fn set_idom(&mut self, node: usize, dom: usize) {
1289 if node < self.idom.len() {
1290 self.idom[node] = Some(dom);
1291 if dom < self.children.len() {
1292 self.children[dom].push(node);
1293 }
1294 self.depth[node] = if dom < self.depth.len() {
1295 self.depth[dom] + 1
1296 } else {
1297 1
1298 };
1299 }
1300 }
1301 #[allow(dead_code)]
1302 pub fn dominates(&self, a: usize, mut b: usize) -> bool {
1303 if a == b {
1304 return true;
1305 }
1306 let n = self.idom.len();
1307 for _ in 0..n {
1308 match self.idom.get(b).copied().flatten() {
1309 None => return false,
1310 Some(p) if p == a => return true,
1311 Some(p) if p == b => return false,
1312 Some(p) => b = p,
1313 }
1314 }
1315 false
1316 }
1317 #[allow(dead_code)]
1318 pub fn children_of(&self, n: usize) -> &[usize] {
1319 self.children.get(n).map(|v| v.as_slice()).unwrap_or(&[])
1320 }
1321 #[allow(dead_code)]
1322 pub fn depth_of(&self, n: usize) -> usize {
1323 self.depth.get(n).copied().unwrap_or(0)
1324 }
1325 #[allow(dead_code)]
1326 pub fn lca(&self, mut a: usize, mut b: usize) -> usize {
1327 let n = self.idom.len();
1328 for _ in 0..(2 * n) {
1329 if a == b {
1330 return a;
1331 }
1332 if self.depth_of(a) > self.depth_of(b) {
1333 a = self.idom.get(a).and_then(|x| *x).unwrap_or(a);
1334 } else {
1335 b = self.idom.get(b).and_then(|x| *x).unwrap_or(b);
1336 }
1337 }
1338 0
1339 }
1340}
1341#[derive(Debug, Clone, PartialEq)]
1343pub struct AgdaField {
1344 pub name: String,
1346 pub ty: AgdaExpr,
1348}
1349#[derive(Debug, Clone, PartialEq)]
1351pub enum AgdaExpr {
1352 Var(String),
1354 App(Box<AgdaExpr>, Box<AgdaExpr>),
1356 Lambda(String, Box<AgdaExpr>),
1358 Pi(Option<String>, Box<AgdaExpr>, Box<AgdaExpr>),
1361 Let(String, Box<AgdaExpr>, Box<AgdaExpr>),
1363 With(Box<AgdaExpr>, Vec<AgdaExpr>),
1365 Case(Box<AgdaExpr>, Vec<AgdaClause>),
1367 Set(Option<u32>),
1369 Prop,
1371 Hole,
1373 Underscore,
1375 Num(i64),
1377 Str(String),
1379 Module(String),
1381 Implicit(Box<AgdaExpr>),
1383 Tuple(Vec<AgdaExpr>),
1385 Record(Vec<(String, AgdaExpr)>),
1387 Ascription(Box<AgdaExpr>, Box<AgdaExpr>),
1389 IfThenElse(Box<AgdaExpr>, Box<AgdaExpr>, Box<AgdaExpr>),
1391}
1392impl AgdaExpr {
1393 pub fn emit(&self, indent: usize) -> String {
1395 let pad = " ".repeat(indent);
1396 match self {
1397 AgdaExpr::Var(x) => x.clone(),
1398 AgdaExpr::Num(n) => n.to_string(),
1399 AgdaExpr::Str(s) => format!("\"{}\"", escape_agda_string(s)),
1400 AgdaExpr::Hole => "{! !}".to_string(),
1401 AgdaExpr::Underscore => "_".to_string(),
1402 AgdaExpr::Prop => "Prop".to_string(),
1403 AgdaExpr::Module(m) => m.clone(),
1404 AgdaExpr::Set(None) => "Set".to_string(),
1405 AgdaExpr::Set(Some(0)) => "Set".to_string(),
1406 AgdaExpr::Set(Some(1)) => "Set₁".to_string(),
1407 AgdaExpr::Set(Some(2)) => "Set₂".to_string(),
1408 AgdaExpr::Set(Some(n)) => format!("Set{}", n),
1409 AgdaExpr::App(f, a) => {
1410 let fs = f.emit_func(indent);
1411 let as_ = a.emit_atom(indent);
1412 format!("{} {}", fs, as_)
1413 }
1414 AgdaExpr::Lambda(x, body) => format!("λ {} → {}", x, body.emit(indent)),
1415 AgdaExpr::Pi(None, dom, cod) => {
1416 format!("{} → {}", dom.emit_pi_dom(indent), cod.emit(indent))
1417 }
1418 AgdaExpr::Pi(Some(x), dom, cod) => {
1419 format!("({} : {}) → {}", x, dom.emit(indent), cod.emit(indent))
1420 }
1421 AgdaExpr::Let(x, rhs, body) => {
1422 format!(
1423 "let {} = {}\n{}in {}",
1424 x,
1425 rhs.emit(indent + 1),
1426 pad,
1427 body.emit(indent)
1428 )
1429 }
1430 AgdaExpr::With(e, ws) => {
1431 let ws_s: Vec<String> = ws.iter().map(|w| w.emit(indent)).collect();
1432 format!("{} | {}", e.emit(indent), ws_s.join(" | "))
1433 }
1434 AgdaExpr::Case(scrutinee, clauses) => {
1435 let mut out = "(λ _case → {\n".to_string();
1436 for clause in clauses {
1437 out.push_str(&format!(
1438 "{} ; {} → {}\n",
1439 pad,
1440 clause.emit_patterns(),
1441 clause
1442 .rhs
1443 .as_ref()
1444 .map(|r| r.emit(indent + 2))
1445 .unwrap_or_else(|| "⊥-elim _".to_string())
1446 ));
1447 }
1448 out.push_str(&format!("{}}} {}", pad, scrutinee.emit(indent)));
1449 out.push(')');
1450 out
1451 }
1452 AgdaExpr::Implicit(e) => format!("{{{}}}", e.emit(indent)),
1453 AgdaExpr::Tuple(elems) => {
1454 let es: Vec<String> = elems.iter().map(|e| e.emit(indent)).collect();
1455 format!("({})", es.join(" , "))
1456 }
1457 AgdaExpr::Record(fields) => {
1458 let fs: Vec<String> = fields
1459 .iter()
1460 .map(|(k, v)| format!("{} = {}", k, v.emit(indent)))
1461 .collect();
1462 format!("record {{ {} }}", fs.join(" ; "))
1463 }
1464 AgdaExpr::Ascription(e, ty) => {
1465 format!("({} : {})", e.emit(indent), ty.emit(indent))
1466 }
1467 AgdaExpr::IfThenElse(cond, then_, else_) => {
1468 format!(
1469 "if {} then {} else {}",
1470 cond.emit(indent),
1471 then_.emit(indent),
1472 else_.emit(indent)
1473 )
1474 }
1475 }
1476 }
1477 pub(super) fn emit_pi_dom(&self, indent: usize) -> String {
1480 match self {
1481 AgdaExpr::Pi(_, _, _) | AgdaExpr::Lambda(_, _) | AgdaExpr::Let(_, _, _) => {
1482 format!("({})", self.emit(indent))
1483 }
1484 _ => self.emit(indent),
1485 }
1486 }
1487 pub(super) fn emit_func(&self, indent: usize) -> String {
1490 match self {
1491 AgdaExpr::Var(_)
1492 | AgdaExpr::Num(_)
1493 | AgdaExpr::Str(_)
1494 | AgdaExpr::Hole
1495 | AgdaExpr::Underscore
1496 | AgdaExpr::Prop
1497 | AgdaExpr::Set(_)
1498 | AgdaExpr::Module(_)
1499 | AgdaExpr::Tuple(_)
1500 | AgdaExpr::Record(_)
1501 | AgdaExpr::Implicit(_)
1502 | AgdaExpr::App(_, _) => self.emit(indent),
1503 _ => format!("({})", self.emit(indent)),
1504 }
1505 }
1506 pub(super) fn emit_atom(&self, indent: usize) -> String {
1508 match self {
1509 AgdaExpr::Var(_)
1510 | AgdaExpr::Num(_)
1511 | AgdaExpr::Str(_)
1512 | AgdaExpr::Hole
1513 | AgdaExpr::Underscore
1514 | AgdaExpr::Prop
1515 | AgdaExpr::Set(_)
1516 | AgdaExpr::Module(_)
1517 | AgdaExpr::Tuple(_)
1518 | AgdaExpr::Record(_)
1519 | AgdaExpr::Implicit(_) => self.emit(indent),
1520 _ => format!("({})", self.emit(indent)),
1521 }
1522 }
1523}
1524#[allow(dead_code)]
1526#[derive(Debug, Clone, Default)]
1527pub struct AgdaExtPassStats {
1528 pub iterations: usize,
1529 pub changed: bool,
1530 pub nodes_visited: usize,
1531 pub nodes_modified: usize,
1532 pub time_ms: u64,
1533 pub memory_bytes: usize,
1534 pub errors: usize,
1535}
1536impl AgdaExtPassStats {
1537 #[allow(dead_code)]
1538 pub fn new() -> Self {
1539 Self::default()
1540 }
1541 #[allow(dead_code)]
1542 pub fn visit(&mut self) {
1543 self.nodes_visited += 1;
1544 }
1545 #[allow(dead_code)]
1546 pub fn modify(&mut self) {
1547 self.nodes_modified += 1;
1548 self.changed = true;
1549 }
1550 #[allow(dead_code)]
1551 pub fn iterate(&mut self) {
1552 self.iterations += 1;
1553 }
1554 #[allow(dead_code)]
1555 pub fn error(&mut self) {
1556 self.errors += 1;
1557 }
1558 #[allow(dead_code)]
1559 pub fn efficiency(&self) -> f64 {
1560 if self.nodes_visited == 0 {
1561 0.0
1562 } else {
1563 self.nodes_modified as f64 / self.nodes_visited as f64
1564 }
1565 }
1566 #[allow(dead_code)]
1567 pub fn merge(&mut self, o: &AgdaExtPassStats) {
1568 self.iterations += o.iterations;
1569 self.changed |= o.changed;
1570 self.nodes_visited += o.nodes_visited;
1571 self.nodes_modified += o.nodes_modified;
1572 self.time_ms += o.time_ms;
1573 self.memory_bytes = self.memory_bytes.max(o.memory_bytes);
1574 self.errors += o.errors;
1575 }
1576}
1577#[allow(dead_code)]
1579#[derive(Debug, Clone)]
1580pub struct AgdaX2PassConfig {
1581 pub name: String,
1582 pub phase: AgdaX2PassPhase,
1583 pub enabled: bool,
1584 pub max_iterations: usize,
1585 pub debug: u32,
1586 pub timeout_ms: Option<u64>,
1587}
1588impl AgdaX2PassConfig {
1589 #[allow(dead_code)]
1590 pub fn new(name: impl Into<String>) -> Self {
1591 Self {
1592 name: name.into(),
1593 phase: AgdaX2PassPhase::Middle,
1594 enabled: true,
1595 max_iterations: 100,
1596 debug: 0,
1597 timeout_ms: None,
1598 }
1599 }
1600 #[allow(dead_code)]
1601 pub fn with_phase(mut self, phase: AgdaX2PassPhase) -> Self {
1602 self.phase = phase;
1603 self
1604 }
1605 #[allow(dead_code)]
1606 pub fn with_max_iter(mut self, n: usize) -> Self {
1607 self.max_iterations = n;
1608 self
1609 }
1610 #[allow(dead_code)]
1611 pub fn with_debug(mut self, d: u32) -> Self {
1612 self.debug = d;
1613 self
1614 }
1615 #[allow(dead_code)]
1616 pub fn disabled(mut self) -> Self {
1617 self.enabled = false;
1618 self
1619 }
1620 #[allow(dead_code)]
1621 pub fn with_timeout(mut self, ms: u64) -> Self {
1622 self.timeout_ms = Some(ms);
1623 self
1624 }
1625 #[allow(dead_code)]
1626 pub fn is_debug_enabled(&self) -> bool {
1627 self.debug > 0
1628 }
1629}
1630#[allow(dead_code)]
1632#[derive(Debug, Clone, Default)]
1633pub struct AgdaX2ConstFolder {
1634 pub(super) folds: usize,
1635 pub(super) failures: usize,
1636 pub(super) enabled: bool,
1637}
1638impl AgdaX2ConstFolder {
1639 #[allow(dead_code)]
1640 pub fn new() -> Self {
1641 Self {
1642 folds: 0,
1643 failures: 0,
1644 enabled: true,
1645 }
1646 }
1647 #[allow(dead_code)]
1648 pub fn add_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1649 self.folds += 1;
1650 a.checked_add(b)
1651 }
1652 #[allow(dead_code)]
1653 pub fn sub_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1654 self.folds += 1;
1655 a.checked_sub(b)
1656 }
1657 #[allow(dead_code)]
1658 pub fn mul_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1659 self.folds += 1;
1660 a.checked_mul(b)
1661 }
1662 #[allow(dead_code)]
1663 pub fn div_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1664 if b == 0 {
1665 self.failures += 1;
1666 None
1667 } else {
1668 self.folds += 1;
1669 a.checked_div(b)
1670 }
1671 }
1672 #[allow(dead_code)]
1673 pub fn rem_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1674 if b == 0 {
1675 self.failures += 1;
1676 None
1677 } else {
1678 self.folds += 1;
1679 a.checked_rem(b)
1680 }
1681 }
1682 #[allow(dead_code)]
1683 pub fn neg_i64(&mut self, a: i64) -> Option<i64> {
1684 self.folds += 1;
1685 a.checked_neg()
1686 }
1687 #[allow(dead_code)]
1688 pub fn shl_i64(&mut self, a: i64, s: u32) -> Option<i64> {
1689 if s >= 64 {
1690 self.failures += 1;
1691 None
1692 } else {
1693 self.folds += 1;
1694 a.checked_shl(s)
1695 }
1696 }
1697 #[allow(dead_code)]
1698 pub fn shr_i64(&mut self, a: i64, s: u32) -> Option<i64> {
1699 if s >= 64 {
1700 self.failures += 1;
1701 None
1702 } else {
1703 self.folds += 1;
1704 a.checked_shr(s)
1705 }
1706 }
1707 #[allow(dead_code)]
1708 pub fn and_i64(&mut self, a: i64, b: i64) -> i64 {
1709 self.folds += 1;
1710 a & b
1711 }
1712 #[allow(dead_code)]
1713 pub fn or_i64(&mut self, a: i64, b: i64) -> i64 {
1714 self.folds += 1;
1715 a | b
1716 }
1717 #[allow(dead_code)]
1718 pub fn xor_i64(&mut self, a: i64, b: i64) -> i64 {
1719 self.folds += 1;
1720 a ^ b
1721 }
1722 #[allow(dead_code)]
1723 pub fn not_i64(&mut self, a: i64) -> i64 {
1724 self.folds += 1;
1725 !a
1726 }
1727 #[allow(dead_code)]
1728 pub fn fold_count(&self) -> usize {
1729 self.folds
1730 }
1731 #[allow(dead_code)]
1732 pub fn failure_count(&self) -> usize {
1733 self.failures
1734 }
1735 #[allow(dead_code)]
1736 pub fn enable(&mut self) {
1737 self.enabled = true;
1738 }
1739 #[allow(dead_code)]
1740 pub fn disable(&mut self) {
1741 self.enabled = false;
1742 }
1743 #[allow(dead_code)]
1744 pub fn is_enabled(&self) -> bool {
1745 self.enabled
1746 }
1747}
1748#[allow(dead_code)]
1750#[derive(Debug, Clone)]
1751pub struct AgdaX2DepGraph {
1752 pub(super) n: usize,
1753 pub(super) adj: Vec<Vec<usize>>,
1754 pub(super) rev: Vec<Vec<usize>>,
1755 pub(super) edge_count: usize,
1756}
1757impl AgdaX2DepGraph {
1758 #[allow(dead_code)]
1759 pub fn new(n: usize) -> Self {
1760 Self {
1761 n,
1762 adj: vec![Vec::new(); n],
1763 rev: vec![Vec::new(); n],
1764 edge_count: 0,
1765 }
1766 }
1767 #[allow(dead_code)]
1768 pub fn add_edge(&mut self, from: usize, to: usize) {
1769 if from < self.n && to < self.n {
1770 if !self.adj[from].contains(&to) {
1771 self.adj[from].push(to);
1772 self.rev[to].push(from);
1773 self.edge_count += 1;
1774 }
1775 }
1776 }
1777 #[allow(dead_code)]
1778 pub fn succs(&self, n: usize) -> &[usize] {
1779 self.adj.get(n).map(|v| v.as_slice()).unwrap_or(&[])
1780 }
1781 #[allow(dead_code)]
1782 pub fn preds(&self, n: usize) -> &[usize] {
1783 self.rev.get(n).map(|v| v.as_slice()).unwrap_or(&[])
1784 }
1785 #[allow(dead_code)]
1786 pub fn topo_sort(&self) -> Option<Vec<usize>> {
1787 let mut deg: Vec<usize> = (0..self.n).map(|i| self.rev[i].len()).collect();
1788 let mut q: std::collections::VecDeque<usize> =
1789 (0..self.n).filter(|&i| deg[i] == 0).collect();
1790 let mut out = Vec::with_capacity(self.n);
1791 while let Some(u) = q.pop_front() {
1792 out.push(u);
1793 for &v in &self.adj[u] {
1794 deg[v] -= 1;
1795 if deg[v] == 0 {
1796 q.push_back(v);
1797 }
1798 }
1799 }
1800 if out.len() == self.n {
1801 Some(out)
1802 } else {
1803 None
1804 }
1805 }
1806 #[allow(dead_code)]
1807 pub fn has_cycle(&self) -> bool {
1808 self.topo_sort().is_none()
1809 }
1810 #[allow(dead_code)]
1811 pub fn reachable(&self, start: usize) -> Vec<usize> {
1812 let mut vis = vec![false; self.n];
1813 let mut stk = vec![start];
1814 let mut out = Vec::new();
1815 while let Some(u) = stk.pop() {
1816 if u < self.n && !vis[u] {
1817 vis[u] = true;
1818 out.push(u);
1819 for &v in &self.adj[u] {
1820 if !vis[v] {
1821 stk.push(v);
1822 }
1823 }
1824 }
1825 }
1826 out
1827 }
1828 #[allow(dead_code)]
1829 pub fn scc(&self) -> Vec<Vec<usize>> {
1830 let mut visited = vec![false; self.n];
1831 let mut order = Vec::new();
1832 for i in 0..self.n {
1833 if !visited[i] {
1834 let mut stk = vec![(i, 0usize)];
1835 while let Some((u, idx)) = stk.last_mut() {
1836 if !visited[*u] {
1837 visited[*u] = true;
1838 }
1839 if *idx < self.adj[*u].len() {
1840 let v = self.adj[*u][*idx];
1841 *idx += 1;
1842 if !visited[v] {
1843 stk.push((v, 0));
1844 }
1845 } else {
1846 order.push(*u);
1847 stk.pop();
1848 }
1849 }
1850 }
1851 }
1852 let mut comp = vec![usize::MAX; self.n];
1853 let mut components: Vec<Vec<usize>> = Vec::new();
1854 for &start in order.iter().rev() {
1855 if comp[start] == usize::MAX {
1856 let cid = components.len();
1857 let mut component = Vec::new();
1858 let mut stk = vec![start];
1859 while let Some(u) = stk.pop() {
1860 if comp[u] == usize::MAX {
1861 comp[u] = cid;
1862 component.push(u);
1863 for &v in &self.rev[u] {
1864 if comp[v] == usize::MAX {
1865 stk.push(v);
1866 }
1867 }
1868 }
1869 }
1870 components.push(component);
1871 }
1872 }
1873 components
1874 }
1875 #[allow(dead_code)]
1876 pub fn node_count(&self) -> usize {
1877 self.n
1878 }
1879 #[allow(dead_code)]
1880 pub fn edge_count(&self) -> usize {
1881 self.edge_count
1882 }
1883}
1884#[allow(dead_code)]
1886#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1887pub enum AgdaX2PassPhase {
1888 Early,
1889 Middle,
1890 Late,
1891 Finalize,
1892}
1893impl AgdaX2PassPhase {
1894 #[allow(dead_code)]
1895 pub fn is_early(&self) -> bool {
1896 matches!(self, Self::Early)
1897 }
1898 #[allow(dead_code)]
1899 pub fn is_middle(&self) -> bool {
1900 matches!(self, Self::Middle)
1901 }
1902 #[allow(dead_code)]
1903 pub fn is_late(&self) -> bool {
1904 matches!(self, Self::Late)
1905 }
1906 #[allow(dead_code)]
1907 pub fn is_finalize(&self) -> bool {
1908 matches!(self, Self::Finalize)
1909 }
1910 #[allow(dead_code)]
1911 pub fn order(&self) -> u32 {
1912 match self {
1913 Self::Early => 0,
1914 Self::Middle => 1,
1915 Self::Late => 2,
1916 Self::Finalize => 3,
1917 }
1918 }
1919 #[allow(dead_code)]
1920 pub fn from_order(n: u32) -> Option<Self> {
1921 match n {
1922 0 => Some(Self::Early),
1923 1 => Some(Self::Middle),
1924 2 => Some(Self::Late),
1925 3 => Some(Self::Finalize),
1926 _ => None,
1927 }
1928 }
1929}
1930#[allow(dead_code)]
1932#[derive(Debug)]
1933pub struct AgdaExtCache {
1934 pub(super) entries: Vec<(u64, Vec<u8>, bool, u32)>,
1935 pub(super) cap: usize,
1936 pub(super) total_hits: u64,
1937 pub(super) total_misses: u64,
1938}
1939impl AgdaExtCache {
1940 #[allow(dead_code)]
1941 pub fn new(cap: usize) -> Self {
1942 Self {
1943 entries: Vec::new(),
1944 cap,
1945 total_hits: 0,
1946 total_misses: 0,
1947 }
1948 }
1949 #[allow(dead_code)]
1950 pub fn get(&mut self, key: u64) -> Option<&[u8]> {
1951 for e in self.entries.iter_mut() {
1952 if e.0 == key && e.2 {
1953 e.3 += 1;
1954 self.total_hits += 1;
1955 return Some(&e.1);
1956 }
1957 }
1958 self.total_misses += 1;
1959 None
1960 }
1961 #[allow(dead_code)]
1962 pub fn put(&mut self, key: u64, data: Vec<u8>) {
1963 if self.entries.len() >= self.cap {
1964 self.entries.retain(|e| e.2);
1965 if self.entries.len() >= self.cap {
1966 self.entries.remove(0);
1967 }
1968 }
1969 self.entries.push((key, data, true, 0));
1970 }
1971 #[allow(dead_code)]
1972 pub fn invalidate(&mut self) {
1973 for e in self.entries.iter_mut() {
1974 e.2 = false;
1975 }
1976 }
1977 #[allow(dead_code)]
1978 pub fn hit_rate(&self) -> f64 {
1979 let t = self.total_hits + self.total_misses;
1980 if t == 0 {
1981 0.0
1982 } else {
1983 self.total_hits as f64 / t as f64
1984 }
1985 }
1986 #[allow(dead_code)]
1987 pub fn live_count(&self) -> usize {
1988 self.entries.iter().filter(|e| e.2).count()
1989 }
1990}
1991#[allow(dead_code)]
1993#[derive(Debug, Clone, Default)]
1994pub struct AgdaExtLiveness {
1995 pub live_in: Vec<Vec<usize>>,
1996 pub live_out: Vec<Vec<usize>>,
1997 pub defs: Vec<Vec<usize>>,
1998 pub uses: Vec<Vec<usize>>,
1999}
2000impl AgdaExtLiveness {
2001 #[allow(dead_code)]
2002 pub fn new(n: usize) -> Self {
2003 Self {
2004 live_in: vec![Vec::new(); n],
2005 live_out: vec![Vec::new(); n],
2006 defs: vec![Vec::new(); n],
2007 uses: vec![Vec::new(); n],
2008 }
2009 }
2010 #[allow(dead_code)]
2011 pub fn live_in(&self, b: usize, v: usize) -> bool {
2012 self.live_in.get(b).map(|s| s.contains(&v)).unwrap_or(false)
2013 }
2014 #[allow(dead_code)]
2015 pub fn live_out(&self, b: usize, v: usize) -> bool {
2016 self.live_out
2017 .get(b)
2018 .map(|s| s.contains(&v))
2019 .unwrap_or(false)
2020 }
2021 #[allow(dead_code)]
2022 pub fn add_def(&mut self, b: usize, v: usize) {
2023 if let Some(s) = self.defs.get_mut(b) {
2024 if !s.contains(&v) {
2025 s.push(v);
2026 }
2027 }
2028 }
2029 #[allow(dead_code)]
2030 pub fn add_use(&mut self, b: usize, v: usize) {
2031 if let Some(s) = self.uses.get_mut(b) {
2032 if !s.contains(&v) {
2033 s.push(v);
2034 }
2035 }
2036 }
2037 #[allow(dead_code)]
2038 pub fn var_is_used_in_block(&self, b: usize, v: usize) -> bool {
2039 self.uses.get(b).map(|s| s.contains(&v)).unwrap_or(false)
2040 }
2041 #[allow(dead_code)]
2042 pub fn var_is_def_in_block(&self, b: usize, v: usize) -> bool {
2043 self.defs.get(b).map(|s| s.contains(&v)).unwrap_or(false)
2044 }
2045}
2046#[allow(dead_code)]
2048#[derive(Debug, Clone)]
2049pub struct AgdaX2Worklist {
2050 pub(super) items: std::collections::VecDeque<usize>,
2051 pub(super) present: Vec<bool>,
2052}
2053impl AgdaX2Worklist {
2054 #[allow(dead_code)]
2055 pub fn new(capacity: usize) -> Self {
2056 Self {
2057 items: std::collections::VecDeque::new(),
2058 present: vec![false; capacity],
2059 }
2060 }
2061 #[allow(dead_code)]
2062 pub fn push(&mut self, id: usize) {
2063 if id < self.present.len() && !self.present[id] {
2064 self.present[id] = true;
2065 self.items.push_back(id);
2066 }
2067 }
2068 #[allow(dead_code)]
2069 pub fn push_front(&mut self, id: usize) {
2070 if id < self.present.len() && !self.present[id] {
2071 self.present[id] = true;
2072 self.items.push_front(id);
2073 }
2074 }
2075 #[allow(dead_code)]
2076 pub fn pop(&mut self) -> Option<usize> {
2077 let id = self.items.pop_front()?;
2078 if id < self.present.len() {
2079 self.present[id] = false;
2080 }
2081 Some(id)
2082 }
2083 #[allow(dead_code)]
2084 pub fn is_empty(&self) -> bool {
2085 self.items.is_empty()
2086 }
2087 #[allow(dead_code)]
2088 pub fn len(&self) -> usize {
2089 self.items.len()
2090 }
2091 #[allow(dead_code)]
2092 pub fn contains(&self, id: usize) -> bool {
2093 id < self.present.len() && self.present[id]
2094 }
2095 #[allow(dead_code)]
2096 pub fn drain_all(&mut self) -> Vec<usize> {
2097 let v: Vec<usize> = self.items.drain(..).collect();
2098 for &id in &v {
2099 if id < self.present.len() {
2100 self.present[id] = false;
2101 }
2102 }
2103 v
2104 }
2105}
2106#[allow(dead_code)]
2108#[derive(Debug, Clone, Default)]
2109pub struct AgdaX2Liveness {
2110 pub live_in: Vec<Vec<usize>>,
2111 pub live_out: Vec<Vec<usize>>,
2112 pub defs: Vec<Vec<usize>>,
2113 pub uses: Vec<Vec<usize>>,
2114}
2115impl AgdaX2Liveness {
2116 #[allow(dead_code)]
2117 pub fn new(n: usize) -> Self {
2118 Self {
2119 live_in: vec![Vec::new(); n],
2120 live_out: vec![Vec::new(); n],
2121 defs: vec![Vec::new(); n],
2122 uses: vec![Vec::new(); n],
2123 }
2124 }
2125 #[allow(dead_code)]
2126 pub fn live_in(&self, b: usize, v: usize) -> bool {
2127 self.live_in.get(b).map(|s| s.contains(&v)).unwrap_or(false)
2128 }
2129 #[allow(dead_code)]
2130 pub fn live_out(&self, b: usize, v: usize) -> bool {
2131 self.live_out
2132 .get(b)
2133 .map(|s| s.contains(&v))
2134 .unwrap_or(false)
2135 }
2136 #[allow(dead_code)]
2137 pub fn add_def(&mut self, b: usize, v: usize) {
2138 if let Some(s) = self.defs.get_mut(b) {
2139 if !s.contains(&v) {
2140 s.push(v);
2141 }
2142 }
2143 }
2144 #[allow(dead_code)]
2145 pub fn add_use(&mut self, b: usize, v: usize) {
2146 if let Some(s) = self.uses.get_mut(b) {
2147 if !s.contains(&v) {
2148 s.push(v);
2149 }
2150 }
2151 }
2152 #[allow(dead_code)]
2153 pub fn var_is_used_in_block(&self, b: usize, v: usize) -> bool {
2154 self.uses.get(b).map(|s| s.contains(&v)).unwrap_or(false)
2155 }
2156 #[allow(dead_code)]
2157 pub fn var_is_def_in_block(&self, b: usize, v: usize) -> bool {
2158 self.defs.get(b).map(|s| s.contains(&v)).unwrap_or(false)
2159 }
2160}
2161#[derive(Debug, Clone)]
2163pub struct AgdaModule {
2164 pub module_name: String,
2166 pub params: Vec<(String, AgdaExpr)>,
2168 pub imports: Vec<String>,
2170 pub opens: Vec<String>,
2172 pub declarations: Vec<AgdaDecl>,
2174}
2175impl AgdaModule {
2176 pub fn new(module_name: impl Into<String>) -> Self {
2178 Self {
2179 module_name: module_name.into(),
2180 params: Vec::new(),
2181 imports: Vec::new(),
2182 opens: Vec::new(),
2183 declarations: Vec::new(),
2184 }
2185 }
2186 pub fn import(&mut self, module: impl Into<String>) {
2188 self.imports.push(module.into());
2189 }
2190 pub fn open(&mut self, module: impl Into<String>) {
2192 self.opens.push(module.into());
2193 }
2194 pub fn add(&mut self, decl: AgdaDecl) {
2196 self.declarations.push(decl);
2197 }
2198 pub fn emit(&self) -> String {
2200 let mut out = "-- Generated by OxiLean\n".to_string();
2201 let ps = emit_agda_params(&self.params, 0);
2202 if ps.is_empty() {
2203 out.push_str(&format!("module {} where\n\n", self.module_name));
2204 } else {
2205 out.push_str(&format!("module {} {} where\n\n", self.module_name, ps));
2206 }
2207 for imp in &self.imports {
2208 out.push_str(&format!("import {}\n", imp));
2209 }
2210 if !self.imports.is_empty() {
2211 out.push('\n');
2212 }
2213 for op in &self.opens {
2214 out.push_str(&format!("open {}\n", op));
2215 }
2216 if !self.opens.is_empty() {
2217 out.push('\n');
2218 }
2219 for decl in &self.declarations {
2220 out.push_str(&decl.emit(0));
2221 out.push('\n');
2222 }
2223 out
2224 }
2225}
2226#[allow(dead_code)]
2228#[derive(Debug, Default)]
2229pub struct AgdaX2PassRegistry {
2230 pub(super) configs: Vec<AgdaX2PassConfig>,
2231 pub(super) stats: Vec<AgdaX2PassStats>,
2232}
2233impl AgdaX2PassRegistry {
2234 #[allow(dead_code)]
2235 pub fn new() -> Self {
2236 Self::default()
2237 }
2238 #[allow(dead_code)]
2239 pub fn register(&mut self, c: AgdaX2PassConfig) {
2240 self.stats.push(AgdaX2PassStats::new());
2241 self.configs.push(c);
2242 }
2243 #[allow(dead_code)]
2244 pub fn len(&self) -> usize {
2245 self.configs.len()
2246 }
2247 #[allow(dead_code)]
2248 pub fn is_empty(&self) -> bool {
2249 self.configs.is_empty()
2250 }
2251 #[allow(dead_code)]
2252 pub fn get(&self, i: usize) -> Option<&AgdaX2PassConfig> {
2253 self.configs.get(i)
2254 }
2255 #[allow(dead_code)]
2256 pub fn get_stats(&self, i: usize) -> Option<&AgdaX2PassStats> {
2257 self.stats.get(i)
2258 }
2259 #[allow(dead_code)]
2260 pub fn enabled_passes(&self) -> Vec<&AgdaX2PassConfig> {
2261 self.configs.iter().filter(|c| c.enabled).collect()
2262 }
2263 #[allow(dead_code)]
2264 pub fn passes_in_phase(&self, ph: &AgdaX2PassPhase) -> Vec<&AgdaX2PassConfig> {
2265 self.configs
2266 .iter()
2267 .filter(|c| c.enabled && &c.phase == ph)
2268 .collect()
2269 }
2270 #[allow(dead_code)]
2271 pub fn total_nodes_visited(&self) -> usize {
2272 self.stats.iter().map(|s| s.nodes_visited).sum()
2273 }
2274 #[allow(dead_code)]
2275 pub fn any_changed(&self) -> bool {
2276 self.stats.iter().any(|s| s.changed)
2277 }
2278}
2279#[derive(Debug, Clone, PartialEq)]
2281pub struct AgdaData {
2282 pub name: String,
2284 pub params: Vec<(String, AgdaExpr)>,
2286 pub indices: AgdaExpr,
2288 pub constructors: Vec<AgdaConstructor>,
2290}
2291#[allow(dead_code)]
2292#[derive(Debug, Clone)]
2293pub struct AgdaWorklist {
2294 pub(super) items: std::collections::VecDeque<u32>,
2295 pub(super) in_worklist: std::collections::HashSet<u32>,
2296}
2297impl AgdaWorklist {
2298 #[allow(dead_code)]
2299 pub fn new() -> Self {
2300 AgdaWorklist {
2301 items: std::collections::VecDeque::new(),
2302 in_worklist: std::collections::HashSet::new(),
2303 }
2304 }
2305 #[allow(dead_code)]
2306 pub fn push(&mut self, item: u32) -> bool {
2307 if self.in_worklist.insert(item) {
2308 self.items.push_back(item);
2309 true
2310 } else {
2311 false
2312 }
2313 }
2314 #[allow(dead_code)]
2315 pub fn pop(&mut self) -> Option<u32> {
2316 let item = self.items.pop_front()?;
2317 self.in_worklist.remove(&item);
2318 Some(item)
2319 }
2320 #[allow(dead_code)]
2321 pub fn is_empty(&self) -> bool {
2322 self.items.is_empty()
2323 }
2324 #[allow(dead_code)]
2325 pub fn len(&self) -> usize {
2326 self.items.len()
2327 }
2328 #[allow(dead_code)]
2329 pub fn contains(&self, item: u32) -> bool {
2330 self.in_worklist.contains(&item)
2331 }
2332}
2333#[allow(dead_code)]
2334pub struct AgdaConstantFoldingHelper;
2335impl AgdaConstantFoldingHelper {
2336 #[allow(dead_code)]
2337 pub fn fold_add_i64(a: i64, b: i64) -> Option<i64> {
2338 a.checked_add(b)
2339 }
2340 #[allow(dead_code)]
2341 pub fn fold_sub_i64(a: i64, b: i64) -> Option<i64> {
2342 a.checked_sub(b)
2343 }
2344 #[allow(dead_code)]
2345 pub fn fold_mul_i64(a: i64, b: i64) -> Option<i64> {
2346 a.checked_mul(b)
2347 }
2348 #[allow(dead_code)]
2349 pub fn fold_div_i64(a: i64, b: i64) -> Option<i64> {
2350 if b == 0 {
2351 None
2352 } else {
2353 a.checked_div(b)
2354 }
2355 }
2356 #[allow(dead_code)]
2357 pub fn fold_add_f64(a: f64, b: f64) -> f64 {
2358 a + b
2359 }
2360 #[allow(dead_code)]
2361 pub fn fold_mul_f64(a: f64, b: f64) -> f64 {
2362 a * b
2363 }
2364 #[allow(dead_code)]
2365 pub fn fold_neg_i64(a: i64) -> Option<i64> {
2366 a.checked_neg()
2367 }
2368 #[allow(dead_code)]
2369 pub fn fold_not_bool(a: bool) -> bool {
2370 !a
2371 }
2372 #[allow(dead_code)]
2373 pub fn fold_and_bool(a: bool, b: bool) -> bool {
2374 a && b
2375 }
2376 #[allow(dead_code)]
2377 pub fn fold_or_bool(a: bool, b: bool) -> bool {
2378 a || b
2379 }
2380 #[allow(dead_code)]
2381 pub fn fold_shl_i64(a: i64, b: u32) -> Option<i64> {
2382 a.checked_shl(b)
2383 }
2384 #[allow(dead_code)]
2385 pub fn fold_shr_i64(a: i64, b: u32) -> Option<i64> {
2386 a.checked_shr(b)
2387 }
2388 #[allow(dead_code)]
2389 pub fn fold_rem_i64(a: i64, b: i64) -> Option<i64> {
2390 if b == 0 {
2391 None
2392 } else {
2393 Some(a % b)
2394 }
2395 }
2396 #[allow(dead_code)]
2397 pub fn fold_bitand_i64(a: i64, b: i64) -> i64 {
2398 a & b
2399 }
2400 #[allow(dead_code)]
2401 pub fn fold_bitor_i64(a: i64, b: i64) -> i64 {
2402 a | b
2403 }
2404 #[allow(dead_code)]
2405 pub fn fold_bitxor_i64(a: i64, b: i64) -> i64 {
2406 a ^ b
2407 }
2408 #[allow(dead_code)]
2409 pub fn fold_bitnot_i64(a: i64) -> i64 {
2410 !a
2411 }
2412}