1mod error;
2mod extract_includes;
3mod gen_effect_expr;
4pub use extract_includes::extract_includes;
5
6use std::{
7 cell::RefCell,
8 collections::{HashMap, HashSet},
9};
10
11use ast::span::{Span, Spanned};
12use error::HirGenError;
13use file::{FileId, InFile};
14use hir::{
15 expr::{Expr, Handler, Literal, MatchCase},
16 meta::{Id, Meta, WithMeta},
17 ty::Type,
18};
19
20pub fn gen_hir(
21 file_id: FileId,
22 src: &Spanned<ast::expr::Expr>,
23 included: HashMap<String, InFile<Spanned<ast::expr::Expr>>>,
24) -> Result<(HirGen, WithMeta<Expr>), HirGenError> {
25 let hir = HirGen {
26 file_stack: RefCell::new(vec![file_id]),
27 included,
28 ..Default::default()
29 };
30 hir.gen(src).map(|expr| (hir, expr))
31}
32
33#[derive(Default, Debug)]
34pub struct HirGen {
35 next_id: RefCell<Id>,
36 next_span: RefCell<Vec<Span>>,
37 pub variables: RefCell<HashMap<String, Id>>,
38 pub attrs: RefCell<HashMap<Id, Vec<Expr>>>,
39 pub included: HashMap<String, InFile<Spanned<ast::expr::Expr>>>,
40 pub type_aliases: RefCell<HashMap<String, Type>>,
41 brands: RefCell<HashSet<String>>,
42 file_stack: RefCell<Vec<FileId>>,
44}
45
46impl HirGen {
47 pub fn push_file_id(&self, file_id: FileId) {
48 self.file_stack.borrow_mut().push(file_id);
49 }
50 pub fn pop_file_id(&self) -> FileId {
51 self.file_stack.borrow_mut().pop().unwrap()
52 }
53 pub fn gen_type(&self, ty: &Spanned<ast::ty::Type>) -> Result<WithMeta<Type>, HirGenError> {
54 let (ty, span) = ty;
55 self.push_span(span.clone());
56
57 let with_meta = match ty {
58 ast::ty::Type::Number => self.with_meta(Type::Number),
59 ast::ty::Type::String => self.with_meta(Type::String),
60 ast::ty::Type::Trait(types) => self.with_meta(Type::Trait(
61 types
62 .iter()
63 .map(|ty| self.gen_type(ty))
64 .collect::<Result<_, _>>()?,
65 )),
66 ast::ty::Type::Effectful { ty, effects } => self.with_meta(Type::Effectful {
67 ty: Box::new(self.gen_type(ty)?),
68 effects: self.gen_effect_expr(effects)?,
69 }),
70 ast::ty::Type::Infer => self.with_meta(Type::Infer),
71 ast::ty::Type::This => self.with_meta(Type::This),
72 ast::ty::Type::Alias(ident) | ast::ty::Type::Variable(ident) => self.with_meta(
73 self.type_aliases
74 .borrow()
75 .get(ident)
76 .cloned()
77 .unwrap_or_else(|| Type::Variable(self.get_id_of(ident.clone()))),
78 ),
79 ast::ty::Type::Product(types) => self.with_meta(Type::Product(
80 types
81 .iter()
82 .map(|ty| self.gen_type(ty))
83 .collect::<Result<_, _>>()?,
84 )),
85 ast::ty::Type::Sum(types) => self.with_meta(Type::Sum(
86 types
87 .iter()
88 .map(|ty| self.gen_type(ty))
89 .collect::<Result<_, _>>()?,
90 )),
91 ast::ty::Type::Function { parameters, body } => {
92 let span = self.pop_span().unwrap();
93 parameters
94 .iter()
95 .map(|parameter| self.gen_type(parameter))
96 .collect::<Result<Vec<_>, _>>()?
97 .into_iter()
98 .try_rfold(self.gen_type(body)?, |body, parameter| {
99 self.push_span(span.clone());
100 Ok(self.with_meta(Type::Function {
101 parameter: Box::new(parameter),
102 body: Box::new(body),
103 }))
104 })?
105 }
106 ast::ty::Type::Array(ty) => self.with_meta(Type::Array(Box::new(self.gen_type(ty)?))),
107 ast::ty::Type::Set(ty) => self.with_meta(Type::Set(Box::new(self.gen_type(ty)?))),
108 ast::ty::Type::Let { variable, body } => self.with_meta(Type::Let {
109 variable: self.get_id_of(variable.clone()),
110 body: Box::new(self.gen_type(body)?),
111 }),
112 ast::ty::Type::BoundedVariable { bound, identifier } => {
113 self.with_meta(Type::BoundedVariable {
114 bound: Box::new(self.gen_type(bound)?),
115 identifier: identifier.clone(),
116 })
117 }
118 ast::ty::Type::Brand { brand, item } => {
119 if self.brands.borrow().contains(brand) {
120 self.with_meta(Type::Brand {
121 brand: brand.clone(),
122 item: Box::new(self.gen_type(item)?),
123 })
124 } else {
125 self.with_meta(Type::Label {
126 label: brand.clone(),
127 item: Box::new(self.gen_type(item)?),
128 })
129 }
130 }
131 ast::ty::Type::Attribute { attr, ty } => {
132 self.pop_span();
133 let mut ret = self.gen_type(ty)?;
134 let attr = self.gen(attr)?.value;
135 ret.meta.attrs.push(attr);
136 self.attrs
137 .borrow_mut()
138 .insert(ret.meta.id, ret.meta.attrs.clone());
139 ret
140 }
141 ast::ty::Type::Comment { item, .. } => self.gen_type(item)?,
142 };
143 Ok(with_meta)
144 }
145
146 pub fn gen(&self, ast: &Spanned<ast::expr::Expr>) -> Result<WithMeta<Expr>, HirGenError> {
147 let (expr, span) = ast;
148 self.push_span(span.clone());
149
150 let with_meta = match expr {
151 ast::expr::Expr::Literal(literal) => self.with_meta(Expr::Literal(match literal {
152 ast::expr::Literal::String(value) => Literal::String(value.clone()),
153 ast::expr::Literal::Int(value) => Literal::Int(*value),
154 ast::expr::Literal::Rational(a, b) => Literal::Rational(*a, *b),
155 ast::expr::Literal::Float(value) => Literal::Float(*value),
156 })),
157 ast::expr::Expr::Hole => self.with_meta(Expr::Literal(Literal::Hole)),
158 ast::expr::Expr::Let {
159 ty: variable,
160 definition,
161 body: expression,
162 } => self.with_meta(Expr::Let {
163 ty: self.gen_type(variable)?,
164 definition: Box::new(self.gen(definition)?),
165 expression: Box::new(self.gen(expression)?),
166 }),
167 ast::expr::Expr::Perform { input, output } => self.with_meta(Expr::Perform {
168 input: Box::new(self.gen(input)?),
169 output: self.gen_type(output)?,
170 }),
171 ast::expr::Expr::Continue { input, output } => self.with_meta(Expr::Continue {
172 input: Box::new(self.gen(input)?),
173 output: output
174 .as_ref()
175 .map(|output| self.gen_type(output))
176 .transpose()?,
177 }),
178 ast::expr::Expr::Handle { handlers, expr } => self.with_meta(Expr::Handle {
179 handlers: handlers
180 .iter()
181 .map(
182 |ast::expr::Handler {
183 input,
184 output,
185 handler,
186 }| {
187 Ok(Handler {
188 input: self.gen_type(input)?,
189 output: self.gen_type(output)?,
190 handler: self.gen(handler)?,
191 })
192 },
193 )
194 .collect::<Result<Vec<_>, _>>()?,
195 expr: Box::new(self.gen(expr)?),
196 }),
197 ast::expr::Expr::Apply {
198 function,
199 link_name,
200 arguments,
201 } => self.with_meta(Expr::Apply {
202 function: self.gen_type(function)?,
203 link_name: link_name.clone(),
204 arguments: arguments
205 .iter()
206 .map(|argument| self.gen(argument))
207 .collect::<Result<Vec<_>, _>>()?,
208 }),
209 ast::expr::Expr::Product(items) => self.with_meta(Expr::Product(
210 items
211 .iter()
212 .map(|item| self.gen(item))
213 .collect::<Result<_, _>>()?,
214 )),
215 ast::expr::Expr::Typed { ty, item: expr } => self.with_meta(Expr::Typed {
216 ty: self.gen_type(ty)?,
217 item: Box::new(self.gen(expr)?),
218 }),
219 ast::expr::Expr::Function { parameters, body } => {
220 let span = self.pop_span().unwrap();
221 parameters
222 .iter()
223 .map(|parameter| self.gen_type(parameter))
224 .collect::<Result<Vec<_>, _>>()?
225 .into_iter()
226 .try_rfold(self.gen(body)?, |body, parameter| {
227 self.push_span(span.clone());
228 Ok(self.with_meta(Expr::Function {
229 parameter,
230 body: Box::new(body),
231 }))
232 })?
233 }
234 ast::expr::Expr::Array(items) => self.with_meta(Expr::Array(
235 items
236 .iter()
237 .map(|item| self.gen(item))
238 .collect::<Result<_, _>>()?,
239 )),
240 ast::expr::Expr::Set(items) => self.with_meta(Expr::Set(
241 items
242 .iter()
243 .map(|item| self.gen(item))
244 .collect::<Result<_, _>>()?,
245 )),
246 ast::expr::Expr::Include(file) => {
247 let InFile { id, expr } = self.included.get(file).unwrap();
248 self.push_file_id(*id);
249 let ret = self.gen(expr)?;
250 self.pop_file_id();
251 ret
252 }
253 ast::expr::Expr::Import { ty: _, uuid: _ } => todo!(),
254 ast::expr::Expr::Export { ty: _ } => todo!(),
255 ast::expr::Expr::Attribute { attr, item: expr } => {
256 self.pop_span();
257 let mut ret = self.gen(expr)?;
258 let attr = self.gen(attr)?.value;
259 ret.meta.attrs.push(attr);
260 self.attrs
261 .borrow_mut()
262 .insert(ret.meta.id, ret.meta.attrs.clone());
263 ret
264 }
265 ast::expr::Expr::Brand { brands, item: expr } => {
266 brands.iter().for_each(|brand| {
267 self.brands.borrow_mut().insert(brand.clone());
268 });
269 self.gen(expr)?
270 }
271 ast::expr::Expr::Match { of, cases } => self.with_meta(Expr::Match {
272 of: Box::new(self.gen(of)?),
273 cases: cases
274 .iter()
275 .map(|ast::expr::MatchCase { ty, expr }| {
276 Ok(MatchCase {
277 ty: self.gen_type(ty)?,
278 expr: self.gen(expr)?,
279 })
280 })
281 .collect::<Result<Vec<_>, _>>()?,
282 }),
283 ast::expr::Expr::Label { label, item: expr } => {
284 if self.brands.borrow().contains(label) {
285 self.with_meta(Expr::Brand {
286 brand: label.clone(),
287 item: Box::new(self.gen(expr)?),
288 })
289 } else {
290 self.with_meta(Expr::Label {
291 label: label.clone(),
292 item: Box::new(self.gen(expr)?),
293 })
294 }
295 }
296 ast::expr::Expr::NewType { ident, ty, expr } => {
297 let ty = self.gen_type(ty)?.value;
298 self.type_aliases.borrow_mut().insert(ident.clone(), ty);
299 self.gen(expr)?
300 }
301 ast::expr::Expr::Comment { item, .. } => self.gen(item)?,
302 ast::expr::Expr::Card { uuid, .. } => {
303 return Err(HirGenError::UnexpectedCard { ident: *uuid });
304 }
305 };
306 Ok(with_meta)
307 }
308
309 pub(crate) fn push_span(&self, span: Span) {
310 self.next_span.borrow_mut().push(span);
311 }
312
313 pub(crate) fn pop_span(&self) -> Option<Span> {
314 self.next_span.borrow_mut().pop()
315 }
316
317 fn get_id_of(&self, ident: String) -> usize {
318 *self
319 .variables
320 .borrow_mut()
321 .entry(ident)
322 .or_insert_with(|| self.next_id())
323 }
324
325 pub fn next_id(&self) -> Id {
326 let id = *self.next_id.borrow();
327 *self.next_id.borrow_mut() += 1;
328 id
329 }
330
331 fn with_meta<T: std::fmt::Debug>(&self, value: T) -> WithMeta<T> {
332 WithMeta {
333 meta: Meta {
334 attrs: vec![],
335 id: self.next_id(),
336 file_id: *self.file_stack.borrow().last().unwrap(),
337 span: self.pop_span().unwrap(),
338 },
339 value,
340 }
341 }
342}
343
344#[cfg(test)]
345mod tests {
346 use hir::{
347 meta::{dummy_meta, Meta},
348 ty::Type,
349 };
350 use pretty_assertions::assert_eq;
351
352 use super::*;
353
354 fn parse(input: &str) -> Spanned<ast::expr::Expr> {
355 parser::parse(lexer::scan(input).unwrap()).unwrap()
356 }
357 fn remove_meta_ty(ty: WithMeta<Type>) -> WithMeta<Type> {
358 let value = match ty.value {
359 Type::Number => ty.value,
360 Type::String => ty.value,
361 Type::Trait(_) => todo!(),
362 Type::Effectful { ty, effects } => Type::Effectful {
363 ty: Box::new(remove_meta_ty(*ty)),
364 effects,
365 },
366 Type::Infer => ty.value,
367 Type::This => ty.value,
368 Type::Product(types) => Type::Product(types.into_iter().map(remove_meta_ty).collect()),
369 Type::Sum(types) => Type::Sum(types.into_iter().map(remove_meta_ty).collect()),
370 Type::Function { parameter, body } => Type::Function {
371 parameter: Box::new(remove_meta_ty(*parameter)),
372 body: Box::new(remove_meta_ty(*body)),
373 },
374 Type::Array(ty) => Type::Array(Box::new(remove_meta_ty(*ty))),
375 Type::Set(ty) => Type::Set(Box::new(remove_meta_ty(*ty))),
376 Type::Let { variable, body } => Type::Let {
377 variable,
378 body: Box::new(remove_meta_ty(*body)),
379 },
380 Type::Variable(_) => ty.value,
381 Type::BoundedVariable { bound, identifier } => Type::BoundedVariable {
382 bound: Box::new(remove_meta_ty(*bound)),
383 identifier,
384 },
385 Type::Brand { brand, item } => Type::Brand {
386 brand,
387 item: Box::new(remove_meta_ty(*item)),
388 },
389 Type::Label { label, item } => Type::Label {
390 label,
391 item: Box::new(remove_meta_ty(*item)),
392 },
393 };
394 dummy_meta(value)
395 }
396 fn remove_meta(expr: WithMeta<Expr>) -> WithMeta<Expr> {
397 let value = match expr.value {
398 Expr::Literal(_) => expr.value,
399 Expr::Let {
400 ty,
401 definition,
402 expression,
403 } => Expr::Let {
404 ty: remove_meta_ty(ty),
405 definition: Box::new(remove_meta(*definition)),
406 expression: Box::new(remove_meta(*expression)),
407 },
408 Expr::Perform { input, output } => Expr::Perform {
409 input: Box::new(remove_meta(*input)),
410 output: remove_meta_ty(output),
411 },
412 Expr::Continue { input, output } => Expr::Continue {
413 input: Box::new(remove_meta(*input)),
414 output: output.map(remove_meta_ty),
415 },
416 Expr::Handle { handlers, expr } => Expr::Handle {
417 handlers: handlers
418 .into_iter()
419 .map(
420 |Handler {
421 input,
422 output,
423 handler,
424 }| Handler {
425 input: remove_meta_ty(input),
426 output: remove_meta_ty(output),
427 handler: remove_meta(handler),
428 },
429 )
430 .collect(),
431 expr: Box::new(remove_meta(*expr)),
432 },
433 Expr::Apply {
434 function,
435 link_name,
436 arguments,
437 } => Expr::Apply {
438 function: remove_meta_ty(function),
439 link_name,
440 arguments: arguments.into_iter().map(remove_meta).collect(),
441 },
442 Expr::Product(exprs) => Expr::Product(exprs.into_iter().map(remove_meta).collect()),
443 Expr::Typed { ty, item: expr } => Expr::Typed {
444 ty: remove_meta_ty(ty),
445 item: Box::new(remove_meta(*expr)),
446 },
447 Expr::Function { parameter, body } => Expr::Function {
448 parameter: remove_meta_ty(parameter),
449 body: Box::new(remove_meta(*body)),
450 },
451 Expr::Array(exprs) => Expr::Array(exprs.into_iter().map(remove_meta).collect()),
452 Expr::Set(exprs) => Expr::Set(exprs.into_iter().map(remove_meta).collect()),
453 Expr::Match { of, cases } => Expr::Match {
454 of: Box::new(remove_meta(*of)),
455 cases: cases
456 .into_iter()
457 .map(|MatchCase { ty, expr }| MatchCase {
458 ty: remove_meta_ty(ty),
459 expr: remove_meta(expr),
460 })
461 .collect(),
462 },
463 Expr::Label { label, item: body } => Expr::Label {
464 label,
465 item: Box::new(remove_meta(*body)),
466 },
467 Expr::Brand { brand, item: body } => Expr::Brand {
468 brand,
469 item: Box::new(remove_meta(*body)),
470 },
471 };
472 dummy_meta(value)
473 }
474
475 #[test]
476 fn test() {
477 let gen = HirGen::default();
478 gen.push_file_id(FileId(0));
479 assert_eq!(
480 gen.gen(&(
481 ast::expr::Expr::Apply {
482 function: (ast::ty::Type::Number, 3..10),
483 link_name: None,
484 arguments: vec![(
485 ast::expr::Expr::Attribute {
486 attr: Box::new((
487 ast::expr::Expr::Literal(ast::expr::Literal::Int(1)),
488 24..25
489 )),
490 item: Box::new((
491 ast::expr::Expr::Attribute {
492 attr: Box::new((
493 ast::expr::Expr::Literal(ast::expr::Literal::Int(2)),
494 24..25
495 )),
496 item: Box::new((ast::expr::Expr::Hole, 26..27)),
497 },
498 25..26
499 )),
500 },
501 24..27
502 )],
503 },
504 0..27
505 ),),
506 Ok(WithMeta {
507 meta: Meta {
508 attrs: vec![],
509 id: 4,
510 file_id: FileId(0),
511 span: 0..27
512 },
513 value: Expr::Apply {
514 function: WithMeta {
515 meta: Meta {
516 attrs: vec![],
517 id: 0,
518 file_id: FileId(0),
519 span: 3..10
520 },
521 value: Type::Number
522 },
523 link_name: Default::default(),
524 arguments: vec![WithMeta {
525 meta: Meta {
526 attrs: vec![
527 Expr::Literal(Literal::Int(2)),
528 Expr::Literal(Literal::Int(1))
529 ],
530 id: 1,
531 file_id: FileId(0),
532 span: 26..27
533 },
534 value: Expr::Literal(Literal::Hole)
535 }],
536 },
537 })
538 );
539
540 assert_eq!(
541 gen.attrs.borrow_mut().get(&1),
542 Some(&vec![
543 Expr::Literal(Literal::Int(2)),
544 Expr::Literal(Literal::Int(1))
545 ])
546 );
547 }
548
549 #[test]
550 fn label_and_brand() {
551 let expr = parse(
552 r#"
553 $ & @brand 'number ~
554 'brand brand ~
555 $ & @brand 'number ~
556 & @label 'number
557 "#,
558 );
559
560 let gen = HirGen::default();
561 gen.push_file_id(FileId(0));
562 assert_eq!(
563 remove_meta(gen.gen(&expr).unwrap()),
564 dummy_meta(Expr::Let {
565 ty: dummy_meta(Type::Infer),
566 definition: Box::new(dummy_meta(Expr::Apply {
567 function: dummy_meta(Type::Label {
568 label: "brand".into(),
569 item: Box::new(dummy_meta(Type::Number)),
570 }),
571 link_name: Default::default(),
572 arguments: vec![],
573 })),
574 expression: Box::new(dummy_meta(Expr::Let {
575 ty: dummy_meta(Type::Infer),
576 definition: Box::new(dummy_meta(Expr::Apply {
577 function: dummy_meta(Type::Brand {
578 brand: "brand".into(),
579 item: Box::new(dummy_meta(Type::Number)),
580 }),
581 link_name: Default::default(),
582 arguments: vec![],
583 })),
584 expression: Box::new(dummy_meta(Expr::Apply {
585 function: dummy_meta(Type::Label {
586 label: "label".into(),
587 item: Box::new(dummy_meta(Type::Number)),
588 }),
589 link_name: Default::default(),
590 arguments: vec![],
591 }))
592 }))
593 })
594 )
595 }
596}