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