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