1use std::collections::BTreeMap;
2
3use voile_util::loc::*;
4use voile_util::meta::MI;
5use voile_util::tags::{PiSig::*, *};
6use voile_util::uid::*;
7
8use crate::check::monad::{TCE, TCM};
9use crate::syntax::surf::{Decl, DeclKind, Expr, Param};
10
11use super::ast::*;
12
13type GlobCtx = BTreeMap<String, GI>;
15
16type LocalCtx = BTreeMap<String, (DBI, Plicit)>;
18
19pub fn trans_decls(decls: Vec<Decl>) -> TCM<Vec<AbsDecl>> {
20 trans_decls_contextual(Default::default(), decls).map(|tcs| tcs.decls)
21}
22
23pub fn trans_decls_contextual(tcs: TransState, decls: Vec<Decl>) -> TCM<TransState> {
24 decls.into_iter().try_fold(tcs, trans_one_decl)
25}
26
27#[derive(Debug, Clone, Default)]
29pub struct TransState {
30 pub decls: Vec<AbsDecl>,
31 pub signature_indices: Vec<DBI>,
35 pub context_mapping: GlobCtx,
36 pub decl_count: GI,
37 pub meta_count: MI,
38}
39
40fn trans_one_decl(mut tcs: TransState, decl: Decl) -> TCM<TransState> {
41 let abs = trans_expr(
42 decl.body,
43 &tcs.decls,
44 &mut tcs.meta_count,
45 &tcs.context_mapping,
46 )?;
47
48 let decl_total = tcs.decl_count;
49 let dbi = *tcs
50 .context_mapping
51 .entry(decl.name.text.clone())
52 .or_insert_with(|| decl_total);
53 let original = if decl_total > dbi {
54 Some(&tcs.decls[tcs.signature_indices[dbi.0].0])
55 } else {
56 None
57 };
58 let modified = match (decl.kind, original) {
59 (DeclKind::Sign, None) => {
60 let abs = AbsDecl::Sign(abs, tcs.decl_count);
61 tcs.signature_indices.push(DBI(tcs.decls.len()));
62 tcs.decl_count += 1;
63 abs
64 }
65 (DeclKind::Sign, Some(thing)) => {
67 return Err(TCE::ReDefine(decl.name.loc, thing.loc()));
68 }
69 (_, Some(AbsDecl::Impl(thing, ..))) | (_, Some(AbsDecl::Decl(thing))) => {
71 return Err(TCE::ReDefine(decl.name.loc, thing.loc()));
72 }
73 (DeclKind::Impl, None) => {
74 tcs.decl_count += 1;
75 tcs.signature_indices.push(DBI(tcs.decls.len()));
76 AbsDecl::Decl(abs)
77 }
78 (DeclKind::Impl, Some(AbsDecl::Sign(_, dbi))) => AbsDecl::Impl(abs, *dbi),
79 };
80 tcs.decls.push(modified);
81 Ok(tcs)
82}
83
84pub fn trans_expr(expr: Expr, env: &[AbsDecl], meta_count: &mut MI, map: &GlobCtx) -> TCM<Abs> {
85 trans_expr_inner(expr, meta_count, env, map, &[], &Default::default())
86}
87
88fn trans_expr_inner(
89 expr: Expr,
90 meta_count: &mut MI,
91 env: &[AbsDecl],
92 global_map: &GlobCtx,
93 local_env: &[UID],
94 local_map: &LocalCtx,
95) -> TCM<Abs> {
96 let mut recursion =
97 |e: Expr| trans_expr_inner(e, meta_count, env, global_map, local_env, local_map);
98 let map_labels =
99 |Labelled { expr, label }| recursion(expr).map(|expr| Labelled { label, expr });
100 match expr {
101 Expr::Type(syntax, level) => Ok(Abs::Type(syntax, level)),
102 Expr::Var(ident) => {
103 let name = &ident.text;
104 if local_map.contains_key(name) {
105 let (dbi, _) = local_map[name];
106 Ok(Abs::Var(ident.clone(), local_env[dbi.0], dbi))
107 } else if global_map.contains_key(name) {
108 Ok(Abs::Ref(ident.clone(), global_map[name]))
109 } else {
110 Err(TCE::LookUpFailed(ident.clone()))
111 }
112 }
113 Expr::App(app_vec) => Ok(app_vec.try_map(recursion)?.fold1(|result: Abs, abs: Abs| {
114 Abs::app(merge_info(&result, &abs), result, Plicit::Ex, abs)
115 })),
116 Expr::Pipe(pipe_vec) => Ok(pipe_vec
118 .try_map(recursion)?
119 .rev_fold1(|result, abs| Abs::app(merge_info(&result, &abs), result, Plicit::Ex, abs))),
120 Expr::Meta(ident) => {
121 let ret = Ok(Abs::Meta(ident.clone(), *meta_count));
122 *meta_count += 1;
123 ret
124 }
125 Expr::Cons(ident) => Ok(Abs::Cons(ident.clone())),
126 Expr::RowKind(info, kind, labels) => Ok(Abs::RowKind(info, kind, labels)),
128 Expr::Proj(expr, projections) => Ok(projections.fold(recursion(*expr)?, |abs, label| {
129 Abs::proj(merge_info(&abs, &label), abs, label)
130 })),
131 Expr::RowPoly(info, kind, labels, rest) => {
132 let labels: Result<_, _> = labels.into_iter().map(map_labels).collect();
133 let rest = rest.map(|e| recursion(*e)).transpose()?;
134 Ok(Abs::row_polymorphic_type(info, kind, labels?, rest))
135 }
136 Expr::Rec(info, fields, rest) => {
137 let labels: Result<_, _> = fields.into_iter().map(map_labels).collect();
138 let rest = rest.map(|e| recursion(*e)).transpose()?;
139 Ok(Abs::record(info, labels?, rest))
140 }
141 Expr::Tup(tup_vec) => Ok(tup_vec
142 .try_map(recursion)?
143 .fold1(|pair, abs| Abs::pair(abs.loc(), pair, abs))),
144 Expr::Sig(initial, last) => trans_dependent_type(
145 meta_count, env, global_map, local_env, local_map, initial, *last, Sigma,
146 ),
147 Expr::Cases(label, binding, body, or) => {
148 let or = trans_expr_inner(*or, meta_count, env, global_map, local_env, local_map)?;
149 let mut local = local_env.to_vec();
150 local.reserve_exact(local.len() + 1);
151 let mut local_map = local_map.clone();
152 let mut names = Vec::with_capacity(1);
153 introduce_abstractions(&[binding.clone()], &mut local, &mut local_map, &mut names);
154 let body = trans_expr_inner(*body, meta_count, env, global_map, &local, &local_map)?;
155 Ok(Abs::case_or(label, binding, names[0], body, or))
156 }
157 Expr::Whatever(info) => Ok(Abs::Whatever(info)),
158 Expr::Lam(info, params, body) => {
159 let mut local = local_env.to_vec();
160 local.reserve_exact(local.len() + params.len() + 1);
161 let mut local_map = local_map.clone();
162 let mut names = Vec::with_capacity(params.len());
163 introduce_abstractions(¶ms, &mut local, &mut local_map, &mut names);
164 let body = trans_expr_inner(*body, meta_count, env, global_map, &local, &local_map)?;
165 Ok(params.into_iter().rev().fold(body, |lam_abs, param| {
166 let pop_empty = "The stack `names` is empty. Please report this as a bug.";
167 let name = names.pop().expect(pop_empty);
168 Abs::lam(info.clone(), param.clone(), name, lam_abs)
169 }))
170 }
171 Expr::Pi(params, result) => trans_dependent_type(
172 meta_count, env, global_map, local_env, local_map, params, *result, Pi,
173 ),
174 Expr::Lift(info, levels, inner) => Ok(Abs::lift(info, levels, recursion(*inner)?)),
175 }
176}
177
178fn introduce_abstractions(
179 params: &[Ident],
180 local_env: &mut Vec<UID>,
181 local_map: &mut LocalCtx,
182 names: &mut Vec<UID>,
183) {
184 for param in params {
185 let shadowing = local_map.get(¶m.text).cloned().map(|(dbi, _)| dbi);
186 for (_name, (dbi, _)) in local_map.iter_mut() {
187 let dbi_value = *dbi;
188 *dbi += 1;
189 if shadowing == Some(dbi_value) {
190 local_env.remove(dbi_value.0);
191 }
192 }
193 local_map.insert(param.text.clone(), (Default::default(), Plicit::Ex));
194 let new_name = unsafe { next_uid() };
195 local_env.insert(0, new_name);
196 names.push(new_name);
197 }
198}
199
200fn trans_dependent_type(
201 meta_count: &mut MI,
202 env: &[AbsDecl],
203 global_map: &GlobCtx,
204 local_env: &[UID],
205 local_map: &LocalCtx,
206 params: Vec<Param>,
207 result: Expr,
208 kind: PiSig,
209) -> TCM<Abs> {
210 let mut pi_env = local_env.to_vec();
211 let mut pi_map = local_map.clone();
212 let mut names = Vec::with_capacity(params.len());
213 let pi_initial = Vec::with_capacity(params.len());
214 let pi_vec: Vec<(Abs, Plicit)> = params.into_iter().try_fold(pi_initial, |pi_vec, param| {
215 introduce_telescope(
216 meta_count,
217 env,
218 global_map,
219 &mut pi_env,
220 &mut pi_map,
221 &mut names,
222 pi_vec,
223 param,
224 )
225 })?;
226
227 Ok(pi_vec.into_iter().rev().fold(
228 trans_expr_inner(result, meta_count, env, global_map, &pi_env, &pi_map)?,
229 |pi_abs, (param, plicit)| {
230 let info = param.loc() + pi_abs.loc();
231 let pop_empty = "The stack `names` is empty. Please report this as a bug.";
232 Abs::dependent_type(
233 info,
234 kind,
235 names.pop().expect(pop_empty),
236 plicit,
237 param,
238 pi_abs,
239 )
240 },
241 ))
242}
243
244fn introduce_telescope(
245 meta_count: &mut MI,
246 env: &[AbsDecl],
247 global_map: &GlobCtx,
248 dt_env: &mut Vec<UID>,
249 dt_map: &mut LocalCtx,
250 names: &mut Vec<UID>,
251 mut dt_vec: Vec<(Abs, Plicit)>,
252 param: Param,
253) -> TCM<Vec<(Abs, Plicit)>> {
254 let param_ty = trans_expr_inner(param.ty, meta_count, env, global_map, &dt_env, &dt_map)?;
255 for name in ¶m.names {
256 let param_name = name.text.clone();
257 assert_eq!(dt_env.len(), dt_map.len());
259 dt_map.iter_mut().for_each(|(_name, (dbi, _))| *dbi += 1);
261 dt_map.insert(param_name, (Default::default(), param.plicit));
271 let new_name = unsafe { next_uid() };
272 dt_env.insert(0, new_name);
273 names.push(new_name);
274 dt_vec.push((param_ty.clone(), param.plicit));
275 }
276 if param.names.is_empty() {
277 let new_name = unsafe { next_uid() };
278 dt_map.iter_mut().for_each(|(_name, (dbi, _))| *dbi += 1);
279 dt_env.insert(0, new_name);
280 names.push(new_name);
281 dt_vec.push((param_ty, param.plicit));
282 }
283
284 Ok(dt_vec)
285}