charon_lib/transform/
ctx.rsuse crate::ast::*;
use crate::errors::ErrorCtx;
use crate::formatter::{FmtCtx, IntoFormatter};
use crate::llbc_ast;
use crate::name_matcher::NamePattern;
use crate::pretty::FmtWithCtx;
use crate::ullbc_ast;
use std::cell::RefCell;
use std::{fmt, mem};
pub struct TransformOptions {
pub no_code_duplication: bool,
pub hide_marker_traits: bool,
pub no_merge_goto_chains: bool,
pub print_built_llbc: bool,
pub item_opacities: Vec<(NamePattern, ItemOpacity)>,
}
pub struct TransformCtx {
pub options: TransformOptions,
pub translated: TranslatedCrate,
pub errors: RefCell<ErrorCtx>,
}
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) {
if let Ok(body) = &mut decl.body {
self.transform_body(ctx, body.as_unstructured_mut().unwrap())
}
}
fn transform_ctx(&self, ctx: &mut TransformCtx) {
ctx.for_each_fun_decl(|ctx, decl| {
let body = decl
.body
.as_mut()
.map(|body| body.as_unstructured_mut().unwrap())
.map_err(|opaque| *opaque);
self.log_before_body(ctx, &decl.item_meta.name, body.as_deref());
self.transform_function(ctx, decl);
});
}
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) {
if let Ok(body) = &mut decl.body {
self.transform_body(ctx, body.as_structured_mut().unwrap())
}
}
fn transform_ctx(&self, ctx: &mut TransformCtx) {
ctx.for_each_fun_decl(|ctx, decl| {
let body = decl
.body
.as_mut()
.map(|body| body.as_structured_mut().unwrap())
.map_err(|opaque| *opaque);
self.log_before_body(ctx, &decl.item_meta.name, body.as_deref());
self.transform_function(ctx, decl);
});
}
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 {
pub(crate) fn has_errors(&self) -> bool {
self.errors.borrow().has_errors()
}
pub(crate) fn span_err(&self, span: Span, msg: &str) -> Error {
self.errors
.borrow_mut()
.span_err(&self.translated, 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 mut errors = self.errors.borrow_mut();
let current_def_id = mem::replace(&mut errors.def_id, Some(def_id.into()));
let current_def_id_is_local = mem::replace(&mut errors.def_id_is_local, def_id_is_local);
drop(errors); let ret = f(self);
let mut errors = self.errors.borrow_mut();
errors.def_id = current_def_id;
errors.def_id_is_local = current_def_id_is_local;
ret
}
pub(crate) fn for_each_body(&mut self, mut f: impl FnMut(&mut Self, &mut Body)) {
let fn_ids = self.translated.fun_decls.all_indices();
for id in fn_ids {
if let Some(decl) = self.translated.fun_decls.get_mut(id) {
if let Ok(mut body) = mem::replace(&mut decl.body, Err(Opaque)) {
let fun_decl_id = decl.def_id;
let is_local = decl.item_meta.is_local;
self.with_def_id(fun_decl_id, is_local, |ctx| f(ctx, &mut body));
self.translated.fun_decls[id].body = Ok(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)) {
let fn_ids = self.translated.fun_decls.all_indices();
for id in fn_ids {
if let Some(mut decl) = self.translated.fun_decls.remove(id) {
let fun_decl_id = decl.def_id;
let is_local = decl.item_meta.is_local;
self.with_def_id(fun_decl_id, is_local, |ctx| f(ctx, &mut decl));
self.translated.fun_decls.set_slot(id, decl);
}
}
}
}
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)
}
}