logicaffeine_compile/extraction/
collector.rs1use crate::kernel::{Context, Term};
6use std::collections::{HashMap, HashSet};
7
8pub fn is_extractable(ctx: &Context, name: &str) -> bool {
14 extractable(ctx, name, &mut HashMap::new())
15}
16
17fn extractable(ctx: &Context, name: &str, memo: &mut HashMap<String, bool>) -> bool {
18 if name == "_" {
21 return true;
22 }
23 if let Some(&b) = memo.get(name) {
24 return b;
25 }
26 memo.insert(name.to_string(), true);
28 let result = if ctx.is_constructor(name) {
29 ctx.constructor_inductive(name)
30 .map(|ind| !ctx.get_constructors(ind).is_empty())
31 .unwrap_or(false)
32 } else if ctx.is_inductive(name) {
33 (!ctx.get_constructors(name).is_empty() && !is_logical_type(name)) || is_mapped_primitive(name)
34 } else if let Some(body) = ctx.get_definition_body(name) {
35 let mut refs = Vec::new();
36 collect_globals(body, &mut refs);
37 refs.iter().all(|g| extractable(ctx, g, memo))
38 && matches_inferable(ctx, body)
39 && super::codegen::arith_uses_well_formed(body)
42 } else {
43 is_mapped_primitive(name) || super::codegen::arith_operator(name).is_some()
48 };
49 memo.insert(name.to_string(), result);
50 result
51}
52
53fn matches_inferable(ctx: &Context, term: &Term) -> bool {
58 match term {
59 Term::Match { discriminant, motive, cases } => {
60 if motive_inductive(ctx, motive)
61 .or_else(|| disc_inductive(ctx, discriminant))
62 .is_none()
63 {
64 return false;
65 }
66 matches_inferable(ctx, discriminant)
67 && matches_inferable(ctx, motive)
68 && cases.iter().all(|c| matches_inferable(ctx, c))
69 }
70 Term::Lambda { param_type, body, .. } => {
71 matches_inferable(ctx, param_type) && matches_inferable(ctx, body)
72 }
73 Term::Pi { param_type, body_type, .. } => {
74 matches_inferable(ctx, param_type) && matches_inferable(ctx, body_type)
75 }
76 Term::App(f, a) => matches_inferable(ctx, f) && matches_inferable(ctx, a),
77 Term::Fix { body, .. } => matches_inferable(ctx, body),
78 _ => true,
79 }
80}
81
82fn motive_inductive(ctx: &Context, motive: &Term) -> Option<String> {
83 if let Term::Lambda { param_type, .. } = motive {
84 if let Term::Global(name) = param_type.as_ref() {
85 if ctx.is_inductive(name) {
86 return Some(name.clone());
87 }
88 }
89 }
90 None
91}
92
93fn disc_inductive(ctx: &Context, term: &Term) -> Option<String> {
94 match term {
95 Term::Global(name) => {
96 if ctx.is_constructor(name) {
97 ctx.constructor_inductive(name).map(|s| s.to_string())
98 } else if ctx.is_inductive(name) {
99 Some(name.clone())
100 } else {
101 None
102 }
103 }
104 Term::App(f, _) => disc_inductive(ctx, f),
105 _ => None,
106 }
107}
108
109fn is_mapped_primitive(name: &str) -> bool {
110 matches!(
111 name,
112 "Int" | "Float" | "Text" | "Bool" | "Duration" | "Date" | "Moment"
113 )
114}
115
116pub fn is_logical_type(name: &str) -> bool {
121 matches!(
122 name,
123 "Syntax" | "Derivation" | "Eq" | "And" | "Or" | "Iff" | "Ex" | "Not"
124 | "True" | "False" | "Entity" | "Univ" | "Prop"
125 )
126}
127
128pub fn collect_dependencies(ctx: &Context, entry: &str) -> HashSet<String> {
133 let mut visited = HashSet::new();
134 let mut to_visit = vec![entry.to_string()];
135
136 while let Some(name) = to_visit.pop() {
137 if visited.contains(&name) {
138 continue;
139 }
140 visited.insert(name.clone());
141
142 if let Some(body) = ctx.get_definition_body(&name) {
144 collect_globals(body, &mut to_visit);
145 if let Some(ty) = ctx.get_definition_type(&name) {
147 collect_globals(ty, &mut to_visit);
148 }
149 }
150
151 if ctx.is_inductive(&name) {
152 for (ctor_name, ctor_ty) in ctx.get_constructors(&name) {
154 collect_globals(ctor_ty, &mut to_visit);
155 to_visit.push(ctor_name.to_string());
156 }
157 }
158
159 if ctx.is_constructor(&name) {
160 if let Some(ind) = ctx.constructor_inductive(&name) {
162 to_visit.push(ind.to_string());
163 }
164 }
165 }
166
167 visited
168}
169
170pub(crate) fn collect_globals(term: &Term, deps: &mut Vec<String>) {
172 match term {
173 Term::Global(name) => deps.push(name.clone()),
174 Term::Const { name, .. } => deps.push(name.clone()),
175 Term::App(f, a) => {
176 collect_globals(f, deps);
177 collect_globals(a, deps);
178 }
179 Term::Lambda {
180 param_type, body, ..
181 } => {
182 collect_globals(param_type, deps);
183 collect_globals(body, deps);
184 }
185 Term::Pi {
186 param_type,
187 body_type,
188 ..
189 } => {
190 collect_globals(param_type, deps);
191 collect_globals(body_type, deps);
192 }
193 Term::Fix { body, .. } => collect_globals(body, deps),
194 Term::Match {
195 discriminant,
196 motive,
197 cases,
198 } => {
199 collect_globals(discriminant, deps);
200 collect_globals(motive, deps);
201 for case in cases {
202 collect_globals(case, deps);
203 }
204 }
205 Term::Let {
206 ty, value, body, ..
207 } => {
208 collect_globals(ty, deps);
209 collect_globals(value, deps);
210 collect_globals(body, deps);
211 }
212 Term::MutualFix { defs, .. } => {
213 for (_, body) in defs {
214 collect_globals(body, deps);
215 }
216 }
217 Term::Sort(_) | Term::Var(_) | Term::Lit(_) | Term::Hole => {}
219 }
220}