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.
|
//! 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(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user