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:
committed by
Chris Fallin
parent
3535f82056
commit
972dc00a92
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user