use crate::ast::*;
use crate::errors::ErrorCtx;
use crate::formatter::{FmtCtx, IntoFormatter};
use crate::ids::Vector;
use crate::llbc_ast;
use crate::name_matcher::NamePattern;
use crate::pretty::FmtWithCtx;
use crate::ullbc_ast;
use std::fmt;
pub struct TransformOptions {
pub no_code_duplication: bool,
pub hide_marker_traits: bool,
pub no_merge_goto_chains: bool,
pub item_opacities: Vec<(NamePattern, ItemOpacity)>,
}
pub struct TransformCtx<'ctx> {
pub options: TransformOptions,
pub translated: TranslatedCrate,
pub errors: ErrorCtx<'ctx>,
}
pub trait UllbcPass: Sync {
fn transform_body(&self, _ctx: &mut TransformCtx<'_>, _body: &mut ullbc_ast::ExprBody) {}
fn transform_function(
&self,
ctx: &mut TransformCtx<'_>,
_decl: &mut FunDecl,
body: Result<&mut ullbc_ast::ExprBody, Opaque>,
) {
if let Ok(body) = body {
self.transform_body(ctx, body)
}
}
fn transform_global(
&self,
ctx: &mut TransformCtx<'_>,
_decl: &mut GlobalDecl,
body: Result<&mut ullbc_ast::ExprBody, Opaque>,
) {
if let Ok(body) = body {
self.transform_body(ctx, body)
}
}
fn transform_ctx(&self, ctx: &mut TransformCtx<'_>) {
ctx.for_each_fun_decl(|ctx, decl, body| {
let body = body.map(|body| body.as_unstructured_mut().unwrap());
self.log_before_body(ctx, &decl.item_meta.name, body.as_deref());
self.transform_function(ctx, decl, body);
});
ctx.for_each_global_decl(|ctx, decl, body| {
let body = body.map(|body| body.as_unstructured_mut().unwrap());
self.log_before_body(ctx, &decl.item_meta.name, body.as_deref());
self.transform_global(ctx, decl, body);
});
}
fn name(&self) -> &str {
std::any::type_name::<Self>()
}
fn log_before_body(
&self,
ctx: &TransformCtx<'_>,
name: &Name,
body: Result<&ullbc_ast::ExprBody, &Opaque>,
) {
let fmt_ctx = &ctx.into_fmt();
let body_str = if let Ok(body) = body {
body.fmt_with_ctx(fmt_ctx)
} else {
"<opaque>".to_owned()
};
trace!(
"# About to run pass [{}] on `{}`:\n{}",
self.name(),
name.with_ctx(fmt_ctx),
body_str,
);
}
}
pub trait LlbcPass: Sync {
fn transform_body(&self, _ctx: &mut TransformCtx<'_>, _body: &mut llbc_ast::ExprBody) {}
fn transform_function(
&self,
ctx: &mut TransformCtx<'_>,
_decl: &mut FunDecl,
body: Result<&mut llbc_ast::ExprBody, Opaque>,
) {
if let Ok(body) = body {
self.transform_body(ctx, body)
}
}
fn transform_global(
&self,
ctx: &mut TransformCtx<'_>,
_decl: &mut GlobalDecl,
body: Result<&mut llbc_ast::ExprBody, Opaque>,
) {
if let Ok(body) = body {
self.transform_body(ctx, body)
}
}
fn transform_ctx(&self, ctx: &mut TransformCtx<'_>) {
ctx.for_each_fun_decl(|ctx, decl, body| {
let body = body.map(|body| body.as_structured_mut().unwrap());
self.log_before_body(ctx, &decl.item_meta.name, body.as_deref());
self.transform_function(ctx, decl, body);
});
ctx.for_each_global_decl(|ctx, decl, body| {
let body = body.map(|body| body.as_structured_mut().unwrap());
self.log_before_body(ctx, &decl.item_meta.name, body.as_deref());
self.transform_global(ctx, decl, body);
});
}
fn name(&self) -> &str {
std::any::type_name::<Self>()
}
fn log_before_body(
&self,
ctx: &TransformCtx<'_>,
name: &Name,
body: Result<&llbc_ast::ExprBody, &Opaque>,
) {
let fmt_ctx = &ctx.into_fmt();
let body_str = if let Ok(body) = body {
body.fmt_with_ctx(fmt_ctx)
} else {
"<opaque>".to_owned()
};
trace!(
"# About to run pass [{}] on `{}`:\n{}",
self.name(),
name.with_ctx(fmt_ctx),
body_str,
);
}
}
pub trait TransformPass: Sync {
fn transform_ctx(&self, ctx: &mut TransformCtx<'_>);
fn name(&self) -> &str {
std::any::type_name::<Self>()
}
}
impl<'ctx> TransformCtx<'ctx> {
pub(crate) fn continue_on_failure(&self) -> bool {
self.errors.continue_on_failure()
}
pub(crate) fn has_errors(&self) -> bool {
self.errors.has_errors()
}
pub(crate) fn span_err(&mut self, span: Span, msg: &str) {
self.errors.span_err(span, msg)
}
pub(crate) fn with_def_id<F, T>(
&mut self,
def_id: impl Into<AnyTransId>,
def_id_is_local: bool,
f: F,
) -> T
where
F: FnOnce(&mut Self) -> T,
{
let current_def_id = self.errors.def_id;
let current_def_id_is_local = self.errors.def_id_is_local;
self.errors.def_id = Some(def_id.into());
self.errors.def_id_is_local = def_id_is_local;
let ret = f(self);
self.errors.def_id = current_def_id;
self.errors.def_id_is_local = current_def_id_is_local;
ret
}
pub(crate) fn with_mut_bodies<R>(
&mut self,
f: impl FnOnce(&mut Self, &mut Vector<BodyId, Body>) -> R,
) -> R {
let mut bodies = std::mem::take(&mut self.translated.bodies);
let ret = f(self, &mut bodies);
self.translated.bodies = bodies;
ret
}
pub(crate) fn with_mut_fun_decls<R>(
&mut self,
f: impl FnOnce(&mut Self, &mut Vector<FunDeclId, FunDecl>) -> R,
) -> R {
let mut fun_decls = std::mem::take(&mut self.translated.fun_decls);
let ret = f(self, &mut fun_decls);
self.translated.fun_decls = fun_decls;
ret
}
pub(crate) fn with_mut_global_decls<R>(
&mut self,
f: impl FnOnce(&mut Self, &mut Vector<GlobalDeclId, GlobalDecl>) -> R,
) -> R {
let mut global_decls = std::mem::take(&mut self.translated.global_decls);
let ret = f(self, &mut global_decls);
self.translated.global_decls = global_decls;
ret
}
pub(crate) fn for_each_body(&mut self, mut f: impl FnMut(&mut Self, &mut Body)) {
self.with_mut_bodies(|ctx, bodies| {
for body in bodies {
f(ctx, body)
}
})
}
pub(crate) fn for_each_structured_body(
&mut self,
mut f: impl FnMut(&mut Self, &mut llbc_ast::ExprBody),
) {
self.for_each_body(|ctx, body| f(ctx, body.as_structured_mut().unwrap()))
}
pub(crate) fn for_each_fun_decl(
&mut self,
mut f: impl FnMut(&mut Self, &mut FunDecl, Result<&mut Body, Opaque>),
) {
self.with_mut_bodies(|ctx, bodies| {
ctx.with_mut_fun_decls(|ctx, decls| {
for decl in decls.iter_mut() {
let body = match decl.body {
Ok(id) => {
match bodies.get_mut(id) {
Some(body) => Ok(body),
None => continue,
}
}
Err(Opaque) => Err(Opaque),
};
ctx.with_def_id(decl.def_id, decl.item_meta.is_local, |ctx| {
f(ctx, decl, body);
})
}
})
})
}
pub(crate) fn for_each_global_decl(
&mut self,
mut f: impl FnMut(&mut Self, &mut GlobalDecl, Result<&mut Body, Opaque>),
) {
self.with_mut_bodies(|ctx, bodies| {
ctx.with_mut_global_decls(|ctx, decls| {
for decl in decls.iter_mut() {
let body = match decl.body {
Ok(id) => {
match bodies.get_mut(id) {
Some(body) => Ok(body),
None => continue,
}
}
Err(Opaque) => Err(Opaque),
};
ctx.with_def_id(decl.def_id, decl.item_meta.is_local, |ctx| {
f(ctx, decl, body);
})
}
})
})
}
}
impl<'a> IntoFormatter for &'a TransformCtx<'_> {
type C = FmtCtx<'a>;
fn into_fmt(self) -> Self::C {
self.translated.into_fmt()
}
}
impl fmt::Display for TransformCtx<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.translated.fmt(f)
}
}