1use crate::files::Files;
4use crate::sema::{
5 BuiltinType, ExternalSig, ReturnKind, Term, TermEnv, TermId, Type, TypeEnv, TypeId,
6};
7use crate::serialize::{Block, ControlFlow, EvalStep, MatchArm};
8use crate::stablemapset::StableSet;
9use crate::trie_again::{Binding, BindingId, Constraint, RuleSet};
10use std::fmt::Write;
11use std::slice::Iter;
12use std::sync::Arc;
13
14#[derive(Clone, Debug, Default)]
16pub struct CodegenOptions {
17 pub exclude_global_allow_pragmas: bool,
20
21 pub prefixes: Vec<Prefix>,
24}
25
26#[derive(Clone, Debug)]
28pub struct Prefix {
29 pub prefix: String,
31
32 pub name: String,
34}
35
36pub fn codegen(
38 files: Arc<Files>,
39 typeenv: &TypeEnv,
40 termenv: &TermEnv,
41 terms: &[(TermId, RuleSet)],
42 options: &CodegenOptions,
43) -> String {
44 Codegen::compile(files, typeenv, termenv, terms).generate_rust(options)
45}
46
47#[derive(Clone, Debug)]
48struct Codegen<'a> {
49 files: Arc<Files>,
50 typeenv: &'a TypeEnv,
51 termenv: &'a TermEnv,
52 terms: &'a [(TermId, RuleSet)],
53}
54
55enum Nested<'a> {
56 Cases(Iter<'a, EvalStep>),
57 Arms(BindingId, Iter<'a, MatchArm>),
58}
59
60struct BodyContext<'a, W> {
61 out: &'a mut W,
62 ruleset: &'a RuleSet,
63 indent: String,
64 is_ref: StableSet<BindingId>,
65 is_bound: StableSet<BindingId>,
66}
67
68impl<'a, W: Write> BodyContext<'a, W> {
69 fn new(out: &'a mut W, ruleset: &'a RuleSet) -> Self {
70 Self {
71 out,
72 ruleset,
73 indent: Default::default(),
74 is_ref: Default::default(),
75 is_bound: Default::default(),
76 }
77 }
78
79 fn enter_scope(&mut self) -> StableSet<BindingId> {
80 let new = self.is_bound.clone();
81 std::mem::replace(&mut self.is_bound, new)
82 }
83
84 fn begin_block(&mut self) -> std::fmt::Result {
85 self.indent.push_str(" ");
86 writeln!(self.out, " {{")
87 }
88
89 fn end_block(&mut self, last_line: &str, scope: StableSet<BindingId>) -> std::fmt::Result {
90 if !last_line.is_empty() {
91 writeln!(self.out, "{}{}", &self.indent, last_line)?;
92 }
93 self.is_bound = scope;
94 self.end_block_without_newline()?;
95 writeln!(self.out)
96 }
97
98 fn end_block_without_newline(&mut self) -> std::fmt::Result {
99 self.indent.truncate(self.indent.len() - 4);
100 write!(self.out, "{}}}", &self.indent)
101 }
102
103 fn set_ref(&mut self, binding: BindingId, is_ref: bool) {
104 if is_ref {
105 self.is_ref.insert(binding);
106 } else {
107 debug_assert!(!self.is_ref.contains(&binding));
108 }
109 }
110}
111
112impl<'a> Codegen<'a> {
113 fn compile(
114 files: Arc<Files>,
115 typeenv: &'a TypeEnv,
116 termenv: &'a TermEnv,
117 terms: &'a [(TermId, RuleSet)],
118 ) -> Codegen<'a> {
119 Codegen {
120 files,
121 typeenv,
122 termenv,
123 terms,
124 }
125 }
126
127 fn generate_rust(&self, options: &CodegenOptions) -> String {
128 let mut code = String::new();
129
130 self.generate_header(&mut code, options);
131 self.generate_ctx_trait(&mut code);
132 self.generate_internal_types(&mut code);
133 self.generate_internal_term_constructors(&mut code).unwrap();
134
135 code
136 }
137
138 fn generate_header(&self, code: &mut String, options: &CodegenOptions) {
139 writeln!(code, "// GENERATED BY ISLE. DO NOT EDIT!").unwrap();
140 writeln!(code, "//").unwrap();
141 writeln!(
142 code,
143 "// Generated automatically from the instruction-selection DSL code in:",
144 )
145 .unwrap();
146 for file in &self.files.file_names {
147 writeln!(code, "// - {file}").unwrap();
148 }
149
150 if !options.exclude_global_allow_pragmas {
151 writeln!(
152 code,
153 "\n#![allow(dead_code, unreachable_code, unreachable_patterns)]"
154 )
155 .unwrap();
156 writeln!(
157 code,
158 "#![allow(unused_imports, unused_variables, non_snake_case, unused_mut)]"
159 )
160 .unwrap();
161 writeln!(
162 code,
163 "#![allow(irrefutable_let_patterns, unused_assignments, non_camel_case_types)]"
164 )
165 .unwrap();
166 }
167
168 writeln!(code, "\nuse super::*; // Pulls in all external types.").unwrap();
169 writeln!(code, "use std::marker::PhantomData;").unwrap();
170 }
171
172 fn generate_trait_sig(&self, code: &mut String, indent: &str, sig: &ExternalSig) {
173 let ret_tuple = format!(
174 "{open_paren}{rets}{close_paren}",
175 open_paren = if sig.ret_tys.len() != 1 { "(" } else { "" },
176 rets = sig
177 .ret_tys
178 .iter()
179 .map(|&ty| self.type_name(ty, false))
180 .collect::<Vec<_>>()
181 .join(", "),
182 close_paren = if sig.ret_tys.len() != 1 { ")" } else { "" },
183 );
184
185 if sig.ret_kind == ReturnKind::Iterator {
186 writeln!(
187 code,
188 "{indent}type {name}_returns: Default + IntoContextIter<Context = Self, Output = {output}>;",
189 indent = indent,
190 name = sig.func_name,
191 output = ret_tuple,
192 )
193 .unwrap();
194 }
195
196 let ret_ty = match sig.ret_kind {
197 ReturnKind::Plain => ret_tuple,
198 ReturnKind::Option => format!("Option<{ret_tuple}>"),
199 ReturnKind::Iterator => format!("()"),
200 };
201
202 writeln!(
203 code,
204 "{indent}fn {name}(&mut self, {params}) -> {ret_ty};",
205 indent = indent,
206 name = sig.func_name,
207 params = sig
208 .param_tys
209 .iter()
210 .enumerate()
211 .map(|(i, &ty)| format!("arg{}: {}", i, self.type_name(ty, true)))
212 .chain(if sig.ret_kind == ReturnKind::Iterator {
213 Some(format!("returns: &mut Self::{}_returns", sig.func_name))
214 } else {
215 None
216 })
217 .collect::<Vec<_>>()
218 .join(", "),
219 ret_ty = ret_ty,
220 )
221 .unwrap();
222 }
223
224 fn generate_ctx_trait(&self, code: &mut String) {
225 writeln!(code).unwrap();
226 writeln!(
227 code,
228 "/// Context during lowering: an implementation of this trait"
229 )
230 .unwrap();
231 writeln!(
232 code,
233 "/// must be provided with all external constructors and extractors."
234 )
235 .unwrap();
236 writeln!(
237 code,
238 "/// A mutable borrow is passed along through all lowering logic."
239 )
240 .unwrap();
241 writeln!(code, "pub trait Context {{").unwrap();
242 for term in &self.termenv.terms {
243 if term.has_external_extractor() {
244 let ext_sig = term.extractor_sig(self.typeenv).unwrap();
245 self.generate_trait_sig(code, " ", &ext_sig);
246 }
247 if term.has_external_constructor() {
248 let ext_sig = term.constructor_sig(self.typeenv).unwrap();
249 self.generate_trait_sig(code, " ", &ext_sig);
250 }
251 }
252 writeln!(code, "}}").unwrap();
253 writeln!(
254 code,
255 r#"
256pub trait ContextIter {{
257 type Context;
258 type Output;
259 fn next(&mut self, ctx: &mut Self::Context) -> Option<Self::Output>;
260 fn size_hint(&self) -> (usize, Option<usize>) {{ (0, None) }}
261}}
262
263pub trait IntoContextIter {{
264 type Context;
265 type Output;
266 type IntoIter: ContextIter<Context = Self::Context, Output = Self::Output>;
267 fn into_context_iter(self) -> Self::IntoIter;
268}}
269
270pub trait Length {{
271 fn len(&self) -> usize;
272}}
273
274impl<T> Length for std::vec::Vec<T> {{
275 fn len(&self) -> usize {{
276 std::vec::Vec::len(self)
277 }}
278}}
279
280pub struct ContextIterWrapper<I, C> {{
281 iter: I,
282 _ctx: std::marker::PhantomData<C>,
283}}
284impl<I: Default, C> Default for ContextIterWrapper<I, C> {{
285 fn default() -> Self {{
286 ContextIterWrapper {{
287 iter: I::default(),
288 _ctx: std::marker::PhantomData
289 }}
290 }}
291}}
292impl<I, C> std::ops::Deref for ContextIterWrapper<I, C> {{
293 type Target = I;
294 fn deref(&self) -> &I {{
295 &self.iter
296 }}
297}}
298impl<I, C> std::ops::DerefMut for ContextIterWrapper<I, C> {{
299 fn deref_mut(&mut self) -> &mut I {{
300 &mut self.iter
301 }}
302}}
303impl<I: Iterator, C: Context> From<I> for ContextIterWrapper<I, C> {{
304 fn from(iter: I) -> Self {{
305 Self {{ iter, _ctx: std::marker::PhantomData }}
306 }}
307}}
308impl<I: Iterator, C: Context> ContextIter for ContextIterWrapper<I, C> {{
309 type Context = C;
310 type Output = I::Item;
311 fn next(&mut self, _ctx: &mut Self::Context) -> Option<Self::Output> {{
312 self.iter.next()
313 }}
314 fn size_hint(&self) -> (usize, Option<usize>) {{
315 self.iter.size_hint()
316 }}
317}}
318impl<I: IntoIterator, C: Context> IntoContextIter for ContextIterWrapper<I, C> {{
319 type Context = C;
320 type Output = I::Item;
321 type IntoIter = ContextIterWrapper<I::IntoIter, C>;
322 fn into_context_iter(self) -> Self::IntoIter {{
323 ContextIterWrapper {{
324 iter: self.iter.into_iter(),
325 _ctx: std::marker::PhantomData
326 }}
327 }}
328}}
329impl<T, E: Extend<T>, C> Extend<T> for ContextIterWrapper<E, C> {{
330 fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {{
331 self.iter.extend(iter);
332 }}
333}}
334impl<L: Length, C> Length for ContextIterWrapper<L, C> {{
335 fn len(&self) -> usize {{
336 self.iter.len()
337 }}
338}}
339 "#,
340 )
341 .unwrap();
342 }
343
344 fn generate_internal_types(&self, code: &mut String) {
345 for ty in &self.typeenv.types {
346 match ty {
347 &Type::Enum {
348 name,
349 is_extern,
350 is_nodebug,
351 ref variants,
352 pos,
353 ..
354 } if !is_extern => {
355 let name = &self.typeenv.syms[name.index()];
356 writeln!(
357 code,
358 "\n/// Internal type {}: defined at {}.",
359 name,
360 pos.pretty_print_line(&self.files)
361 )
362 .unwrap();
363
364 let debug_derive = if is_nodebug { "" } else { ", Debug" };
366 if variants.iter().all(|v| v.fields.is_empty()) {
367 writeln!(code, "#[derive(Copy, Clone, PartialEq, Eq{debug_derive})]")
368 .unwrap();
369 } else {
370 writeln!(code, "#[derive(Clone{debug_derive})]").unwrap();
371 }
372
373 writeln!(code, "pub enum {name} {{").unwrap();
374 for variant in variants {
375 let name = &self.typeenv.syms[variant.name.index()];
376 if variant.fields.is_empty() {
377 writeln!(code, " {name},").unwrap();
378 } else {
379 writeln!(code, " {name} {{").unwrap();
380 for field in &variant.fields {
381 let name = &self.typeenv.syms[field.name.index()];
382 let ty_name =
383 self.typeenv.types[field.ty.index()].name(self.typeenv);
384 writeln!(code, " {name}: {ty_name},").unwrap();
385 }
386 writeln!(code, " }},").unwrap();
387 }
388 }
389 writeln!(code, "}}").unwrap();
390 }
391 _ => {}
392 }
393 }
394 }
395
396 fn type_name(&self, typeid: TypeId, by_ref: bool) -> String {
397 match self.typeenv.types[typeid.index()] {
398 Type::Builtin(bt) => String::from(bt.name()),
399 Type::Primitive(_, sym, _) => self.typeenv.syms[sym.index()].clone(),
400 Type::Enum { name, .. } => {
401 let r = if by_ref { "&" } else { "" };
402 format!("{}{}", r, self.typeenv.syms[name.index()])
403 }
404 }
405 }
406
407 fn generate_internal_term_constructors(&self, code: &mut String) -> std::fmt::Result {
408 for &(termid, ref ruleset) in self.terms.iter() {
409 let root = crate::serialize::serialize(ruleset);
410 let mut ctx = BodyContext::new(code, ruleset);
411
412 let termdata = &self.termenv.terms[termid.index()];
413 let term_name = &self.typeenv.syms[termdata.name.index()];
414 writeln!(ctx.out)?;
415 writeln!(
416 ctx.out,
417 "{}// Generated as internal constructor for term {}.",
418 &ctx.indent, term_name,
419 )?;
420
421 let sig = termdata.constructor_sig(self.typeenv).unwrap();
422 writeln!(
423 ctx.out,
424 "{}pub fn {}<C: Context>(",
425 &ctx.indent, sig.func_name
426 )?;
427
428 writeln!(ctx.out, "{} ctx: &mut C,", &ctx.indent)?;
429 for (i, &ty) in sig.param_tys.iter().enumerate() {
430 let (is_ref, ty) = self.ty(ty);
431 write!(ctx.out, "{} arg{}: ", &ctx.indent, i)?;
432 write!(ctx.out, "{}{}", if is_ref { "&" } else { "" }, ty)?;
433 if let Some(binding) = ctx.ruleset.find_binding(&Binding::Argument {
434 index: i.try_into().unwrap(),
435 }) {
436 ctx.set_ref(binding, is_ref);
437 }
438 writeln!(ctx.out, ",")?;
439 }
440
441 let (_, ret) = self.ty(sig.ret_tys[0]);
442
443 if let ReturnKind::Iterator = sig.ret_kind {
444 writeln!(
445 ctx.out,
446 "{} returns: &mut (impl Extend<{}> + Length),",
447 &ctx.indent, ret
448 )?;
449 }
450
451 write!(ctx.out, "{}) -> ", &ctx.indent)?;
452 match sig.ret_kind {
453 ReturnKind::Iterator => write!(ctx.out, "()")?,
454 ReturnKind::Option => write!(ctx.out, "Option<{ret}>")?,
455 ReturnKind::Plain => write!(ctx.out, "{ret}")?,
456 };
457
458 let last_expr = if let Some(EvalStep {
459 check: ControlFlow::Return { .. },
460 ..
461 }) = root.steps.last()
462 {
463 String::new()
465 } else {
466 match sig.ret_kind {
467 ReturnKind::Iterator => String::new(),
468 ReturnKind::Option => "None".to_string(),
469 ReturnKind::Plain => format!(
470 "unreachable!(\"no rule matched for term {{}} at {{}}; should it be partial?\", {:?}, {:?})",
471 term_name,
472 termdata
473 .decl_pos
474 .pretty_print_line(&self.files)
475 ),
476 }
477 };
478
479 let scope = ctx.enter_scope();
480 self.emit_block(&mut ctx, &root, sig.ret_kind, &last_expr, scope)?;
481 }
482 Ok(())
483 }
484
485 fn ty(&self, typeid: TypeId) -> (bool, String) {
486 let ty = &self.typeenv.types[typeid.index()];
487 let name = ty.name(self.typeenv);
488 let is_ref = match ty {
489 Type::Builtin(_) | Type::Primitive(..) => false,
490 Type::Enum { .. } => true,
491 };
492 (is_ref, String::from(name))
493 }
494
495 fn validate_block(ret_kind: ReturnKind, block: &Block) -> Nested {
496 if !matches!(ret_kind, ReturnKind::Iterator) {
497 assert!(!block
499 .steps
500 .iter()
501 .any(|c| matches!(c.check, ControlFlow::Loop { .. })));
502
503 if let Some(result_pos) = block
506 .steps
507 .iter()
508 .position(|c| matches!(c.check, ControlFlow::Return { .. }))
509 {
510 assert_eq!(block.steps.len() - 1, result_pos);
511 }
512 }
513
514 Nested::Cases(block.steps.iter())
515 }
516
517 fn emit_block<W: Write>(
518 &self,
519 ctx: &mut BodyContext<W>,
520 block: &Block,
521 ret_kind: ReturnKind,
522 last_expr: &str,
523 scope: StableSet<BindingId>,
524 ) -> std::fmt::Result {
525 let mut stack = Vec::new();
526 ctx.begin_block()?;
527 stack.push((Self::validate_block(ret_kind, block), last_expr, scope));
528
529 while let Some((mut nested, last_line, scope)) = stack.pop() {
530 match &mut nested {
531 Nested::Cases(cases) => {
532 let Some(case) = cases.next() else {
533 ctx.end_block(last_line, scope)?;
534 continue;
535 };
536 stack.push((nested, last_line, scope));
538
539 for &expr in case.bind_order.iter() {
540 let iter_return = match &ctx.ruleset.bindings[expr.index()] {
541 Binding::Extractor { term, .. } => {
542 let termdata = &self.termenv.terms[term.index()];
543 let sig = termdata.extractor_sig(self.typeenv).unwrap();
544 if sig.ret_kind == ReturnKind::Iterator {
545 if termdata.has_external_extractor() {
546 Some(format!("C::{}_returns", sig.func_name))
547 } else {
548 Some(format!("ContextIterWrapper::<ConstructorVec<_>, _>"))
549 }
550 } else {
551 None
552 }
553 }
554 Binding::Constructor { term, .. } => {
555 let termdata = &self.termenv.terms[term.index()];
556 let sig = termdata.constructor_sig(self.typeenv).unwrap();
557 if sig.ret_kind == ReturnKind::Iterator {
558 if termdata.has_external_constructor() {
559 Some(format!("C::{}_returns", sig.func_name))
560 } else {
561 Some(format!("ContextIterWrapper::<ConstructorVec<_>, _>"))
562 }
563 } else {
564 None
565 }
566 }
567 _ => None,
568 };
569 if let Some(ty) = iter_return {
570 writeln!(
571 ctx.out,
572 "{}let mut v{} = {}::default();",
573 &ctx.indent,
574 expr.index(),
575 ty
576 )?;
577 write!(ctx.out, "{}", &ctx.indent)?;
578 } else {
579 write!(ctx.out, "{}let v{} = ", &ctx.indent, expr.index())?;
580 }
581 self.emit_expr(ctx, expr)?;
582 writeln!(ctx.out, ";")?;
583 ctx.is_bound.insert(expr);
584 }
585
586 match &case.check {
587 ControlFlow::Match { source, arms } if arms.len() == 1 => {
589 let arm = &arms[0];
590 let scope = ctx.enter_scope();
591 match arm.constraint {
592 Constraint::ConstBool { .. }
593 | Constraint::ConstInt { .. }
594 | Constraint::ConstPrim { .. } => {
595 write!(ctx.out, "{}if ", &ctx.indent)?;
596 self.emit_expr(ctx, *source)?;
597 write!(ctx.out, " == ")?;
598 self.emit_constraint(ctx, *source, arm)?;
599 }
600 Constraint::Variant { .. } | Constraint::Some => {
601 write!(ctx.out, "{}if let ", &ctx.indent)?;
602 self.emit_constraint(ctx, *source, arm)?;
603 write!(ctx.out, " = ")?;
604 self.emit_source(ctx, *source, arm.constraint)?;
605 }
606 }
607 ctx.begin_block()?;
608 stack.push((Self::validate_block(ret_kind, &arm.body), "", scope));
609 }
610
611 ControlFlow::Match { source, arms } => {
612 let scope = ctx.enter_scope();
613 write!(ctx.out, "{}match ", &ctx.indent)?;
614 self.emit_source(ctx, *source, arms[0].constraint)?;
615 ctx.begin_block()?;
616
617 stack.push((Nested::Arms(*source, arms.iter()), "_ => {}", scope));
621 }
622
623 ControlFlow::Equal { a, b, body } => {
624 let scope = ctx.enter_scope();
625 write!(ctx.out, "{}if ", &ctx.indent)?;
626 self.emit_expr(ctx, *a)?;
627 write!(ctx.out, " == ")?;
628 self.emit_expr(ctx, *b)?;
629 ctx.begin_block()?;
630 stack.push((Self::validate_block(ret_kind, body), "", scope));
631 }
632
633 ControlFlow::Loop { result, body } => {
634 let source = match &ctx.ruleset.bindings[result.index()] {
635 Binding::Iterator { source } => source,
636 _ => unreachable!("Loop from a non-Iterator"),
637 };
638 let scope = ctx.enter_scope();
639
640 writeln!(
641 ctx.out,
642 "{}let mut v{} = v{}.into_context_iter();",
643 &ctx.indent,
644 source.index(),
645 source.index(),
646 )?;
647
648 write!(
649 ctx.out,
650 "{}while let Some(v{}) = v{}.next(ctx)",
651 &ctx.indent,
652 result.index(),
653 source.index()
654 )?;
655 ctx.is_bound.insert(*result);
656 ctx.begin_block()?;
657 stack.push((Self::validate_block(ret_kind, body), "", scope));
658 }
659
660 &ControlFlow::Return { pos, result } => {
661 writeln!(
662 ctx.out,
663 "{}// Rule at {}.",
664 &ctx.indent,
665 pos.pretty_print_line(&self.files)
666 )?;
667 write!(ctx.out, "{}", &ctx.indent)?;
668 match ret_kind {
669 ReturnKind::Plain | ReturnKind::Option => {
670 write!(ctx.out, "return ")?
671 }
672 ReturnKind::Iterator => write!(ctx.out, "returns.extend(Some(")?,
673 }
674 self.emit_expr(ctx, result)?;
675 if ctx.is_ref.contains(&result) {
676 write!(ctx.out, ".clone()")?;
677 }
678 match ret_kind {
679 ReturnKind::Plain | ReturnKind::Option => writeln!(ctx.out, ";")?,
680 ReturnKind::Iterator => {
681 writeln!(ctx.out, "));")?;
682 writeln!(
683 ctx.out,
684 "{}if returns.len() >= MAX_ISLE_RETURNS {{ return; }}",
685 ctx.indent
686 )?;
687 }
688 }
689 }
690 }
691 }
692
693 Nested::Arms(source, arms) => {
694 let Some(arm) = arms.next() else {
695 ctx.end_block(last_line, scope)?;
696 continue;
697 };
698 let source = *source;
699 stack.push((nested, last_line, scope));
701
702 let scope = ctx.enter_scope();
703 write!(ctx.out, "{}", &ctx.indent)?;
704 self.emit_constraint(ctx, source, arm)?;
705 write!(ctx.out, " =>")?;
706 ctx.begin_block()?;
707 stack.push((Self::validate_block(ret_kind, &arm.body), "", scope));
708 }
709 }
710 }
711
712 Ok(())
713 }
714
715 fn emit_expr<W: Write>(&self, ctx: &mut BodyContext<W>, result: BindingId) -> std::fmt::Result {
716 if ctx.is_bound.contains(&result) {
717 return write!(ctx.out, "v{}", result.index());
718 }
719
720 let binding = &ctx.ruleset.bindings[result.index()];
721
722 let mut call =
723 |term: TermId,
724 parameters: &[BindingId],
725
726 get_sig: fn(&Term, &TypeEnv) -> Option<ExternalSig>| {
727 let termdata = &self.termenv.terms[term.index()];
728 let sig = get_sig(termdata, self.typeenv).unwrap();
729 if let &[ret_ty] = &sig.ret_tys[..] {
730 let (is_ref, _) = self.ty(ret_ty);
731 if is_ref {
732 ctx.set_ref(result, true);
733 write!(ctx.out, "&")?;
734 }
735 }
736 write!(ctx.out, "{}(ctx", sig.full_name)?;
737 debug_assert_eq!(parameters.len(), sig.param_tys.len());
738 for (¶meter, &arg_ty) in parameters.iter().zip(sig.param_tys.iter()) {
739 let (is_ref, _) = self.ty(arg_ty);
740 write!(ctx.out, ", ")?;
741 let (before, after) = match (is_ref, ctx.is_ref.contains(¶meter)) {
742 (false, true) => ("", ".clone()"),
743 (true, false) => ("&", ""),
744 _ => ("", ""),
745 };
746 write!(ctx.out, "{before}")?;
747 self.emit_expr(ctx, parameter)?;
748 write!(ctx.out, "{after}")?;
749 }
750 if let ReturnKind::Iterator = sig.ret_kind {
751 write!(ctx.out, ", &mut v{}", result.index())?;
752 }
753 write!(ctx.out, ")")
754 };
755
756 match binding {
757 &Binding::ConstBool { val, .. } => self.emit_bool(ctx, val),
758 &Binding::ConstInt { val, ty } => self.emit_int(ctx, val, ty),
759 Binding::ConstPrim { val } => write!(ctx.out, "{}", &self.typeenv.syms[val.index()]),
760 Binding::Argument { index } => write!(ctx.out, "arg{}", index.index()),
761 Binding::Extractor { term, parameter } => {
762 call(*term, std::slice::from_ref(parameter), Term::extractor_sig)
763 }
764 Binding::Constructor {
765 term, parameters, ..
766 } => call(*term, ¶meters[..], Term::constructor_sig),
767
768 Binding::MakeVariant {
769 ty,
770 variant,
771 fields,
772 } => {
773 let (name, variants) = match &self.typeenv.types[ty.index()] {
774 Type::Enum { name, variants, .. } => (name, variants),
775 _ => unreachable!("MakeVariant with primitive type"),
776 };
777 let variant = &variants[variant.index()];
778 write!(
779 ctx.out,
780 "{}::{}",
781 &self.typeenv.syms[name.index()],
782 &self.typeenv.syms[variant.name.index()]
783 )?;
784 if !fields.is_empty() {
785 ctx.begin_block()?;
786 for (field, value) in variant.fields.iter().zip(fields.iter()) {
787 write!(
788 ctx.out,
789 "{}{}: ",
790 &ctx.indent,
791 &self.typeenv.syms[field.name.index()],
792 )?;
793 self.emit_expr(ctx, *value)?;
794 if ctx.is_ref.contains(value) {
795 write!(ctx.out, ".clone()")?;
796 }
797 writeln!(ctx.out, ",")?;
798 }
799 ctx.end_block_without_newline()?;
800 }
801 Ok(())
802 }
803
804 &Binding::MakeSome { inner } => {
805 write!(ctx.out, "Some(")?;
806 self.emit_expr(ctx, inner)?;
807 write!(ctx.out, ")")
808 }
809 &Binding::MatchSome { source } => {
810 self.emit_expr(ctx, source)?;
811 write!(ctx.out, "?")
812 }
813 &Binding::MatchTuple { source, field } => {
814 self.emit_expr(ctx, source)?;
815 write!(ctx.out, ".{}", field.index())
816 }
817
818 &Binding::MatchVariant { source, field, .. } => {
821 self.emit_expr(ctx, source)?;
822 write!(ctx.out, ".{} /*FIXME*/", field.index())
823 }
824 &Binding::Iterator { source } => {
825 self.emit_expr(ctx, source)?;
826 write!(ctx.out, ".next() /*FIXME*/")
827 }
828 }
829 }
830
831 fn emit_source<W: Write>(
832 &self,
833 ctx: &mut BodyContext<W>,
834 source: BindingId,
835 constraint: Constraint,
836 ) -> std::fmt::Result {
837 if let Constraint::Variant { .. } = constraint {
838 if !ctx.is_ref.contains(&source) {
839 write!(ctx.out, "&")?;
840 }
841 }
842 self.emit_expr(ctx, source)
843 }
844
845 fn emit_constraint<W: Write>(
846 &self,
847 ctx: &mut BodyContext<W>,
848 source: BindingId,
849 arm: &MatchArm,
850 ) -> std::fmt::Result {
851 let MatchArm {
852 constraint,
853 bindings,
854 ..
855 } = arm;
856 for binding in bindings.iter() {
857 if let &Some(binding) = binding {
858 ctx.is_bound.insert(binding);
859 }
860 }
861 match *constraint {
862 Constraint::ConstBool { val, .. } => self.emit_bool(ctx, val),
863 Constraint::ConstInt { val, ty } => self.emit_int(ctx, val, ty),
864 Constraint::ConstPrim { val } => {
865 write!(ctx.out, "{}", &self.typeenv.syms[val.index()])
866 }
867 Constraint::Variant { ty, variant, .. } => {
868 let (name, variants) = match &self.typeenv.types[ty.index()] {
869 Type::Enum { name, variants, .. } => (name, variants),
870 _ => unreachable!("Variant constraint on primitive type"),
871 };
872 let variant = &variants[variant.index()];
873 write!(
874 ctx.out,
875 "&{}::{}",
876 &self.typeenv.syms[name.index()],
877 &self.typeenv.syms[variant.name.index()]
878 )?;
879 if !bindings.is_empty() {
880 ctx.begin_block()?;
881 let mut skipped_some = false;
882 for (&binding, field) in bindings.iter().zip(variant.fields.iter()) {
883 if let Some(binding) = binding {
884 write!(
885 ctx.out,
886 "{}{}: ",
887 &ctx.indent,
888 &self.typeenv.syms[field.name.index()]
889 )?;
890 let (is_ref, _) = self.ty(field.ty);
891 if is_ref {
892 ctx.set_ref(binding, true);
893 write!(ctx.out, "ref ")?;
894 }
895 writeln!(ctx.out, "v{},", binding.index())?;
896 } else {
897 skipped_some = true;
898 }
899 }
900 if skipped_some {
901 writeln!(ctx.out, "{}..", &ctx.indent)?;
902 }
903 ctx.end_block_without_newline()?;
904 }
905 Ok(())
906 }
907 Constraint::Some => {
908 write!(ctx.out, "Some(")?;
909 if let Some(binding) = bindings[0] {
910 ctx.set_ref(binding, ctx.is_ref.contains(&source));
911 write!(ctx.out, "v{}", binding.index())?;
912 } else {
913 write!(ctx.out, "_")?;
914 }
915 write!(ctx.out, ")")
916 }
917 }
918 }
919
920 fn emit_bool<W: Write>(
921 &self,
922 ctx: &mut BodyContext<W>,
923 val: bool,
924 ) -> Result<(), std::fmt::Error> {
925 write!(ctx.out, "{val}")
926 }
927
928 fn emit_int<W: Write>(
929 &self,
930 ctx: &mut BodyContext<W>,
931 val: i128,
932 ty: TypeId,
933 ) -> Result<(), std::fmt::Error> {
934 let ty_data = &self.typeenv.types[ty.index()];
935 match ty_data {
936 Type::Builtin(BuiltinType::Int(ty)) if ty.is_signed() => write!(ctx.out, "{val}_{ty}"),
937 Type::Builtin(BuiltinType::Int(ty)) => write!(ctx.out, "{val:#x}_{ty}"),
938 _ => write!(ctx.out, "{val:#x}"),
939 }
940 }
941}