1use serde::{Deserialize, Serialize};
7use std::fmt;
8
9pub const RLEAN_NS: &str = "http://github.com/createyourpersonalaccount/rlean-search";
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
14#[serde(rename_all = "lowercase")]
15pub enum DeclKind {
16 Theorem,
17 Lemma,
18 Axiom,
19}
20
21impl DeclKind {
22 pub fn as_str(self) -> &'static str {
23 match self {
24 DeclKind::Theorem => "theorem",
25 DeclKind::Lemma => "lemma",
26 DeclKind::Axiom => "axiom",
27 }
28 }
29
30 pub fn parse(s: &str) -> Option<Self> {
31 match s {
32 "theorem" => Some(DeclKind::Theorem),
33 "lemma" => Some(DeclKind::Lemma),
34 "axiom" => Some(DeclKind::Axiom),
35 _ => None,
36 }
37 }
38}
39
40impl fmt::Display for DeclKind {
41 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42 f.write_str(self.as_str())
43 }
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
48#[serde(rename_all = "lowercase")]
49pub enum BinderKind {
50 Default,
52 Implicit,
54 Instance,
56 StrictImplicit,
58}
59
60#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
62pub struct Binder {
63 pub kind: BinderKind,
64 pub names: Vec<String>,
65 pub ty: Option<Box<TypeExpr>>,
66}
67
68#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
70pub enum TypeExpr {
71 Hole,
73 NamedHole(String),
75 Ident(String),
77 NatLit(String),
79 Literal(String),
81 App(Box<TypeExpr>, Box<TypeExpr>),
83 BinOp {
85 op: String,
86 left: Box<TypeExpr>,
87 right: Box<TypeExpr>,
88 },
89 UnaryOp {
91 op: String,
92 arg: Box<TypeExpr>,
93 },
94 Postfix {
96 arg: Box<TypeExpr>,
97 op: String,
98 },
99 Arrow(Box<TypeExpr>, Box<TypeExpr>),
101 Forall {
103 binders: Vec<Binder>,
104 body: Box<TypeExpr>,
105 },
106 Exists {
108 binders: Vec<Binder>,
109 body: Box<TypeExpr>,
110 },
111 Lambda {
113 binders: Vec<Binder>,
114 body: Box<TypeExpr>,
115 },
116 Pi {
118 binder: Binder,
119 body: Box<TypeExpr>,
120 },
121 Proj {
123 base: Box<TypeExpr>,
124 field: String,
125 },
126 Sort {
128 name: String,
129 level: Option<Box<TypeExpr>>,
130 },
131 Raw(String),
133}
134
135impl TypeExpr {
136 pub fn apps(f: TypeExpr, args: impl IntoIterator<Item = TypeExpr>) -> TypeExpr {
138 args.into_iter()
139 .fold(f, |acc, a| TypeExpr::App(Box::new(acc), Box::new(a)))
140 }
141
142 pub fn idents(&self) -> Vec<&str> {
144 let mut out = Vec::new();
145 self.collect_idents(&mut out);
146 out
147 }
148
149 fn collect_idents<'a>(&'a self, out: &mut Vec<&'a str>) {
150 match self {
151 TypeExpr::Ident(s) => out.push(s),
152 TypeExpr::App(f, a) => {
153 f.collect_idents(out);
154 a.collect_idents(out);
155 }
156 TypeExpr::BinOp { left, right, .. } => {
157 left.collect_idents(out);
158 right.collect_idents(out);
159 }
160 TypeExpr::UnaryOp { arg, .. } | TypeExpr::Postfix { arg, .. } => {
161 arg.collect_idents(out);
162 }
163 TypeExpr::Arrow(a, b) => {
164 a.collect_idents(out);
165 b.collect_idents(out);
166 }
167 TypeExpr::Forall { binders, body }
168 | TypeExpr::Exists { binders, body }
169 | TypeExpr::Lambda { binders, body } => {
170 for b in binders {
171 if let Some(ty) = &b.ty {
172 ty.collect_idents(out);
173 }
174 }
175 body.collect_idents(out);
176 }
177 TypeExpr::Pi { binder, body } => {
178 if let Some(ty) = &binder.ty {
179 ty.collect_idents(out);
180 }
181 body.collect_idents(out);
182 }
183 TypeExpr::Proj { base, .. } => base.collect_idents(out),
184 TypeExpr::Sort { level: Some(l), .. } => l.collect_idents(out),
185 _ => {}
186 }
187 }
188
189 pub fn operators(&self) -> Vec<&str> {
191 let mut out = Vec::new();
192 self.collect_ops(&mut out);
193 out
194 }
195
196 fn collect_ops<'a>(&'a self, out: &mut Vec<&'a str>) {
197 match self {
198 TypeExpr::BinOp { op, left, right } => {
199 out.push(op.as_str());
200 left.collect_ops(out);
201 right.collect_ops(out);
202 }
203 TypeExpr::UnaryOp { op, arg } => {
204 out.push(op.as_str());
205 arg.collect_ops(out);
206 }
207 TypeExpr::Postfix { op, arg } => {
208 out.push(op.as_str());
209 arg.collect_ops(out);
210 }
211 TypeExpr::App(f, a) => {
212 f.collect_ops(out);
213 a.collect_ops(out);
214 }
215 TypeExpr::Arrow(a, b) => {
216 out.push("→");
217 a.collect_ops(out);
218 b.collect_ops(out);
219 }
220 TypeExpr::Forall { binders, body } => {
221 out.push("∀");
222 for b in binders {
223 if let Some(ty) = &b.ty {
224 ty.collect_ops(out);
225 }
226 }
227 body.collect_ops(out);
228 }
229 TypeExpr::Exists { binders, body } => {
230 out.push("∃");
231 for b in binders {
232 if let Some(ty) = &b.ty {
233 ty.collect_ops(out);
234 }
235 }
236 body.collect_ops(out);
237 }
238 TypeExpr::Lambda { binders, body } => {
239 for b in binders {
240 if let Some(ty) = &b.ty {
241 ty.collect_ops(out);
242 }
243 }
244 body.collect_ops(out);
245 }
246 TypeExpr::Pi { binder, body } => {
247 out.push("→");
248 if let Some(ty) = &binder.ty {
249 ty.collect_ops(out);
250 }
251 body.collect_ops(out);
252 }
253 TypeExpr::Proj { base, .. } => base.collect_ops(out),
254 TypeExpr::Sort { level: Some(l), .. } => l.collect_ops(out),
255 _ => {}
256 }
257 }
258
259 pub fn conclusion(&self) -> &TypeExpr {
263 match self {
264 TypeExpr::Forall { body, .. }
265 | TypeExpr::Exists { body, .. }
266 | TypeExpr::Lambda { body, .. }
267 | TypeExpr::Pi { body, .. } => body.conclusion(),
268 TypeExpr::Arrow(_, right) => right.conclusion(),
269 other => other,
270 }
271 }
272
273 pub fn head_key(&self) -> String {
275 match self.conclusion() {
276 TypeExpr::BinOp { op, .. } => format!("op:{op}"),
277 TypeExpr::UnaryOp { op, .. } => format!("uop:{op}"),
278 TypeExpr::Postfix { op, .. } => format!("pop:{op}"),
279 TypeExpr::Ident(s) => format!("id:{s}"),
280 TypeExpr::App(f, _) => match f.as_ref() {
281 TypeExpr::Ident(s) => format!("id:{s}"),
282 TypeExpr::App(ff, _) => match ff.as_ref() {
283 TypeExpr::Ident(s) => format!("id:{s}"),
284 _ => "app".into(),
285 },
286 _ => "app".into(),
287 },
288 TypeExpr::Arrow(_, _) => "op:→".into(),
289 TypeExpr::Forall { .. } => "op:∀".into(),
290 TypeExpr::Exists { .. } => "op:∃".into(),
291 TypeExpr::Sort { name, .. } => format!("sort:{name}"),
292 TypeExpr::NatLit(_) => "lit:nat".into(),
293 TypeExpr::Hole | TypeExpr::NamedHole(_) => "hole".into(),
294 _ => "other".into(),
295 }
296 }
297
298 pub fn surface(&self) -> String {
300 match self {
301 TypeExpr::Hole => "_".into(),
302 TypeExpr::NamedHole(n) => format!("?{n}"),
303 TypeExpr::Ident(s) => s.clone(),
304 TypeExpr::NatLit(n) => n.clone(),
305 TypeExpr::Literal(s) => s.clone(),
306 TypeExpr::App(f, a) => {
307 let fa = f.surface();
308 let aa = match a.as_ref() {
309 TypeExpr::App(_, _)
310 | TypeExpr::BinOp { .. }
311 | TypeExpr::Arrow(_, _)
312 | TypeExpr::Forall { .. }
313 | TypeExpr::Exists { .. }
314 | TypeExpr::Lambda { .. }
315 | TypeExpr::Pi { .. } => format!("({})", a.surface()),
316 _ => a.surface(),
317 };
318 format!("{fa} {aa}")
319 }
320 TypeExpr::BinOp { op, left, right } => {
321 format!("({} {} {})", left.surface(), op, right.surface())
322 }
323 TypeExpr::UnaryOp { op, arg } => format!("{op}{}", arg.surface()),
324 TypeExpr::Postfix { arg, op } => format!("{}{op}", arg.surface()),
325 TypeExpr::Arrow(a, b) => format!("({} → {})", a.surface(), b.surface()),
326 TypeExpr::Forall { binders, body } => {
327 format!("(∀ {}, {})", format_binders(binders), body.surface())
328 }
329 TypeExpr::Exists { binders, body } => {
330 format!("(∃ {}, {})", format_binders(binders), body.surface())
331 }
332 TypeExpr::Lambda { binders, body } => {
333 format!("(fun {} => {})", format_binders(binders), body.surface())
334 }
335 TypeExpr::Pi { binder, body } => {
336 format!("({} → {})", format_binder(binder), body.surface())
337 }
338 TypeExpr::Proj { base, field } => format!("{}.{}", base.surface(), field),
339 TypeExpr::Sort { name, level } => match level {
340 Some(l) => format!("{name} {}", l.surface()),
341 None => name.clone(),
342 },
343 TypeExpr::Raw(s) => s.clone(),
344 }
345 }
346}
347
348fn format_binders(binders: &[Binder]) -> String {
349 binders
350 .iter()
351 .map(format_binder)
352 .collect::<Vec<_>>()
353 .join(" ")
354}
355
356fn format_binder(b: &Binder) -> String {
357 let names = b.names.join(" ");
358 let inner = match &b.ty {
359 Some(ty) => format!("{names} : {}", ty.surface()),
360 None => names,
361 };
362 match b.kind {
363 BinderKind::Default => format!("({inner})"),
364 BinderKind::Implicit => format!("{{{inner}}}"),
365 BinderKind::Instance => format!("[{inner}]"),
366 BinderKind::StrictImplicit => format!("⦃{inner}⦄"),
367 }
368}
369
370#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
372pub struct Declaration {
373 pub kind: DeclKind,
374 pub name: String,
375 pub full_name: String,
377 pub binders: Vec<Binder>,
378 pub ty: TypeExpr,
379 pub type_surface: String,
381 pub file: String,
382 pub line: usize,
383 pub module: Option<String>,
384 pub namespace_path: Vec<String>,
385 pub attributes: Vec<String>,
386}
387
388impl Declaration {
389 pub fn effective_type(&self) -> TypeExpr {
391 if self.binders.is_empty() {
392 return self.ty.clone();
393 }
394 TypeExpr::Forall {
396 binders: self.binders.clone(),
397 body: Box::new(self.ty.clone()),
398 }
399 }
400}
401
402#[derive(Debug, Clone, Serialize, Deserialize)]
404pub struct PackageInfo {
405 pub name: String,
406 pub root: String,
407 pub src_dirs: Vec<String>,
408 pub lean_libs: Vec<String>,
409}
410
411#[derive(Debug, Clone, Default, Serialize, Deserialize)]
413pub struct IndexDocument {
414 pub schema: String,
415 pub created_at: String,
416 pub packages: Vec<PackageInfo>,
417 pub declarations: Vec<Declaration>,
418 pub source_hash: String,
420}
421
422impl IndexDocument {
423 pub fn new() -> Self {
424 Self {
425 schema: RLEAN_NS.to_string(),
426 created_at: chrono::Utc::now().to_rfc3339(),
427 packages: Vec::new(),
428 declarations: Vec::new(),
429 source_hash: String::new(),
430 }
431 }
432}