use std::cell::{Cell, RefCell};
use std::ops::ControlFlow;
use crate::pattern::BitConstraint;
use crate::semantic::display::Display;
use crate::semantic::pattern::PatternLen;
use crate::semantic::table::Constructor as FinalConstructor;
use crate::semantic::{Sleigh as FinalSleigh, Table as FinalTable, TableId};
use crate::table::{ConstructorId, Matcher, VariantId};
use crate::{syntax, ExecutionError, PatternError, SleighError, Span, TableError};
use super::disassembly;
use super::execution::{Execution, ExecutionBuilder, FieldSize, FieldSizeMut, TableExportType};
use super::pattern::{Pattern, PatternWalker};
use super::with_block::WithBlockCurrent;
use super::{GlobalScope, Sleigh, SolverStatus};
pub mod execution;
#[derive(Clone)]
pub struct Table {
pub is_root: bool,
pub name: String,
pub constructors: RefCell<Vec<Constructor>>,
pub export: RefCell<Option<TableExportType>>,
pub pattern_recursion_checked: RefCell<bool>,
pub pattern_len: Cell<Option<PatternLen>>,
}
impl std::fmt::Debug for Table {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Table returning: {:?}", self.export)
}
}
fn is_first_then(
constructors: &[FinalConstructor],
matcher_a: Matcher,
matcher_b: Matcher,
) -> bool {
let constructor_a = &constructors[matcher_a.constructor.0];
let constructor_b = &constructors[matcher_b.constructor.0];
let pattern_len_a = constructor_a.pattern.bits_produced();
let pattern_len_b = constructor_b.pattern.bits_produced();
let pattern_len_max = pattern_len_a.max(pattern_len_b);
let extend_len_a = pattern_len_max - pattern_len_a;
let extend_len_b = pattern_len_max - pattern_len_b;
fn produce_iter(
constructor: &FinalConstructor,
variant: VariantId,
extend: usize,
) -> impl Iterator<Item = BitConstraint> + '_ {
let context_bits = &constructor.variants_bits[variant.0].1;
let token_bits = &constructor.variants_bits[variant.0].2;
context_bits
.iter()
.chain(token_bits.iter())
.cloned()
.chain((0..extend).map(|_| BitConstraint::Unrestrained))
}
let bits_a = produce_iter(constructor_a, matcher_a.variant_id, extend_len_a);
let bits_b = produce_iter(constructor_b, matcher_b.variant_id, extend_len_b);
use BitConstraint::*;
bits_a.zip(bits_b).all(|(x, y)| {
match (x, y) {
(Defined(x), Defined(y)) if x == y => true,
(Unrestrained, Unrestrained)
| (Defined(_), Unrestrained)
| (Restrained, Unrestrained) => true,
(Defined(_), Defined(_)) => false,
(Defined(_), Restrained) | (Restrained, Defined(_)) | (Restrained, Restrained) => false,
(Unrestrained, Restrained) | (Unrestrained, Defined(_)) => false,
}
})
}
impl Table {
pub fn new_empty(is_root: bool, name: String) -> Self {
Self {
is_root,
name,
constructors: RefCell::new(vec![]),
export: RefCell::new(None),
pattern_recursion_checked: RefCell::new(false),
pattern_len: Cell::default(),
}
}
pub fn is_root(&self) -> bool {
self.is_root
}
pub fn add_constructor(&mut self, constructor: Constructor) -> Result<(), Box<SleighError>> {
if let Some(execution) = constructor.execution() {
let mut export = self.export.borrow_mut();
if let Some(export) = export.as_mut() {
*export = export.combine(execution.return_value).ok_or_else(|| {
Box::new(SleighError::new_table(
constructor.src.clone(),
ExecutionError::InvalidExport,
))
})?;
} else {
*export = Some(execution.return_value);
}
}
self.constructors.borrow_mut().push(constructor);
Ok(())
}
pub fn pattern_indirect_recursion(
&self,
sleigh: &Sleigh,
me: TableId,
) -> ControlFlow<Vec<TableId>> {
struct FindIndirectRecursion<'a>(&'a Sleigh, TableId);
impl<'a> PatternWalker<Vec<TableId>> for FindIndirectRecursion<'a> {
fn table(&mut self, table: TableId) -> ControlFlow<Vec<TableId>> {
if table == self.1 {
return ControlFlow::Continue(());
}
self.0
.table(table)
.pattern_indirect_recursion(self.0, table)
}
}
let mut checked = if let Ok(checked) = self.pattern_recursion_checked.try_borrow_mut() {
if *checked {
return ControlFlow::Continue(());
}
checked
} else {
return ControlFlow::Break(vec![me]);
};
let mut find = FindIndirectRecursion(sleigh, me);
let constructors = self.constructors.borrow();
for constructor in constructors.iter() {
find.pattern(&constructor.pattern)?;
}
*checked = true;
ControlFlow::Continue(())
}
pub fn pattern_len(&self) -> Option<PatternLen> {
self.pattern_len.get()
}
fn solve_pattern_len<T>(&self, sleigh: &Sleigh, solved: &mut T) -> Result<(), Box<SleighError>>
where
T: SolverStatus + Default,
{
self.constructors
.borrow_mut()
.iter_mut()
.try_for_each(|constructor| constructor.solve_pattern(sleigh, solved).map(|_| ()))?;
if self.pattern_len.get().is_some() {
return Ok(());
};
let constructors = self.constructors.borrow();
let lens: Result<Vec<_>, &Span> = constructors
.iter()
.map(|constructor| constructor.pattern.len.ok_or_else(|| constructor.src()))
.collect();
let lens: Vec<_> = match lens {
Ok(lens) => lens,
Err(src) => {
solved.iam_not_finished(src, file!(), line!());
return Ok(());
}
};
let min = lens.iter().filter_map(|len| len.min()).min();
let mut iter = lens.iter().map(|len| len.max());
let max = iter
.next()
.unwrap()
.and_then(|first| iter.try_fold(first, |acc, len| len.map(|len| len.max(acc))));
match (min, max) {
(None, Some(_)) => unreachable!(),
(None, None) => {
panic!("Table is composed exclusivelly of recursive patterns");
}
(Some(min), None) => {
self.pattern_len.set(Some(PatternLen::Min(min)));
solved.i_did_a_thing();
}
(Some(min), Some(max)) => {
let len = PatternLen::new(min, max);
self.pattern_len.set(Some(len));
solved.i_did_a_thing();
}
}
Ok(())
}
pub fn solve<T>(&self, sleigh: &Sleigh, solved: &mut T) -> Result<(), Box<SleighError>>
where
T: SolverStatus + Default,
{
if self.constructors.borrow().is_empty() {
return Ok(());
}
self.solve_pattern_len(sleigh, solved)?;
self.constructors
.borrow_mut()
.iter_mut()
.try_for_each(|constructor| constructor.solve_execution(sleigh, solved))?;
let mut export = self.export.borrow_mut();
let Some(export_size) = export.as_mut().and_then(|x| x.size_mut()) else {
return Ok(());
};
let mut inputs: Vec<FieldSize> = self
.constructors
.borrow()
.iter()
.filter_map(|con| con.execution())
.map(|exe| exe.return_value.size().unwrap().clone())
.collect();
let modified = super::execution::len::n_generate_a(inputs.as_mut_slice(), export_size)
.ok_or_else(|| SleighError::TableUnsolvable(self.name.clone()))?;
if modified {
solved.i_did_a_thing();
let mut constructors = self.constructors.borrow_mut();
let execs = constructors
.iter_mut()
.filter_map(|con| con.execution_mut());
for (new_size, exe) in inputs.into_iter().zip(execs) {
let old_size = exe.return_value.size_mut().unwrap();
*old_size = new_size;
}
}
if export_size.is_undefined() {
for constructor in self.constructors.borrow().iter() {
solved.iam_not_finished(&constructor.src, file!(), line!());
}
}
Ok(())
}
pub fn convert(self, sleigh: &FinalSleigh) -> FinalTable {
let constructors: Box<[_]> = self
.constructors
.take()
.into_iter()
.map(|constructor| constructor.convert(sleigh))
.collect();
let matchers_num = constructors.iter().map(|c| c.variants_bits.len()).sum();
let mut matcher_order = Vec::with_capacity(matchers_num);
let matcher_a_iter = constructors.iter().enumerate().flat_map(|(i, c)| {
c.variants().map(move |x| Matcher {
constructor: ConstructorId(i),
variant_id: x.0,
})
});
for matcher_a in matcher_a_iter {
let pos = matcher_order
.iter()
.position(|matcher_b| is_first_then(&constructors, matcher_a, *matcher_b));
if let Some(pos) = pos {
matcher_order.insert(pos, matcher_a);
} else {
matcher_order.push(matcher_a);
}
}
FinalTable {
is_root: self.is_root,
constructors,
export: self
.export
.borrow()
.unwrap_or(TableExportType::None)
.convert(),
pattern_len: self.pattern_len.get().unwrap(),
name: self.name.into(),
matcher_order: matcher_order.into(),
}
}
}
impl FieldSizeMut for &Table {
fn get(&self) -> FieldSize {
match self.export.borrow().as_ref().and_then(|x| x.size()) {
Some(size) => *size,
None => FieldSize::default(),
}
}
fn set(&mut self, size: FieldSize) -> Option<bool> {
let mut self_export = self.export.borrow_mut();
let Some(export) = self_export.as_mut() else {
return Some(false);
};
let Some(self_ref) = export.size_mut() else {
return Some(false);
};
let modify = *self_ref != size;
if modify {
let _ = std::mem::replace(self_ref, size);
}
Some(modify)
}
}
#[derive(Clone, Debug)]
pub struct Constructor {
pub display: Display,
pub pattern: Pattern,
pub execution: Option<Execution>,
src: Span,
}
impl Constructor {
pub fn new(
display: Display,
pattern: Pattern,
execution: Option<Execution>,
src: Span,
) -> Self {
Self {
display,
pattern,
execution,
src,
}
}
pub fn execution(&self) -> Option<&Execution> {
self.execution.as_ref()
}
pub fn execution_mut(&mut self) -> Option<&mut Execution> {
self.execution.as_mut()
}
pub fn src(&self) -> &Span {
&self.src
}
pub fn solve_pattern<T>(
&mut self,
sleigh: &Sleigh,
solved: &mut T,
) -> Result<bool, Box<SleighError>>
where
T: SolverStatus + Default,
{
self.pattern
.calculate_len(sleigh, solved)
.map_err(|e| Box::new(SleighError::new_table(self.src.clone(), *e)))
}
pub fn solve_execution<T>(
&mut self,
sleigh: &Sleigh,
solved: &mut T,
) -> Result<(), Box<SleighError>>
where
T: SolverStatus + Default,
{
if let Some(execution) = &mut self.execution {
execution
.solve(sleigh, solved)
.map_err(|e| SleighError::new_table(self.src.clone(), *e))?
}
Ok(())
}
pub fn convert(mut self, sleigh: &FinalSleigh) -> FinalConstructor {
self.pattern.calculate_bits(0);
let pattern = self.pattern.convert();
let execution = self.execution.map(|x| x.convert());
let src = self.src;
let variants_bits = pattern
.pattern_bits_variants(sleigh)
.map(|(i, c, v)| (VariantId(i), c.into(), v.into()))
.collect();
FinalConstructor {
pattern,
display: self.display,
execution,
location: src,
variants_bits,
}
}
}
impl Sleigh {
pub(crate) fn insert_table_constructor(
&mut self,
with_block_current: &mut WithBlockCurrent,
constructor: syntax::block::table::Constructor,
) -> Result<(), Box<SleighError>> {
let table_name = with_block_current.table_name(constructor.table_name());
let table_id = self.get_table_or_create_empty(table_name, &constructor.src)?;
let pattern = with_block_current.pattern(&constructor.pattern);
let mut pattern = Pattern::new(self, pattern, table_id)
.map_err(|e| Box::new(SleighError::new_table(constructor.src.clone(), *e)))?;
pattern
.unresolved_token_fields(self)
.try_for_each(|(token_field, location)| {
let token_produced = pattern
.produce_token_field(self, token_field)
.map_err(|e| Box::new(SleighError::new_table(constructor.src.clone(), *e)))?;
if token_produced.is_none() {
return Err(Box::new(SleighError::new_table(
constructor.src.clone(),
PatternError::MissingRef(location),
)));
}
Ok(())
})?;
let disassembly_raw = with_block_current.disassembly(constructor.disassembly);
if let Some(disassembly_raw) = disassembly_raw {
disassembly::Builder::new(self, &mut pattern)
.build(disassembly_raw)
.map_err(|e| Box::new(SleighError::new_table(constructor.src.clone(), *e)))?;
}
let is_root = self.instruction_table == table_id;
let display = self
.new_display(constructor.display, &mut pattern, is_root)
.map_err(|e| Box::new(SleighError::new_table(constructor.src.clone(), *e)))?;
let execution = constructor
.execution
.map(|x| -> Result<Execution, Box<ExecutionError>> {
let mut execution =
execution::Builder::new(self, &mut pattern, constructor.src.clone());
execution.extend(x)?;
Ok(execution.into())
})
.transpose()
.map_err(|e| Box::new(SleighError::new_table(constructor.src.clone(), *e)))?;
let constructor = Constructor::new(display, pattern, execution, constructor.src);
let table = self.table_mut(table_id);
table.add_constructor(constructor)?;
Ok(())
}
pub fn get_table_or_create_empty(
&mut self,
name: &str,
location: &Span,
) -> Result<TableId, Box<SleighError>> {
match self.global_scope.get(name) {
Some(GlobalScope::Table(id)) => Ok(*id),
Some(_) => Err(Box::new(SleighError::new_table(
location.clone(),
TableError::TableNameInvalid,
))),
None => {
let table = Table::new_empty(false, name.to_owned());
self.tables.push(table);
let table_id = TableId(self.tables.len() - 1);
self.global_scope
.insert(name.to_owned(), GlobalScope::Table(table_id));
Ok(table_id)
}
}
}
}