pub mod map_adapter;
use crate::common::error::ErrorGen;
use crate::emitter::memory_allocator::MemoryAllocator;
use crate::emitter::InjectStrategy;
use crate::generator::ast::{AstVisitor, Metadata, Probe, Script, WhammParam};
use crate::lang_features::libraries::core::maps::map_adapter::MapLibAdapter;
use crate::lang_features::libraries::core::utils::utils_adapter::UtilsAdapter;
use crate::lang_features::libraries::core::{LibAdapter, LibPackage};
use crate::parser::types::{Block, DataType, Expr, Statement};
use log::debug;
use wirm::ir::id::FunctionID;
use wirm::Module;
pub struct MapLibPackage {
strategy: InjectStrategy,
is_used: bool,
pub used_in_global_scope: bool,
pub adapter: MapLibAdapter,
}
impl MapLibPackage {
pub fn new(strategy: InjectStrategy) -> Self {
Self {
strategy,
is_used: false,
used_in_global_scope: false,
adapter: MapLibAdapter::default(),
}
}
}
impl LibPackage for MapLibPackage {
fn is_used(&self) -> bool {
self.is_used
}
fn is_used_in_global_scope(&self) -> bool {
self.used_in_global_scope
}
fn import_memory(&self) -> bool {
true
}
fn set_lib_mem_id(&mut self, mem_id: i32) {
self.adapter.lib_mem = mem_id;
}
fn set_instr_mem_id(&mut self, mem_id: i32) {
self.adapter.instr_mem = mem_id;
}
fn get_adapter(&self) -> &dyn LibAdapter {
&self.adapter
}
fn get_adapter_mut(&mut self) -> &mut dyn LibAdapter {
&mut self.adapter
}
fn set_adapter_usage(&mut self, is_used: bool) {
self.adapter.is_used = is_used;
}
fn set_global_adapter_usage(&mut self, is_used: bool) {
self.adapter.used_in_global_scope = is_used;
}
fn define_helper_funcs(
&mut self,
utils: &UtilsAdapter,
mem_allocator: &mut MemoryAllocator,
app_wasm: &mut Module,
err: &mut ErrorGen,
) -> Vec<FunctionID> {
self.adapter
.define_helper_funcs(utils, mem_allocator, app_wasm, err)
}
}
impl AstVisitor<bool> for MapLibPackage {
fn visit_ast(&mut self, ast: &[Script]) -> bool {
for script in ast.iter() {
self.is_used |= self.visit_script(script);
if self.is_used {
return true;
}
}
self.is_used
}
fn visit_script(&mut self, script: &Script) -> bool {
for f in script.fns.iter() {
if self.visit_fn(f) {
return true;
}
}
for (name, global) in script.globals.iter() {
if let DataType::Map { .. } = global.ty {
debug!("{name} is a map!");
self.used_in_global_scope = true;
return true;
}
}
for stmt in script.global_stmts.iter() {
if self.visit_stmt(stmt) {
self.used_in_global_scope = true;
return true;
}
}
let mut has_maps = false;
for probe in script.probes.iter() {
has_maps |= self.visit_probe(probe);
}
has_maps
}
fn visit_probe(&mut self, probe: &Probe) -> bool {
let mut has_maps = self.visit_metadata(&probe.metadata);
if let Some(body) = &probe.body {
for stmt in body.stmts.iter() {
has_maps |= self.visit_stmt(stmt);
}
}
has_maps
}
fn visit_metadata(&mut self, metadata: &Metadata) -> bool {
for param in metadata.pred_args.params.iter() {
if self.visit_whamm_param(param) {
return true;
}
}
for param in metadata.body_args.params.iter() {
if self.visit_whamm_param(param) {
return true;
}
}
false
}
fn visit_whamm_param(&mut self, param: &WhammParam) -> bool {
self.visit_datatype(¶m.ty)
}
fn visit_fn(&mut self, f: &crate::parser::types::Fn) -> bool {
for param in f.params.iter() {
if self.visit_formal_param(param) {
return true;
}
}
if self.visit_datatype(&f.results) {
return true;
}
if self.visit_block(&f.body) {
return true;
}
false
}
fn visit_formal_param(&mut self, param: &(Expr, DataType)) -> bool {
if self.visit_datatype(¶m.1) {
return true;
}
false
}
fn visit_block(&mut self, block: &Block) -> bool {
let mut has_maps = false;
for stmt in &block.stmts {
has_maps |= self.visit_stmt(stmt);
}
has_maps
}
fn visit_stmt(&mut self, stmt: &Statement) -> bool {
match stmt {
Statement::Decl {
ty: DataType::Map { .. },
var_id,
..
} => {
if let Expr::VarId { name, .. } = var_id {
debug!("{name} is a map!");
}
true
}
Statement::UnsharedDecl { decl, .. } => {
if let Statement::Decl {
ty: DataType::Map { .. },
var_id,
..
} = &**decl
{
if let Expr::VarId { name, .. } = var_id {
debug!("{name} is a map!");
}
if matches!(self.strategy, InjectStrategy::Rewriting) {
self.used_in_global_scope = true;
}
true
} else {
false
}
}
_ => false,
}
}
fn visit_datatype(&mut self, datatype: &DataType) -> bool {
if let DataType::Map { .. } = datatype {
return true;
}
false
}
}