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