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

View File

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