Don't use &mut dyn Write in codegen

We always use a `String` which has infallible writing so we can remove all these
`Result`s and pretend-fallible methods.
This commit is contained in:
Nick Fitzgerald
2021-09-27 15:57:32 -07:00
committed by Chris Fallin
parent 3535f82056
commit 972dc00a92
2 changed files with 120 additions and 115 deletions

View File

@@ -1,8 +1,8 @@
//! Generate Rust code from a series of Sequences. //! Generate Rust code from a series of Sequences.
use crate::ir::{lower_rule, ExprInst, ExprSequence, InstId, PatternInst, PatternSequence, Value}; use crate::ir::{lower_rule, ExprInst, ExprSequence, InstId, PatternInst, PatternSequence, Value};
use crate::sema::ExternalSig;
use crate::sema::{RuleId, TermEnv, TermId, Type, TypeEnv, TypeId, Variant}; use crate::sema::{RuleId, TermEnv, TermId, Type, TypeEnv, TypeId, Variant};
use crate::{error::Error, sema::ExternalSig};
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::fmt::Write; use std::fmt::Write;
@@ -506,60 +506,56 @@ struct BodyContext {
} }
impl<'a> Codegen<'a> { impl<'a> Codegen<'a> {
pub fn compile(typeenv: &'a TypeEnv, termenv: &'a TermEnv) -> Result<Codegen<'a>, Error> { pub fn compile(typeenv: &'a TypeEnv, termenv: &'a TermEnv) -> Codegen<'a> {
let mut builder = TermFunctionsBuilder::new(typeenv, termenv); let mut builder = TermFunctionsBuilder::new(typeenv, termenv);
builder.build(); builder.build();
log::trace!("builder: {:?}", builder); log::trace!("builder: {:?}", builder);
let functions_by_term = builder.finalize(); let functions_by_term = builder.finalize();
Ok(Codegen { Codegen {
typeenv, typeenv,
termenv, termenv,
functions_by_term, functions_by_term,
}) }
} }
pub fn generate_rust(&self) -> Result<String, Error> { pub fn generate_rust(&self) -> String {
let mut code = String::new(); let mut code = String::new();
self.generate_header(&mut code)?; self.generate_header(&mut code);
self.generate_ctx_trait(&mut code)?; self.generate_ctx_trait(&mut code);
self.generate_internal_types(&mut code)?; self.generate_internal_types(&mut code);
self.generate_internal_term_constructors(&mut code)?; self.generate_internal_term_constructors(&mut code);
Ok(code) code
} }
fn generate_header(&self, code: &mut dyn Write) -> Result<(), Error> { fn generate_header(&self, code: &mut String) {
writeln!(code, "// GENERATED BY ISLE. DO NOT EDIT!")?; writeln!(code, "// GENERATED BY ISLE. DO NOT EDIT!").unwrap();
writeln!(code, "//")?; writeln!(code, "//").unwrap();
writeln!( writeln!(
code, code,
"// Generated automatically from the instruction-selection DSL code in:", "// Generated automatically from the instruction-selection DSL code in:",
)?; )
.unwrap();
for file in &self.typeenv.filenames { for file in &self.typeenv.filenames {
writeln!(code, "// - {}", file)?; writeln!(code, "// - {}", file).unwrap();
} }
writeln!( writeln!(
code, code,
"\n#![allow(dead_code, unreachable_code, unreachable_patterns)]" "\n#![allow(dead_code, unreachable_code, unreachable_patterns)]"
)?; )
.unwrap();
writeln!( writeln!(
code, code,
"#![allow(unused_imports, unused_variables, non_snake_case)]" "#![allow(unused_imports, unused_variables, non_snake_case)]"
)?; )
.unwrap();
writeln!(code, "\nuse super::*; // Pulls in all external types.")?; writeln!(code, "\nuse super::*; // Pulls in all external types.").unwrap();
Ok(())
} }
fn generate_trait_sig( fn generate_trait_sig(&self, code: &mut String, indent: &str, sig: &ExternalSig) {
&self,
code: &mut dyn Write,
indent: &str,
sig: &ExternalSig,
) -> Result<(), Error> {
writeln!( writeln!(
code, code,
"{}fn {}(&mut self, {}) -> {}({},){};", "{}fn {}(&mut self, {}) -> {}({},){};",
@@ -578,37 +574,38 @@ impl<'a> Codegen<'a> {
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(", "), .join(", "),
if sig.infallible { "" } else { ">" }, if sig.infallible { "" } else { ">" },
)?; )
Ok(()) .unwrap();
} }
fn generate_ctx_trait(&self, code: &mut dyn Write) -> Result<(), Error> { fn generate_ctx_trait(&self, code: &mut String) {
writeln!(code, "")?; writeln!(code, "").unwrap();
writeln!( writeln!(
code, code,
"/// Context during lowering: an implementation of this trait" "/// Context during lowering: an implementation of this trait"
)?; )
.unwrap();
writeln!( writeln!(
code, code,
"/// must be provided with all external constructors and extractors." "/// must be provided with all external constructors and extractors."
)?; )
.unwrap();
writeln!( writeln!(
code, code,
"/// A mutable borrow is passed along through all lowering logic." "/// A mutable borrow is passed along through all lowering logic."
)?; )
writeln!(code, "pub trait Context {{")?; .unwrap();
writeln!(code, "pub trait Context {{").unwrap();
for term in &self.termenv.terms { for term in &self.termenv.terms {
if term.is_external() { if term.is_external() {
let ext_sig = term.to_sig(self.typeenv).unwrap(); let ext_sig = term.to_sig(self.typeenv).unwrap();
self.generate_trait_sig(code, " ", &ext_sig)?; self.generate_trait_sig(code, " ", &ext_sig);
} }
} }
writeln!(code, "}}")?; writeln!(code, "}}").unwrap();
Ok(())
} }
fn generate_internal_types(&self, code: &mut dyn Write) -> Result<(), Error> { fn generate_internal_types(&self, code: &mut String) {
for ty in &self.typeenv.types { for ty in &self.typeenv.types {
match ty { match ty {
&Type::Enum { &Type::Enum {
@@ -624,30 +621,30 @@ impl<'a> Codegen<'a> {
"\n/// Internal type {}: defined at {}.", "\n/// Internal type {}: defined at {}.",
name, name,
pos.pretty_print_line(&self.typeenv.filenames[..]) pos.pretty_print_line(&self.typeenv.filenames[..])
)?; )
writeln!(code, "#[derive(Clone, Debug)]")?; .unwrap();
writeln!(code, "pub enum {} {{", name)?; writeln!(code, "#[derive(Clone, Debug)]").unwrap();
writeln!(code, "pub enum {} {{", name).unwrap();
for variant in variants { for variant in variants {
let name = &self.typeenv.syms[variant.name.index()]; let name = &self.typeenv.syms[variant.name.index()];
if variant.fields.is_empty() { if variant.fields.is_empty() {
writeln!(code, " {},", name)?; writeln!(code, " {},", name).unwrap();
} else { } else {
writeln!(code, " {} {{", name)?; writeln!(code, " {} {{", name).unwrap();
for field in &variant.fields { for field in &variant.fields {
let name = &self.typeenv.syms[field.name.index()]; let name = &self.typeenv.syms[field.name.index()];
let ty_name = let ty_name =
self.typeenv.types[field.ty.index()].name(&self.typeenv); self.typeenv.types[field.ty.index()].name(&self.typeenv);
writeln!(code, " {}: {},", name, ty_name)?; writeln!(code, " {}: {},", name, ty_name).unwrap();
} }
writeln!(code, " }},")?; writeln!(code, " }},").unwrap();
} }
} }
writeln!(code, "}}")?; writeln!(code, "}}").unwrap();
} }
_ => {} _ => {}
} }
} }
Ok(())
} }
fn type_name(&self, typeid: TypeId, by_ref: bool) -> String { fn type_name(&self, typeid: TypeId, by_ref: bool) -> String {
@@ -718,7 +715,7 @@ impl<'a> Codegen<'a> {
} }
} }
fn generate_internal_term_constructors(&self, code: &mut dyn Write) -> Result<(), Error> { fn generate_internal_term_constructors(&self, code: &mut String) {
for (&termid, trie) in &self.functions_by_term { for (&termid, trie) in &self.functions_by_term {
let termdata = &self.termenv.terms[termid.index()]; let termdata = &self.termenv.terms[termid.index()];
@@ -744,35 +741,35 @@ impl<'a> Codegen<'a> {
code, code,
"\n// Generated as internal constructor for term {}.", "\n// Generated as internal constructor for term {}.",
self.typeenv.syms[termdata.name.index()], self.typeenv.syms[termdata.name.index()],
)?; )
.unwrap();
writeln!( writeln!(
code, code,
"pub fn {}<C: Context>(ctx: &mut C, {}) -> Option<{}> {{", "pub fn {}<C: Context>(ctx: &mut C, {}) -> Option<{}> {{",
sig.func_name, args, ret, sig.func_name, args, ret,
)?; )
.unwrap();
let mut body_ctx: BodyContext = Default::default(); let mut body_ctx: BodyContext = Default::default();
let returned = let returned =
self.generate_body(code, /* depth = */ 0, trie, " ", &mut body_ctx)?; self.generate_body(code, /* depth = */ 0, trie, " ", &mut body_ctx);
if !returned { if !returned {
writeln!(code, " return None;")?; writeln!(code, " return None;").unwrap();
} }
writeln!(code, "}}")?; writeln!(code, "}}").unwrap();
} }
Ok(())
} }
fn generate_expr_inst( fn generate_expr_inst(
&self, &self,
code: &mut dyn Write, code: &mut String,
id: InstId, id: InstId,
inst: &ExprInst, inst: &ExprInst,
indent: &str, indent: &str,
ctx: &mut BodyContext, ctx: &mut BodyContext,
returns: &mut Vec<(usize, String)>, returns: &mut Vec<(usize, String)>,
) -> Result<(), Error> { ) {
log::trace!("generate_expr_inst: {:?}", inst); log::trace!("generate_expr_inst: {:?}", inst);
match inst { match inst {
&ExprInst::ConstInt { ty, val } => { &ExprInst::ConstInt { ty, val } => {
@@ -790,7 +787,8 @@ impl<'a> Codegen<'a> {
name, name,
ty_name, ty_name,
self.const_int(val, ty) self.const_int(val, ty)
)?; )
.unwrap();
} }
&ExprInst::ConstPrim { ty, val } => { &ExprInst::ConstPrim { ty, val } => {
let value = Value::Expr { let value = Value::Expr {
@@ -807,7 +805,8 @@ impl<'a> Codegen<'a> {
name, name,
ty_name, ty_name,
self.typeenv.syms[val.index()], self.typeenv.syms[val.index()],
)?; )
.unwrap();
} }
&ExprInst::CreateVariant { &ExprInst::CreateVariant {
ref inputs, ref inputs,
@@ -840,17 +839,19 @@ impl<'a> Codegen<'a> {
code, code,
"{}let {} = {};", "{}let {} = {};",
indent, outputname, full_variant_name indent, outputname, full_variant_name
)?; )
.unwrap();
} else { } else {
writeln!( writeln!(
code, code,
"{}let {} = {} {{", "{}let {} = {} {{",
indent, outputname, full_variant_name indent, outputname, full_variant_name
)?; )
.unwrap();
for input_field in input_fields { for input_field in input_fields {
writeln!(code, "{} {},", indent, input_field)?; writeln!(code, "{} {},", indent, input_field).unwrap();
} }
writeln!(code, "{}}};", indent)?; writeln!(code, "{}}};", indent).unwrap();
} }
self.define_val(&output, ctx, /* is_ref = */ false, ty); self.define_val(&output, ctx, /* is_ref = */ false, ty);
} }
@@ -883,7 +884,8 @@ impl<'a> Codegen<'a> {
sig.full_name, sig.full_name,
input_exprs.join(", "), input_exprs.join(", "),
fallible_try, fallible_try,
)?; )
.unwrap();
self.define_val(&output, ctx, /* is_ref = */ false, termdata.ret_ty); self.define_val(&output, ctx, /* is_ref = */ false, termdata.ret_ty);
} }
&ExprInst::Return { &ExprInst::Return {
@@ -893,8 +895,6 @@ impl<'a> Codegen<'a> {
returns.push((index, value_expr)); returns.push((index, value_expr));
} }
} }
Ok(())
} }
fn match_variant_binders( fn match_variant_binders(
@@ -925,12 +925,12 @@ impl<'a> Codegen<'a> {
/// infallible. /// infallible.
fn generate_pattern_inst( fn generate_pattern_inst(
&self, &self,
code: &mut dyn Write, code: &mut String,
id: InstId, id: InstId,
inst: &PatternInst, inst: &PatternInst,
indent: &str, indent: &str,
ctx: &mut BodyContext, ctx: &mut BodyContext,
) -> Result<bool, Error> { ) -> bool {
match inst { match inst {
&PatternInst::Arg { index, ty } => { &PatternInst::Arg { index, ty } => {
let output = Value::Pattern { let output = Value::Pattern {
@@ -942,7 +942,7 @@ impl<'a> Codegen<'a> {
&Type::Primitive(..) => false, &Type::Primitive(..) => false,
_ => true, _ => true,
}; };
writeln!(code, "{}let {} = arg{};", indent, outputname, index)?; writeln!(code, "{}let {} = arg{};", indent, outputname, index).unwrap();
self.define_val( self.define_val(
&Value::Pattern { &Value::Pattern {
inst: id, inst: id,
@@ -952,26 +952,26 @@ impl<'a> Codegen<'a> {
is_ref, is_ref,
ty, ty,
); );
Ok(true) true
} }
&PatternInst::MatchEqual { ref a, ref b, .. } => { &PatternInst::MatchEqual { ref a, ref b, .. } => {
let a = self.value_by_ref(a, ctx); let a = self.value_by_ref(a, ctx);
let b = self.value_by_ref(b, ctx); let b = self.value_by_ref(b, ctx);
writeln!(code, "{}if {} == {} {{", indent, a, b)?; writeln!(code, "{}if {} == {} {{", indent, a, b).unwrap();
Ok(false) false
} }
&PatternInst::MatchInt { &PatternInst::MatchInt {
ref input, int_val, .. ref input, int_val, ..
} => { } => {
let input = self.value_by_val(input, ctx); let input = self.value_by_val(input, ctx);
writeln!(code, "{}if {} == {} {{", indent, input, int_val)?; writeln!(code, "{}if {} == {} {{", indent, input, int_val).unwrap();
Ok(false) false
} }
&PatternInst::MatchPrim { ref input, val, .. } => { &PatternInst::MatchPrim { ref input, val, .. } => {
let input = self.value_by_val(input, ctx); let input = self.value_by_val(input, ctx);
let sym = &self.typeenv.syms[val.index()]; let sym = &self.typeenv.syms[val.index()];
writeln!(code, "{}if {} == {} {{", indent, input, sym)?; writeln!(code, "{}if {} == {} {{", indent, input, sym).unwrap();
Ok(false) false
} }
&PatternInst::MatchVariant { &PatternInst::MatchVariant {
ref input, ref input,
@@ -997,8 +997,9 @@ impl<'a> Codegen<'a> {
code, code,
"{}if let {}::{} {} = {} {{", "{}if let {}::{} {} = {} {{",
indent, ty_name, variantname, args, input indent, ty_name, variantname, args, input
)?; )
Ok(false) .unwrap();
false
} }
&PatternInst::Extract { &PatternInst::Extract {
ref inputs, ref inputs,
@@ -1035,8 +1036,9 @@ impl<'a> Codegen<'a> {
output_binders.join(", "), output_binders.join(", "),
sig.full_name, sig.full_name,
input_values.join(", "), input_values.join(", "),
)?; )
Ok(true) .unwrap();
true
} else { } else {
writeln!( writeln!(
code, code,
@@ -1045,8 +1047,9 @@ impl<'a> Codegen<'a> {
output_binders.join(", "), output_binders.join(", "),
sig.full_name, sig.full_name,
input_values.join(", "), input_values.join(", "),
)?; )
Ok(false) .unwrap();
false
} }
} }
&PatternInst::Expr { &PatternInst::Expr {
@@ -1065,25 +1068,26 @@ impl<'a> Codegen<'a> {
indent, indent,
self.value_name(&output), self.value_name(&output),
self.const_int(val, ty), self.const_int(val, ty),
)?; )
.unwrap();
self.define_val(&output, ctx, /* is_ref = */ false, ty); self.define_val(&output, ctx, /* is_ref = */ false, ty);
Ok(true) true
} }
&PatternInst::Expr { &PatternInst::Expr {
ref seq, output_ty, .. ref seq, output_ty, ..
} => { } => {
let closure_name = format!("closure{}", id.index()); let closure_name = format!("closure{}", id.index());
writeln!(code, "{}let {} = || {{", indent, closure_name)?; writeln!(code, "{}let {} = || {{", indent, closure_name).unwrap();
let subindent = format!("{} ", indent); let subindent = format!("{} ", indent);
let mut subctx = ctx.clone(); let mut subctx = ctx.clone();
let mut returns = vec![]; let mut returns = vec![];
for (id, inst) in seq.insts.iter().enumerate() { for (id, inst) in seq.insts.iter().enumerate() {
let id = InstId(id); let id = InstId(id);
self.generate_expr_inst(code, id, inst, &subindent, &mut subctx, &mut returns)?; self.generate_expr_inst(code, id, inst, &subindent, &mut subctx, &mut returns);
} }
assert_eq!(returns.len(), 1); assert_eq!(returns.len(), 1);
writeln!(code, "{}return Some({});", subindent, returns[0].1)?; writeln!(code, "{}return Some({});", subindent, returns[0].1).unwrap();
writeln!(code, "{}}};", indent)?; writeln!(code, "{}}};", indent).unwrap();
let output = Value::Pattern { let output = Value::Pattern {
inst: id, inst: id,
@@ -1095,22 +1099,23 @@ impl<'a> Codegen<'a> {
indent, indent,
self.value_binder(&output, /* is_ref = */ false, output_ty), self.value_binder(&output, /* is_ref = */ false, output_ty),
closure_name closure_name
)?; )
.unwrap();
self.define_val(&output, ctx, /* is_ref = */ false, output_ty); self.define_val(&output, ctx, /* is_ref = */ false, output_ty);
Ok(false) false
} }
} }
} }
fn generate_body( fn generate_body(
&self, &self,
code: &mut dyn Write, code: &mut String,
depth: usize, depth: usize,
trie: &TrieNode, trie: &TrieNode,
indent: &str, indent: &str,
ctx: &mut BodyContext, ctx: &mut BodyContext,
) -> Result<bool, Error> { ) -> bool {
log::trace!("generate_body: trie {:?}", trie); log::trace!("generate_body: trie {:?}", trie);
let mut returned = false; let mut returned = false;
match trie { match trie {
@@ -1122,16 +1127,17 @@ impl<'a> Codegen<'a> {
"{}// Rule at {}.", "{}// Rule at {}.",
indent, indent,
output.pos.pretty_print_line(&self.typeenv.filenames[..]) output.pos.pretty_print_line(&self.typeenv.filenames[..])
)?; )
.unwrap();
// If this is a leaf node, generate the ExprSequence and return. // If this is a leaf node, generate the ExprSequence and return.
let mut returns = vec![]; let mut returns = vec![];
for (id, inst) in output.insts.iter().enumerate() { for (id, inst) in output.insts.iter().enumerate() {
let id = InstId(id); let id = InstId(id);
self.generate_expr_inst(code, id, inst, indent, ctx, &mut returns)?; self.generate_expr_inst(code, id, inst, indent, ctx, &mut returns);
} }
assert_eq!(returns.len(), 1); assert_eq!(returns.len(), 1);
writeln!(code, "{}return Some({});", indent, returns[0].1)?; writeln!(code, "{}return Some({});", indent, returns[0].1).unwrap();
returned = true; returned = true;
} }
@@ -1181,7 +1187,7 @@ impl<'a> Codegen<'a> {
// a `match` form if there are at least two // a `match` form if there are at least two
// adjacent options. // adjacent options.
if last - i > 1 { if last - i > 1 {
self.generate_body_matches(code, depth, &edges[i..last], indent, ctx)?; self.generate_body_matches(code, depth, &edges[i..last], indent, ctx);
i = last; i = last;
continue; continue;
} else { } else {
@@ -1194,18 +1200,17 @@ impl<'a> Codegen<'a> {
match symbol { match symbol {
&TrieSymbol::EndOfMatch => { &TrieSymbol::EndOfMatch => {
returned = returned = self.generate_body(code, depth + 1, node, indent, ctx);
self.generate_body(code, depth + 1, node, indent, ctx)?;
} }
&TrieSymbol::Match { ref op } => { &TrieSymbol::Match { ref op } => {
let id = InstId(depth); let id = InstId(depth);
let infallible = let infallible =
self.generate_pattern_inst(code, id, op, indent, ctx)?; self.generate_pattern_inst(code, id, op, indent, ctx);
let i = if infallible { indent } else { &subindent[..] }; let i = if infallible { indent } else { &subindent[..] };
let sub_returned = let sub_returned =
self.generate_body(code, depth + 1, node, i, ctx)?; self.generate_body(code, depth + 1, node, i, ctx);
if !infallible { if !infallible {
writeln!(code, "{}}}", indent)?; writeln!(code, "{}}}", indent).unwrap();
} }
if infallible && sub_returned { if infallible && sub_returned {
returned = true; returned = true;
@@ -1218,17 +1223,17 @@ impl<'a> Codegen<'a> {
} }
} }
Ok(returned) returned
} }
fn generate_body_matches( fn generate_body_matches(
&self, &self,
code: &mut dyn Write, code: &mut String,
depth: usize, depth: usize,
edges: &[TrieEdge], edges: &[TrieEdge],
indent: &str, indent: &str,
ctx: &mut BodyContext, ctx: &mut BodyContext,
) -> Result<(), Error> { ) {
let (input, input_ty) = match &edges[0].symbol { let (input, input_ty) = match &edges[0].symbol {
&TrieSymbol::Match { &TrieSymbol::Match {
op: op:
@@ -1254,7 +1259,8 @@ impl<'a> Codegen<'a> {
"{}match {} {{", "{}match {} {{",
indent, indent,
self.value_by_ref(&input, ctx) self.value_by_ref(&input, ctx)
)?; )
.unwrap();
// Emit each case. // Emit each case.
for &TrieEdge { for &TrieEdge {
@@ -1288,18 +1294,17 @@ impl<'a> Codegen<'a> {
code, code,
"{} &{}::{} {} => {{", "{} &{}::{} {} => {{",
indent, input_ty_name, variantname, fields, indent, input_ty_name, variantname, fields,
)?; )
.unwrap();
let subindent = format!("{} ", indent); let subindent = format!("{} ", indent);
self.generate_body(code, depth + 1, node, &subindent, ctx)?; self.generate_body(code, depth + 1, node, &subindent, ctx);
writeln!(code, "{} }}", indent)?; writeln!(code, "{} }}", indent).unwrap();
} }
// Always add a catchall, because we don't do exhaustiveness // Always add a catchall, because we don't do exhaustiveness
// checking on the MatcHVariants. // checking on the MatcHVariants.
writeln!(code, "{} _ => {{}}", indent)?; writeln!(code, "{} _ => {{}}", indent).unwrap();
writeln!(code, "{}}}", indent)?; writeln!(code, "{}}}", indent).unwrap();
Ok(())
} }
} }

View File

@@ -6,6 +6,6 @@ use crate::{ast, codegen, sema};
pub fn compile(defs: &ast::Defs) -> Result<String, Vec<Error>> { pub fn compile(defs: &ast::Defs) -> Result<String, Vec<Error>> {
let mut typeenv = sema::TypeEnv::from_ast(defs)?; let mut typeenv = sema::TypeEnv::from_ast(defs)?;
let termenv = sema::TermEnv::from_ast(&mut typeenv, defs)?; let termenv = sema::TermEnv::from_ast(&mut typeenv, defs)?;
let codegen = codegen::Codegen::compile(&typeenv, &termenv).map_err(|e| vec![e])?; let codegen = codegen::Codegen::compile(&typeenv, &termenv);
codegen.generate_rust().map_err(|e| vec![e]) Ok(codegen.generate_rust())
} }