use std::convert::TryFrom;
use std::fmt::Display;
use std::num::NonZeroU32;
use controlled_option::ControlledOption;
use controlled_option::Niche;
use enumset::EnumSetType;
use smallvec::SmallVec;
use crate::arena::Deque;
use crate::arena::DequeArena;
use crate::arena::Handle;
use crate::graph::Edge;
use crate::graph::Node;
use crate::graph::NodeID;
use crate::graph::StackGraph;
use crate::graph::Symbol;
use crate::paths::PathResolutionError;
use crate::utils::cmp_option;
use crate::utils::equals_option;
trait DisplayWithPartialPaths {
fn prepare(&mut self, _graph: &StackGraph, _partials: &mut PartialPaths) {}
fn display_with(
&self,
graph: &StackGraph,
partials: &PartialPaths,
f: &mut std::fmt::Formatter,
) -> std::fmt::Result;
}
fn display_with<'a, D>(
mut value: D,
graph: &'a StackGraph,
partials: &'a mut PartialPaths,
) -> impl Display + 'a
where
D: DisplayWithPartialPaths + 'a,
{
value.prepare(graph, partials);
DisplayWithPartialPathsWrapper {
value,
graph,
partials,
}
}
fn display_prepared<'a, D>(
value: D,
graph: &'a StackGraph,
partials: &'a PartialPaths,
) -> impl Display + 'a
where
D: DisplayWithPartialPaths + 'a,
{
DisplayWithPartialPathsWrapper {
value,
graph,
partials,
}
}
#[doc(hidden)]
struct DisplayWithPartialPathsWrapper<'a, D> {
value: D,
graph: &'a StackGraph,
partials: &'a PartialPaths,
}
impl<'a, D> Display for DisplayWithPartialPathsWrapper<'a, D>
where
D: DisplayWithPartialPaths,
{
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
self.value.display_with(self.graph, self.partials, f)
}
}
#[repr(transparent)]
#[derive(Clone, Copy, Debug, Eq, Hash, Niche, Ord, PartialEq, PartialOrd)]
pub struct SymbolStackVariable(#[niche] NonZeroU32);
impl SymbolStackVariable {
pub fn new(variable: u32) -> Option<SymbolStackVariable> {
NonZeroU32::new(variable).map(SymbolStackVariable)
}
pub(crate) fn initial() -> SymbolStackVariable {
SymbolStackVariable(unsafe { NonZeroU32::new_unchecked(1) })
}
pub fn with_offset(self, symbol_variable_offset: u32) -> SymbolStackVariable {
let offset_value = self.0.get() + symbol_variable_offset;
SymbolStackVariable(unsafe { NonZeroU32::new_unchecked(offset_value) })
}
pub(crate) fn as_u32(self) -> u32 {
self.0.get()
}
fn as_usize(self) -> usize {
self.0.get() as usize
}
}
impl Display for SymbolStackVariable {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "%{}", self.0.get())
}
}
impl From<NonZeroU32> for SymbolStackVariable {
fn from(value: NonZeroU32) -> SymbolStackVariable {
SymbolStackVariable(value)
}
}
impl Into<u32> for SymbolStackVariable {
fn into(self) -> u32 {
self.0.get()
}
}
impl TryFrom<u32> for SymbolStackVariable {
type Error = ();
fn try_from(value: u32) -> Result<SymbolStackVariable, ()> {
let value = NonZeroU32::new(value).ok_or(())?;
Ok(SymbolStackVariable(value))
}
}
#[repr(transparent)]
#[derive(Clone, Copy, Debug, Eq, Hash, Niche, Ord, PartialEq, PartialOrd)]
pub struct ScopeStackVariable(#[niche] NonZeroU32);
impl ScopeStackVariable {
pub fn new(variable: u32) -> Option<ScopeStackVariable> {
NonZeroU32::new(variable).map(ScopeStackVariable)
}
fn initial() -> ScopeStackVariable {
ScopeStackVariable(unsafe { NonZeroU32::new_unchecked(1) })
}
fn fresher_than(max_used: u32) -> ScopeStackVariable {
ScopeStackVariable(unsafe { NonZeroU32::new_unchecked(max_used + 1) })
}
pub fn with_offset(self, scope_variable_offset: u32) -> ScopeStackVariable {
let offset_value = self.0.get() + scope_variable_offset;
ScopeStackVariable(unsafe { NonZeroU32::new_unchecked(offset_value) })
}
pub(crate) fn as_u32(self) -> u32 {
self.0.get()
}
fn as_usize(self) -> usize {
self.0.get() as usize
}
}
impl Display for ScopeStackVariable {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "${}", self.0.get())
}
}
impl From<NonZeroU32> for ScopeStackVariable {
fn from(value: NonZeroU32) -> ScopeStackVariable {
ScopeStackVariable(value)
}
}
impl Into<u32> for ScopeStackVariable {
fn into(self) -> u32 {
self.0.get()
}
}
impl TryFrom<u32> for ScopeStackVariable {
type Error = ();
fn try_from(value: u32) -> Result<ScopeStackVariable, ()> {
let value = NonZeroU32::new(value).ok_or(())?;
Ok(ScopeStackVariable(value))
}
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct PartialScopedSymbol {
pub symbol: Handle<Symbol>,
pub scopes: ControlledOption<PartialScopeStack>,
}
impl PartialScopedSymbol {
pub fn with_offset(mut self, scope_variable_offset: u32) -> PartialScopedSymbol {
let scopes = self
.scopes
.into_option()
.map(|stack| stack.with_offset(scope_variable_offset));
self.scopes = ControlledOption::from_option(scopes);
self
}
pub fn unify(
&mut self,
partials: &mut PartialPaths,
rhs: PartialScopedSymbol,
scope_bindings: &mut PartialScopeStackBindings,
) -> Result<(), PathResolutionError> {
if self.symbol != rhs.symbol {
return Err(PathResolutionError::SymbolStackUnsatisfied);
}
match (self.scopes.into_option(), rhs.scopes.into_option()) {
(Some(lhs), Some(rhs)) => {
let unified = lhs.unify(partials, rhs, scope_bindings)?;
self.scopes = ControlledOption::some(unified);
}
(None, None) => {}
_ => return Err(PathResolutionError::SymbolStackUnsatisfied),
}
Ok(())
}
pub fn matches(self, partials: &mut PartialPaths, postcondition: PartialScopedSymbol) -> bool {
if self.symbol != postcondition.symbol {
return false;
}
if self.scopes.is_none() != postcondition.scopes.is_none() {
return false;
}
if let Some(precondition_scopes) = self.scopes.into_option() {
if let Some(postcondition_scopes) = postcondition.scopes.into_option() {
return precondition_scopes.matches(partials, postcondition_scopes);
}
}
true
}
pub fn apply_partial_bindings(
mut self,
partials: &mut PartialPaths,
scope_bindings: &PartialScopeStackBindings,
) -> Result<PartialScopedSymbol, PathResolutionError> {
let scopes = match self.scopes.into_option() {
Some(scopes) => Some(scopes.apply_partial_bindings(partials, scope_bindings)?),
None => None,
};
self.scopes = scopes.into();
Ok(self)
}
pub fn equals(&self, partials: &mut PartialPaths, other: &PartialScopedSymbol) -> bool {
self.symbol == other.symbol
&& equals_option(
self.scopes.into_option(),
other.scopes.into_option(),
|a, b| a.equals(partials, b),
)
}
pub fn cmp(
&self,
graph: &StackGraph,
partials: &mut PartialPaths,
other: &PartialScopedSymbol,
) -> std::cmp::Ordering {
std::cmp::Ordering::Equal
.then_with(|| graph[self.symbol].cmp(&graph[other.symbol]))
.then_with(|| {
cmp_option(
self.scopes.into_option(),
other.scopes.into_option(),
|a, b| a.cmp(partials, b),
)
})
}
pub fn display<'a>(
self,
graph: &'a StackGraph,
partials: &'a mut PartialPaths,
) -> impl Display + 'a {
display_with(self, graph, partials)
}
}
impl DisplayWithPartialPaths for PartialScopedSymbol {
fn prepare(&mut self, graph: &StackGraph, partials: &mut PartialPaths) {
if let Some(mut scopes) = self.scopes.into_option() {
scopes.prepare(graph, partials);
self.scopes = scopes.into();
}
}
fn display_with(
&self,
graph: &StackGraph,
partials: &PartialPaths,
f: &mut std::fmt::Formatter,
) -> std::fmt::Result {
if let Some(scopes) = self.scopes.into_option() {
write!(
f,
"{}/({})",
self.symbol.display(graph),
display_prepared(scopes, graph, partials)
)
} else {
write!(f, "{}", self.symbol.display(graph))
}
}
}
#[repr(C)]
#[derive(Clone, Copy, Niche)]
pub struct PartialSymbolStack {
#[niche]
symbols: Deque<PartialScopedSymbol>,
length: u32,
variable: ControlledOption<SymbolStackVariable>,
}
impl PartialSymbolStack {
#[inline(always)]
pub fn can_match_empty(&self) -> bool {
self.symbols.is_empty()
}
#[inline(always)]
pub fn can_only_match_empty(&self) -> bool {
self.symbols.is_empty() && self.variable.is_none()
}
#[inline(always)]
pub fn contains_symbols(&self) -> bool {
!self.symbols.is_empty()
}
#[inline(always)]
pub fn has_variable(&self) -> bool {
self.variable.is_some()
}
#[inline(always)]
pub fn len(&self) -> usize {
self.length as usize
}
pub fn empty() -> PartialSymbolStack {
PartialSymbolStack {
symbols: Deque::empty(),
length: 0,
variable: ControlledOption::none(),
}
}
pub fn from_variable(variable: SymbolStackVariable) -> PartialSymbolStack {
PartialSymbolStack {
symbols: Deque::empty(),
length: 0,
variable: ControlledOption::some(variable),
}
}
pub fn have_reversal(&self, partials: &PartialPaths) -> bool {
self.symbols.have_reversal(&partials.partial_symbol_stacks)
}
pub fn with_offset(
mut self,
partials: &mut PartialPaths,
symbol_variable_offset: u32,
scope_variable_offset: u32,
) -> PartialSymbolStack {
let mut result = match self.variable.into_option() {
Some(variable) => Self::from_variable(variable.with_offset(symbol_variable_offset)),
None => Self::empty(),
};
while let Some(symbol) = self.pop_front(partials) {
result.push_back(partials, symbol.with_offset(scope_variable_offset));
}
result
}
fn prepend(&mut self, partials: &mut PartialPaths, mut head: Deque<PartialScopedSymbol>) {
while let Some(head) = head.pop_back(&mut partials.partial_symbol_stacks).copied() {
self.push_front(partials, head);
}
}
pub fn push_front(&mut self, partials: &mut PartialPaths, symbol: PartialScopedSymbol) {
self.length += 1;
self.symbols
.push_front(&mut partials.partial_symbol_stacks, symbol);
}
pub fn push_back(&mut self, partials: &mut PartialPaths, symbol: PartialScopedSymbol) {
self.length += 1;
self.symbols
.push_back(&mut partials.partial_symbol_stacks, symbol);
}
pub fn pop_front(&mut self, partials: &mut PartialPaths) -> Option<PartialScopedSymbol> {
let result = self
.symbols
.pop_front(&mut partials.partial_symbol_stacks)
.copied();
if result.is_some() {
self.length -= 1;
}
result
}
pub fn pop_back(&mut self, partials: &mut PartialPaths) -> Option<PartialScopedSymbol> {
let result = self
.symbols
.pop_back(&mut partials.partial_symbol_stacks)
.copied();
if result.is_some() {
self.length -= 1;
}
result
}
pub fn display<'a>(
self,
graph: &'a StackGraph,
partials: &'a mut PartialPaths,
) -> impl Display + 'a {
display_with(self, graph, partials)
}
pub fn matches(mut self, partials: &mut PartialPaths, mut other: PartialSymbolStack) -> bool {
while let Some(self_element) = self.pop_front(partials) {
if let Some(other_element) = other.pop_front(partials) {
if !self_element.matches(partials, other_element) {
return false;
}
} else {
return false;
}
}
if other.contains_symbols() {
return false;
}
self.variable.into_option() == other.variable.into_option()
}
pub fn apply_partial_bindings(
mut self,
partials: &mut PartialPaths,
symbol_bindings: &PartialSymbolStackBindings,
scope_bindings: &PartialScopeStackBindings,
) -> Result<PartialSymbolStack, PathResolutionError> {
let mut result = match self.variable.into_option() {
Some(variable) => match symbol_bindings.get(variable) {
Some(bound) => bound,
None => PartialSymbolStack::from_variable(variable),
},
None => PartialSymbolStack::empty(),
};
while let Some(partial_symbol) = self.pop_back(partials) {
let partial_symbol = partial_symbol.apply_partial_bindings(partials, scope_bindings)?;
result.push_front(partials, partial_symbol);
}
Ok(result)
}
pub fn unify(
self,
partials: &mut PartialPaths,
mut rhs: PartialSymbolStack,
symbol_bindings: &mut PartialSymbolStackBindings,
scope_bindings: &mut PartialScopeStackBindings,
) -> Result<PartialSymbolStack, PathResolutionError> {
let mut lhs = self;
let mut head = Deque::empty();
while lhs.contains_symbols() && rhs.contains_symbols() {
let mut lhs_front = lhs.pop_front(partials).unwrap();
let rhs_front = rhs.pop_front(partials).unwrap();
lhs_front.unify(partials, rhs_front, scope_bindings)?;
head.push_back(&mut partials.partial_symbol_stacks, lhs_front);
}
if !lhs.contains_symbols() && !rhs.contains_symbols() {
match (lhs.variable.into_option(), rhs.variable.into_option()) {
(None, None) => {
lhs.prepend(partials, head);
return Ok(lhs);
}
(None, Some(var)) => {
symbol_bindings.add(
partials,
var,
PartialSymbolStack::empty(),
scope_bindings,
)?;
rhs.prepend(partials, head);
return Ok(rhs);
}
(Some(var), None) => {
symbol_bindings.add(
partials,
var,
PartialSymbolStack::empty(),
scope_bindings,
)?;
lhs.prepend(partials, head);
return Ok(lhs);
}
(Some(lhs_var), Some(rhs_var)) => {
symbol_bindings.add(
partials,
rhs_var,
PartialSymbolStack::from_variable(lhs_var),
scope_bindings,
)?;
lhs.prepend(partials, head);
return Ok(lhs);
}
}
}
if !lhs.contains_symbols() && lhs.variable.is_none() {
return Err(PathResolutionError::SymbolStackUnsatisfied);
}
if !rhs.contains_symbols() && rhs.variable.is_none() {
return Err(PathResolutionError::SymbolStackUnsatisfied);
}
match (lhs.variable.into_option(), rhs.variable.into_option()) {
(Some(v1), Some(v2)) if v1 == v2 => {
return Err(PathResolutionError::ScopeStackUnsatisfied)
}
_ => {}
}
if lhs.contains_symbols() {
let rhs_variable = rhs.variable.into_option().unwrap();
symbol_bindings.add(partials, rhs_variable, lhs, scope_bindings)?;
lhs.prepend(partials, head);
return Ok(lhs);
}
if rhs.contains_symbols() {
let lhs_variable = lhs.variable.into_option().unwrap();
symbol_bindings.add(partials, lhs_variable, rhs, scope_bindings)?;
rhs.prepend(partials, head);
return Ok(rhs);
}
unreachable!();
}
pub fn equals(mut self, partials: &mut PartialPaths, mut other: PartialSymbolStack) -> bool {
while let Some(self_symbol) = self.pop_front(partials) {
if let Some(other_symbol) = other.pop_front(partials) {
if !self_symbol.equals(partials, &other_symbol) {
return false;
}
} else {
return false;
}
}
if !other.symbols.is_empty() {
return false;
}
equals_option(
self.variable.into_option(),
other.variable.into_option(),
|a, b| a == b,
)
}
pub fn cmp(
mut self,
graph: &StackGraph,
partials: &mut PartialPaths,
mut other: PartialSymbolStack,
) -> std::cmp::Ordering {
use std::cmp::Ordering;
while let Some(self_symbol) = self.pop_front(partials) {
if let Some(other_symbol) = other.pop_front(partials) {
match self_symbol.cmp(graph, partials, &other_symbol) {
Ordering::Equal => continue,
result @ _ => return result,
}
} else {
return Ordering::Greater;
}
}
if !other.symbols.is_empty() {
return Ordering::Less;
}
cmp_option(
self.variable.into_option(),
other.variable.into_option(),
|a, b| a.cmp(&b),
)
}
pub fn iter<'a>(
&self,
partials: &'a mut PartialPaths,
) -> impl Iterator<Item = PartialScopedSymbol> + 'a {
self.symbols
.iter(&mut partials.partial_symbol_stacks)
.copied()
}
pub fn iter_unordered<'a>(
&self,
partials: &'a PartialPaths,
) -> impl Iterator<Item = PartialScopedSymbol> + 'a {
self.symbols
.iter_unordered(&partials.partial_symbol_stacks)
.copied()
}
pub fn variable(&self) -> Option<SymbolStackVariable> {
self.variable.clone().into_option()
}
fn ensure_both_directions(&mut self, partials: &mut PartialPaths) {
self.symbols
.ensure_backwards(&mut partials.partial_symbol_stacks);
self.symbols
.ensure_forwards(&mut partials.partial_symbol_stacks);
}
fn ensure_forwards(&mut self, partials: &mut PartialPaths) {
self.symbols
.ensure_forwards(&mut partials.partial_symbol_stacks);
}
pub fn largest_symbol_stack_variable(&self) -> u32 {
self.variable
.into_option()
.map(SymbolStackVariable::as_u32)
.unwrap_or(0)
}
pub fn largest_scope_stack_variable(&self, partials: &PartialPaths) -> u32 {
self.iter_unordered(partials)
.filter_map(|symbol| symbol.scopes.into_option())
.filter_map(|scopes| scopes.variable.into_option())
.map(ScopeStackVariable::as_u32)
.max()
.unwrap_or(0)
}
}
impl DisplayWithPartialPaths for PartialSymbolStack {
fn prepare(&mut self, graph: &StackGraph, partials: &mut PartialPaths) {
self.symbols
.ensure_forwards(&mut partials.partial_symbol_stacks);
let mut symbols = self.symbols;
while let Some(mut symbol) = symbols
.pop_front(&mut partials.partial_symbol_stacks)
.copied()
{
symbol.prepare(graph, partials);
}
}
fn display_with(
&self,
graph: &StackGraph,
partials: &PartialPaths,
f: &mut std::fmt::Formatter,
) -> std::fmt::Result {
for symbol in self.symbols.iter_reused(&partials.partial_symbol_stacks) {
symbol.display_with(graph, partials, f)?;
}
if let Some(variable) = self.variable.into_option() {
if self.symbols.is_empty() {
write!(f, "{}", variable)?;
} else {
write!(f, ",{}", variable)?;
}
}
Ok(())
}
}
#[repr(C)]
#[derive(Clone, Copy, Niche)]
pub struct PartialScopeStack {
#[niche]
scopes: Deque<Handle<Node>>,
length: u32,
variable: ControlledOption<ScopeStackVariable>,
}
impl PartialScopeStack {
#[inline(always)]
pub fn can_match_empty(&self) -> bool {
self.scopes.is_empty()
}
#[inline(always)]
pub fn can_only_match_empty(&self) -> bool {
self.scopes.is_empty() && self.variable.is_none()
}
#[inline(always)]
pub fn contains_scopes(&self) -> bool {
!self.scopes.is_empty()
}
#[inline(always)]
pub fn has_variable(&self) -> bool {
self.variable.is_some()
}
#[inline(always)]
pub fn len(&self) -> usize {
self.length as usize
}
pub fn empty() -> PartialScopeStack {
PartialScopeStack {
scopes: Deque::empty(),
length: 0,
variable: ControlledOption::none(),
}
}
pub fn from_variable(variable: ScopeStackVariable) -> PartialScopeStack {
PartialScopeStack {
scopes: Deque::empty(),
length: 0,
variable: ControlledOption::some(variable),
}
}
pub fn have_reversal(&self, partials: &PartialPaths) -> bool {
self.scopes.have_reversal(&partials.partial_scope_stacks)
}
pub fn with_offset(mut self, scope_variable_offset: u32) -> PartialScopeStack {
match self.variable.into_option() {
Some(variable) => {
self.variable = ControlledOption::some(variable.with_offset(scope_variable_offset));
}
None => {}
};
self
}
pub fn matches(mut self, partials: &mut PartialPaths, mut other: PartialScopeStack) -> bool {
while let Some(self_element) = self.pop_front(partials) {
if let Some(other_element) = other.pop_front(partials) {
if self_element != other_element {
return false;
}
} else {
return false;
}
}
if other.contains_scopes() {
return false;
}
self.variable.into_option() == other.variable.into_option()
}
pub fn apply_partial_bindings(
mut self,
partials: &mut PartialPaths,
scope_bindings: &PartialScopeStackBindings,
) -> Result<PartialScopeStack, PathResolutionError> {
let mut result = match self.variable.into_option() {
Some(variable) => match scope_bindings.get(variable) {
Some(bound) => bound,
None => PartialScopeStack::from_variable(variable),
},
None => PartialScopeStack::empty(),
};
while let Some(scope) = self.pop_back(partials) {
result.push_front(partials, scope);
}
Ok(result)
}
pub fn unify(
self,
partials: &mut PartialPaths,
mut rhs: PartialScopeStack,
bindings: &mut PartialScopeStackBindings,
) -> Result<PartialScopeStack, PathResolutionError> {
let mut lhs = self;
let original_rhs = rhs;
while lhs.contains_scopes() && rhs.contains_scopes() {
let lhs_front = lhs.pop_front(partials).unwrap();
let rhs_front = rhs.pop_front(partials).unwrap();
if lhs_front != rhs_front {
return Err(PathResolutionError::ScopeStackUnsatisfied);
}
}
if !lhs.contains_scopes() && !rhs.contains_scopes() {
match (lhs.variable.into_option(), rhs.variable.into_option()) {
(None, None) => return Ok(self),
(None, Some(var)) => {
bindings.add(partials, var, PartialScopeStack::empty())?;
return Ok(original_rhs);
}
(Some(var), None) => {
bindings.add(partials, var, PartialScopeStack::empty())?;
return Ok(self);
}
(Some(lhs_var), Some(rhs_var)) => {
bindings.add(partials, rhs_var, PartialScopeStack::from_variable(lhs_var))?;
return Ok(self);
}
}
}
if !lhs.contains_scopes() && lhs.variable.is_none() {
return Err(PathResolutionError::ScopeStackUnsatisfied);
}
if !rhs.contains_scopes() && rhs.variable.is_none() {
return Err(PathResolutionError::ScopeStackUnsatisfied);
}
match (lhs.variable.into_option(), rhs.variable.into_option()) {
(Some(v1), Some(v2)) if v1 == v2 => {
return Err(PathResolutionError::ScopeStackUnsatisfied)
}
_ => {}
}
if lhs.contains_scopes() {
let rhs_variable = rhs.variable.into_option().unwrap();
bindings.add(partials, rhs_variable, lhs)?;
return Ok(self);
}
if rhs.contains_scopes() {
let lhs_variable = lhs.variable.into_option().unwrap();
bindings.add(partials, lhs_variable, rhs)?;
return Ok(original_rhs);
}
unreachable!();
}
pub fn push_front(&mut self, partials: &mut PartialPaths, node: Handle<Node>) {
self.length += 1;
self.scopes
.push_front(&mut partials.partial_scope_stacks, node);
}
pub fn push_back(&mut self, partials: &mut PartialPaths, node: Handle<Node>) {
self.length += 1;
self.scopes
.push_back(&mut partials.partial_scope_stacks, node);
}
pub fn pop_front(&mut self, partials: &mut PartialPaths) -> Option<Handle<Node>> {
let result = self
.scopes
.pop_front(&mut partials.partial_scope_stacks)
.copied();
if result.is_some() {
self.length -= 1;
}
result
}
pub fn pop_back(&mut self, partials: &mut PartialPaths) -> Option<Handle<Node>> {
let result = self
.scopes
.pop_back(&mut partials.partial_scope_stacks)
.copied();
if result.is_some() {
self.length -= 1;
}
result
}
pub fn variable(&self) -> Option<ScopeStackVariable> {
self.variable.into_option()
}
pub fn equals(self, partials: &mut PartialPaths, other: PartialScopeStack) -> bool {
self.scopes
.equals_with(&mut partials.partial_scope_stacks, other.scopes, |a, b| {
*a == *b
})
&& equals_option(
self.variable.into_option(),
other.variable.into_option(),
|a, b| a == b,
)
}
pub fn cmp(self, partials: &mut PartialPaths, other: PartialScopeStack) -> std::cmp::Ordering {
std::cmp::Ordering::Equal
.then_with(|| {
self.scopes
.cmp_with(&mut partials.partial_scope_stacks, other.scopes, |a, b| {
a.cmp(b)
})
})
.then_with(|| {
cmp_option(
self.variable.into_option(),
other.variable.into_option(),
|a, b| a.cmp(&b),
)
})
}
pub fn iter_scopes<'a>(
&self,
partials: &'a mut PartialPaths,
) -> impl Iterator<Item = Handle<Node>> + 'a {
self.scopes
.iter(&mut partials.partial_scope_stacks)
.copied()
}
pub fn iter_unordered<'a>(
&self,
partials: &'a PartialPaths,
) -> impl Iterator<Item = Handle<Node>> + 'a {
self.scopes
.iter_unordered(&partials.partial_scope_stacks)
.copied()
}
pub fn display<'a>(
self,
graph: &'a StackGraph,
partials: &'a mut PartialPaths,
) -> impl Display + 'a {
display_with(self, graph, partials)
}
fn ensure_both_directions(&mut self, partials: &mut PartialPaths) {
self.scopes
.ensure_backwards(&mut partials.partial_scope_stacks);
self.scopes
.ensure_forwards(&mut partials.partial_scope_stacks);
}
fn ensure_forwards(&mut self, partials: &mut PartialPaths) {
self.scopes
.ensure_forwards(&mut partials.partial_scope_stacks);
}
pub fn largest_scope_stack_variable(&self) -> u32 {
self.variable
.into_option()
.map(ScopeStackVariable::as_u32)
.unwrap_or(0)
}
}
impl DisplayWithPartialPaths for PartialScopeStack {
fn prepare(&mut self, _graph: &StackGraph, partials: &mut PartialPaths) {
self.scopes
.ensure_forwards(&mut partials.partial_scope_stacks);
}
fn display_with(
&self,
graph: &StackGraph,
partials: &PartialPaths,
f: &mut std::fmt::Formatter,
) -> std::fmt::Result {
let mut first = true;
for scope in self.scopes.iter_reused(&partials.partial_scope_stacks) {
if first {
first = false;
} else {
write!(f, ",")?;
}
write!(f, "{:#}", scope.display(graph))?;
}
if let Some(variable) = self.variable.into_option() {
if self.scopes.is_empty() {
write!(f, "{}", variable)?;
} else {
write!(f, ",{}", variable)?;
}
}
Ok(())
}
}
pub struct PartialSymbolStackBindings {
bindings: SmallVec<[Option<PartialSymbolStack>; 4]>,
}
impl PartialSymbolStackBindings {
pub fn new() -> PartialSymbolStackBindings {
PartialSymbolStackBindings {
bindings: SmallVec::new(),
}
}
pub fn get(&self, variable: SymbolStackVariable) -> Option<PartialSymbolStack> {
let index = variable.as_usize();
if self.bindings.len() < index {
return None;
}
self.bindings[index - 1]
}
pub fn add(
&mut self,
partials: &mut PartialPaths,
variable: SymbolStackVariable,
mut symbols: PartialSymbolStack,
scope_bindings: &mut PartialScopeStackBindings,
) -> Result<(), PathResolutionError> {
let index = variable.as_usize();
if self.bindings.len() < index {
self.bindings.resize_with(index, || None);
}
if let Some(old_binding) = self.bindings[index - 1] {
symbols = symbols.unify(partials, old_binding, self, scope_bindings)?;
}
self.bindings[index - 1] = Some(symbols);
Ok(())
}
pub fn display<'a>(
&'a mut self,
graph: &'a StackGraph,
partials: &'a mut PartialPaths,
) -> impl Display + 'a {
display_with(self, graph, partials)
}
}
impl<'a> DisplayWithPartialPaths for &'a mut PartialSymbolStackBindings {
fn prepare(&mut self, graph: &StackGraph, partials: &mut PartialPaths) {
for binding in &mut self.bindings {
if let Some(binding) = binding.as_mut() {
binding.prepare(graph, partials);
}
}
}
fn display_with(
&self,
graph: &StackGraph,
partials: &PartialPaths,
f: &mut std::fmt::Formatter,
) -> std::fmt::Result {
write!(f, "{{")?;
let mut first = true;
for (idx, binding) in self.bindings.iter().enumerate() {
if let Some(binding) = binding.as_ref() {
if first {
first = false;
} else {
write!(f, ", ")?;
}
write!(
f,
"%{} => <{}>",
idx + 1,
display_prepared(*binding, graph, partials)
)?;
}
}
write!(f, "}}")
}
}
pub struct PartialScopeStackBindings {
bindings: SmallVec<[Option<PartialScopeStack>; 4]>,
}
impl PartialScopeStackBindings {
pub fn new() -> PartialScopeStackBindings {
PartialScopeStackBindings {
bindings: SmallVec::new(),
}
}
pub fn get(&self, variable: ScopeStackVariable) -> Option<PartialScopeStack> {
let index = variable.as_usize();
if self.bindings.len() < index {
return None;
}
self.bindings[index - 1]
}
pub fn add(
&mut self,
partials: &mut PartialPaths,
variable: ScopeStackVariable,
mut scopes: PartialScopeStack,
) -> Result<(), PathResolutionError> {
let index = variable.as_usize();
if self.bindings.len() < index {
self.bindings.resize_with(index, || None);
}
if let Some(old_binding) = self.bindings[index - 1] {
scopes = scopes.unify(partials, old_binding, self)?;
}
self.bindings[index - 1] = Some(scopes);
Ok(())
}
pub fn display<'a>(
&'a mut self,
graph: &'a StackGraph,
partials: &'a mut PartialPaths,
) -> impl Display + 'a {
display_with(self, graph, partials)
}
}
impl<'a> DisplayWithPartialPaths for &'a mut PartialScopeStackBindings {
fn prepare(&mut self, graph: &StackGraph, partials: &mut PartialPaths) {
for binding in &mut self.bindings {
if let Some(binding) = binding.as_mut() {
binding.prepare(graph, partials);
}
}
}
fn display_with(
&self,
graph: &StackGraph,
partials: &PartialPaths,
f: &mut std::fmt::Formatter,
) -> std::fmt::Result {
write!(f, "{{")?;
let mut first = true;
for (idx, binding) in self.bindings.iter().enumerate() {
if let Some(binding) = binding.as_ref() {
if first {
first = false;
} else {
write!(f, ", ")?;
}
write!(
f,
"${} => ({})",
idx + 1,
display_prepared(*binding, graph, partials)
)?;
}
}
write!(f, "}}")
}
}
#[repr(C)]
#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct PartialPathEdge {
pub source_node_id: NodeID,
pub precedence: i32,
}
impl PartialPathEdge {
pub fn shadows(self, other: PartialPathEdge) -> bool {
self.source_node_id == other.source_node_id && self.precedence > other.precedence
}
pub fn display<'a>(
self,
graph: &'a StackGraph,
partials: &'a mut PartialPaths,
) -> impl Display + 'a {
display_with(self, graph, partials)
}
}
impl DisplayWithPartialPaths for PartialPathEdge {
fn display_with(
&self,
graph: &StackGraph,
_partials: &PartialPaths,
f: &mut std::fmt::Formatter,
) -> std::fmt::Result {
match graph.node_for_id(self.source_node_id) {
Some(node) => write!(f, "{:#}", node.display(graph))?,
None => write!(f, "[missing]")?,
}
if self.precedence != 0 {
write!(f, "({})", self.precedence)?;
}
Ok(())
}
}
#[repr(C)]
#[derive(Clone, Copy, Niche)]
pub struct PartialPathEdgeList {
#[niche]
edges: Deque<PartialPathEdge>,
length: u32,
}
impl PartialPathEdgeList {
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.edges.is_empty()
}
#[inline(always)]
pub fn len(&self) -> usize {
self.length as usize
}
pub fn have_reversal(&self, partials: &PartialPaths) -> bool {
self.edges.have_reversal(&partials.partial_path_edges)
}
pub fn empty() -> PartialPathEdgeList {
PartialPathEdgeList {
edges: Deque::empty(),
length: 0,
}
}
pub fn push_front(&mut self, partials: &mut PartialPaths, edge: PartialPathEdge) {
self.length += 1;
self.edges
.push_front(&mut partials.partial_path_edges, edge);
}
pub fn push_back(&mut self, partials: &mut PartialPaths, edge: PartialPathEdge) {
self.length += 1;
self.edges.push_back(&mut partials.partial_path_edges, edge);
}
pub fn pop_front(&mut self, partials: &mut PartialPaths) -> Option<PartialPathEdge> {
let result = self.edges.pop_front(&mut partials.partial_path_edges);
if result.is_some() {
self.length -= 1;
}
result.copied()
}
pub fn pop_back(&mut self, partials: &mut PartialPaths) -> Option<PartialPathEdge> {
let result = self.edges.pop_back(&mut partials.partial_path_edges);
if result.is_some() {
self.length -= 1;
}
result.copied()
}
pub fn display<'a>(
self,
graph: &'a StackGraph,
partials: &'a mut PartialPaths,
) -> impl Display + 'a {
display_with(self, graph, partials)
}
pub fn shadows(mut self, partials: &mut PartialPaths, mut other: PartialPathEdgeList) -> bool {
while let Some(self_edge) = self.pop_front(partials) {
if let Some(other_edge) = other.pop_front(partials) {
if self_edge.source_node_id != other_edge.source_node_id {
return false;
} else if self_edge.shadows(other_edge) {
return true;
}
} else {
return false;
}
}
false
}
pub fn equals(mut self, partials: &mut PartialPaths, mut other: PartialPathEdgeList) -> bool {
while let Some(self_edge) = self.pop_front(partials) {
if let Some(other_edge) = other.pop_front(partials) {
if self_edge != other_edge {
return false;
}
} else {
return false;
}
}
other.edges.is_empty()
}
pub fn cmp(
mut self,
partials: &mut PartialPaths,
mut other: PartialPathEdgeList,
) -> std::cmp::Ordering {
use std::cmp::Ordering;
while let Some(self_edge) = self.pop_front(partials) {
if let Some(other_edge) = other.pop_front(partials) {
match self_edge.cmp(&other_edge) {
Ordering::Equal => continue,
result @ _ => return result,
}
} else {
return Ordering::Greater;
}
}
if other.edges.is_empty() {
Ordering::Equal
} else {
Ordering::Less
}
}
pub fn iter<'a>(
&self,
partials: &'a mut PartialPaths,
) -> impl Iterator<Item = PartialPathEdge> + 'a {
self.edges.iter(&mut partials.partial_path_edges).copied()
}
pub fn iter_unordered<'a>(
&self,
partials: &'a PartialPaths,
) -> impl Iterator<Item = PartialPathEdge> + 'a {
self.edges
.iter_unordered(&partials.partial_path_edges)
.copied()
}
fn ensure_both_directions(&mut self, partials: &mut PartialPaths) {
self.edges
.ensure_backwards(&mut partials.partial_path_edges);
self.edges.ensure_forwards(&mut partials.partial_path_edges);
}
fn ensure_forwards(&mut self, partials: &mut PartialPaths) {
self.edges.ensure_forwards(&mut partials.partial_path_edges);
}
}
impl DisplayWithPartialPaths for PartialPathEdgeList {
fn prepare(&mut self, graph: &StackGraph, partials: &mut PartialPaths) {
self.edges.ensure_forwards(&mut partials.partial_path_edges);
let mut edges = self.edges;
while let Some(mut edge) = edges.pop_front(&mut partials.partial_path_edges).copied() {
edge.prepare(graph, partials);
}
}
fn display_with(
&self,
graph: &StackGraph,
partials: &PartialPaths,
f: &mut std::fmt::Formatter,
) -> std::fmt::Result {
for edge in self.edges.iter_reused(&partials.partial_path_edges) {
edge.display_with(graph, partials, f)?;
}
Ok(())
}
}
#[repr(C)]
#[derive(Clone)]
pub struct PartialPath {
pub start_node: Handle<Node>,
pub end_node: Handle<Node>,
pub symbol_stack_precondition: PartialSymbolStack,
pub symbol_stack_postcondition: PartialSymbolStack,
pub scope_stack_precondition: PartialScopeStack,
pub scope_stack_postcondition: PartialScopeStack,
pub edges: PartialPathEdgeList,
}
impl PartialPath {
pub fn from_node(
graph: &StackGraph,
partials: &mut PartialPaths,
node: Handle<Node>,
) -> PartialPath {
let initial_symbol_stack = SymbolStackVariable::initial();
let initial_scope_stack = ScopeStackVariable::initial();
let mut symbol_stack_precondition = PartialSymbolStack::from_variable(initial_symbol_stack);
let mut symbol_stack_postcondition =
PartialSymbolStack::from_variable(initial_symbol_stack);
let mut scope_stack_precondition = PartialScopeStack::from_variable(initial_scope_stack);
let mut scope_stack_postcondition = PartialScopeStack::from_variable(initial_scope_stack);
graph[node]
.append_to_partial_stacks(
graph,
partials,
&mut symbol_stack_precondition,
&mut scope_stack_precondition,
&mut symbol_stack_postcondition,
&mut scope_stack_postcondition,
)
.expect("lifting single nodes to partial paths should not fail");
PartialPath {
start_node: node,
end_node: node,
symbol_stack_precondition,
symbol_stack_postcondition,
scope_stack_precondition,
scope_stack_postcondition,
edges: PartialPathEdgeList::empty(),
}
}
pub fn shadows(&self, partials: &mut PartialPaths, other: &PartialPath) -> bool {
self.edges.shadows(partials, other.edges)
}
pub fn equals(&self, partials: &mut PartialPaths, other: &PartialPath) -> bool {
self.start_node == other.start_node
&& self.end_node == other.end_node
&& self
.symbol_stack_precondition
.equals(partials, other.symbol_stack_precondition)
&& self
.symbol_stack_postcondition
.equals(partials, other.symbol_stack_postcondition)
&& self
.scope_stack_precondition
.equals(partials, other.scope_stack_precondition)
&& self
.scope_stack_postcondition
.equals(partials, other.scope_stack_postcondition)
}
pub fn cmp(
&self,
graph: &StackGraph,
partials: &mut PartialPaths,
other: &PartialPath,
) -> std::cmp::Ordering {
std::cmp::Ordering::Equal
.then_with(|| self.start_node.cmp(&other.start_node))
.then_with(|| self.end_node.cmp(&other.end_node))
.then_with(|| {
self.symbol_stack_precondition
.cmp(graph, partials, other.symbol_stack_precondition)
})
.then_with(|| {
self.symbol_stack_postcondition.cmp(
graph,
partials,
other.symbol_stack_postcondition,
)
})
.then_with(|| {
self.scope_stack_precondition
.cmp(partials, other.scope_stack_precondition)
})
.then_with(|| {
self.scope_stack_postcondition
.cmp(partials, other.scope_stack_postcondition)
})
}
pub fn starts_at_reference(&self, graph: &StackGraph) -> bool {
graph[self.start_node].is_reference()
&& self.symbol_stack_precondition.can_match_empty()
&& self.scope_stack_precondition.can_match_empty()
}
pub fn ends_at_definition(&self, graph: &StackGraph) -> bool {
graph[self.end_node].is_definition() && self.symbol_stack_postcondition.can_match_empty()
}
pub fn is_complete(&self, graph: &StackGraph) -> bool {
self.starts_at_reference(graph) && self.ends_at_definition(graph)
}
pub fn starts_at_endpoint(&self, graph: &StackGraph) -> bool {
graph[self.start_node].is_endpoint()
}
pub fn ends_at_endpoint(&self, graph: &StackGraph) -> bool {
graph[self.end_node].is_endpoint()
}
pub fn ends_in_jump(&self, graph: &StackGraph) -> bool {
graph[self.end_node].is_jump_to()
}
pub fn is_cyclic(&self, graph: &StackGraph, partials: &mut PartialPaths) -> Option<Cyclicity> {
if self.start_node != self.end_node {
return None;
}
let lhs = self;
let mut rhs = self.clone();
rhs.ensure_no_overlapping_variables(partials, lhs);
let join = match Self::compute_join(graph, partials, lhs, &rhs) {
Ok(join) => join,
Err(_) => return None,
};
if lhs
.symbol_stack_precondition
.variable
.into_option()
.map_or(false, |v| join.symbol_bindings.get(v).iter().len() > 0)
|| lhs
.scope_stack_precondition
.variable
.into_option()
.map_or(false, |v| join.scope_bindings.get(v).iter().len() > 0)
{
Some(Cyclicity::StrengthensPrecondition)
} else if rhs
.symbol_stack_postcondition
.variable
.into_option()
.map_or(false, |v| join.symbol_bindings.get(v).iter().len() > 0)
|| rhs
.scope_stack_postcondition
.variable
.into_option()
.map_or(false, |v| join.scope_bindings.get(v).iter().len() > 0)
{
Some(Cyclicity::StrengthensPostcondition)
} else {
Some(Cyclicity::Free)
}
}
pub fn ensure_both_directions(&mut self, partials: &mut PartialPaths) {
self.symbol_stack_precondition
.ensure_both_directions(partials);
self.symbol_stack_postcondition
.ensure_both_directions(partials);
self.scope_stack_precondition
.ensure_both_directions(partials);
self.scope_stack_postcondition
.ensure_both_directions(partials);
self.edges.ensure_both_directions(partials);
let mut stack = self.symbol_stack_precondition;
while let Some(symbol) = stack.pop_front(partials) {
if let Some(mut scopes) = symbol.scopes.into_option() {
scopes.ensure_both_directions(partials);
}
}
let mut stack = self.symbol_stack_postcondition;
while let Some(symbol) = stack.pop_front(partials) {
if let Some(mut scopes) = symbol.scopes.into_option() {
scopes.ensure_both_directions(partials);
}
}
}
pub fn ensure_forwards(&mut self, partials: &mut PartialPaths) {
self.symbol_stack_precondition.ensure_forwards(partials);
self.symbol_stack_postcondition.ensure_forwards(partials);
self.scope_stack_precondition.ensure_forwards(partials);
self.scope_stack_postcondition.ensure_forwards(partials);
self.edges.ensure_forwards(partials);
let mut stack = self.symbol_stack_precondition;
while let Some(symbol) = stack.pop_front(partials) {
if let Some(mut scopes) = symbol.scopes.into_option() {
scopes.ensure_forwards(partials);
}
}
let mut stack = self.symbol_stack_postcondition;
while let Some(symbol) = stack.pop_front(partials) {
if let Some(mut scopes) = symbol.scopes.into_option() {
scopes.ensure_forwards(partials);
}
}
}
pub fn largest_symbol_stack_variable(&self) -> u32 {
self.symbol_stack_precondition
.largest_symbol_stack_variable()
}
pub fn largest_scope_stack_variable(&self, partials: &PartialPaths) -> u32 {
Self::largest_scope_stack_variable_for_partial_stacks(
partials,
&self.symbol_stack_precondition,
&self.scope_stack_precondition,
)
}
fn largest_scope_stack_variable_for_partial_stacks(
partials: &PartialPaths,
symbol_stack_precondition: &PartialSymbolStack,
scope_stack_precondition: &PartialScopeStack,
) -> u32 {
std::cmp::max(
symbol_stack_precondition.largest_scope_stack_variable(partials),
scope_stack_precondition.largest_scope_stack_variable(),
)
}
pub fn fresh_scope_stack_variable(&self, partials: &PartialPaths) -> ScopeStackVariable {
Self::fresh_scope_stack_variable_for_partial_stack(
partials,
&self.symbol_stack_precondition,
&self.scope_stack_precondition,
)
}
fn fresh_scope_stack_variable_for_partial_stack(
partials: &PartialPaths,
symbol_stack_precondition: &PartialSymbolStack,
scope_stack_precondition: &PartialScopeStack,
) -> ScopeStackVariable {
ScopeStackVariable::fresher_than(Self::largest_scope_stack_variable_for_partial_stacks(
partials,
symbol_stack_precondition,
scope_stack_precondition,
))
}
pub fn display<'a>(
&'a self,
graph: &'a StackGraph,
partials: &'a mut PartialPaths,
) -> impl Display + 'a {
display_with(self, graph, partials)
}
}
#[derive(Debug, EnumSetType)]
pub enum Cyclicity {
Free,
StrengthensPrecondition,
StrengthensPostcondition,
}
impl<'a> DisplayWithPartialPaths for &'a PartialPath {
fn prepare(&mut self, graph: &StackGraph, partials: &mut PartialPaths) {
self.symbol_stack_precondition
.clone()
.prepare(graph, partials);
self.symbol_stack_postcondition
.clone()
.prepare(graph, partials);
self.scope_stack_precondition
.clone()
.prepare(graph, partials);
self.scope_stack_postcondition
.clone()
.prepare(graph, partials);
}
fn display_with(
&self,
graph: &StackGraph,
partials: &PartialPaths,
f: &mut std::fmt::Formatter,
) -> std::fmt::Result {
write!(
f,
"<{}> ({}) {} -> {} <{}> ({})",
display_prepared(self.symbol_stack_precondition, graph, partials),
display_prepared(self.scope_stack_precondition, graph, partials),
self.start_node.display(graph),
self.end_node.display(graph),
display_prepared(self.symbol_stack_postcondition, graph, partials),
display_prepared(self.scope_stack_postcondition, graph, partials),
)
}
}
impl PartialPath {
pub fn ensure_no_overlapping_variables(
&mut self,
partials: &mut PartialPaths,
other: &PartialPath,
) {
let symbol_variable_offset = other.largest_symbol_stack_variable();
let scope_variable_offset = other.largest_scope_stack_variable(partials);
self.symbol_stack_precondition = self.symbol_stack_precondition.with_offset(
partials,
symbol_variable_offset,
scope_variable_offset,
);
self.symbol_stack_postcondition = self.symbol_stack_postcondition.with_offset(
partials,
symbol_variable_offset,
scope_variable_offset,
);
self.scope_stack_precondition = self
.scope_stack_precondition
.with_offset(scope_variable_offset);
self.scope_stack_postcondition = self
.scope_stack_postcondition
.with_offset(scope_variable_offset);
}
pub fn eliminate_precondition_stack_variables(&mut self, partials: &mut PartialPaths) {
let mut symbol_bindings = PartialSymbolStackBindings::new();
let mut scope_bindings = PartialScopeStackBindings::new();
if let Some(symbol_variable) = self.symbol_stack_precondition.variable() {
symbol_bindings
.add(
partials,
symbol_variable,
PartialSymbolStack::empty(),
&mut scope_bindings,
)
.unwrap();
}
if let Some(scope_variable) = self.scope_stack_precondition.variable() {
scope_bindings
.add(partials, scope_variable, PartialScopeStack::empty())
.unwrap();
}
self.symbol_stack_precondition = self
.symbol_stack_precondition
.apply_partial_bindings(partials, &symbol_bindings, &scope_bindings)
.unwrap();
self.scope_stack_precondition = self
.scope_stack_precondition
.apply_partial_bindings(partials, &scope_bindings)
.unwrap();
self.symbol_stack_postcondition = self
.symbol_stack_postcondition
.apply_partial_bindings(partials, &symbol_bindings, &scope_bindings)
.unwrap();
self.scope_stack_postcondition = self
.scope_stack_postcondition
.apply_partial_bindings(partials, &scope_bindings)
.unwrap();
}
pub fn append(
&mut self,
graph: &StackGraph,
partials: &mut PartialPaths,
edge: Edge,
) -> Result<(), PathResolutionError> {
if edge.source != self.end_node {
return Err(PathResolutionError::IncorrectSourceNode);
}
graph[edge.sink].append_to_partial_stacks(
graph,
partials,
&mut self.symbol_stack_precondition,
&mut self.scope_stack_precondition,
&mut self.symbol_stack_postcondition,
&mut self.scope_stack_postcondition,
)?;
self.end_node = edge.sink;
self.edges.push_back(
partials,
PartialPathEdge {
source_node_id: graph[edge.source].id(),
precedence: edge.precedence,
},
);
self.resolve_from_postcondition(graph, partials)?;
Ok(())
}
pub fn resolve_from_postcondition(
&mut self,
graph: &StackGraph,
partials: &mut PartialPaths,
) -> Result<(), PathResolutionError> {
if !graph[self.end_node].is_jump_to() {
return Ok(());
}
if self.scope_stack_postcondition.can_only_match_empty() {
return Err(PathResolutionError::EmptyScopeStack);
}
if !self.scope_stack_postcondition.contains_scopes() {
return Ok(());
}
let top_scope = self.scope_stack_postcondition.pop_front(partials).unwrap();
self.edges.push_back(
partials,
PartialPathEdge {
source_node_id: graph[self.end_node].id(),
precedence: 0,
},
);
self.end_node = top_scope;
Ok(())
}
pub fn resolve_to_node(
&mut self,
graph: &StackGraph,
partials: &mut PartialPaths,
node: Handle<Node>,
) -> Result<(), PathResolutionError> {
if !graph[self.end_node].is_jump_to() {
return Ok(());
}
let scope_variable = match self.scope_stack_postcondition.variable() {
Some(scope_variable) => scope_variable,
None => return Err(PathResolutionError::ScopeStackUnsatisfied),
};
let mut scope_stack = PartialScopeStack::from_variable(scope_variable);
scope_stack.push_front(partials, node);
let symbol_bindings = PartialSymbolStackBindings::new();
let mut scope_bindings = PartialScopeStackBindings::new();
scope_bindings
.add(partials, scope_variable, scope_stack)
.unwrap();
self.symbol_stack_precondition = self
.symbol_stack_precondition
.apply_partial_bindings(partials, &symbol_bindings, &scope_bindings)
.unwrap();
self.scope_stack_precondition = self
.scope_stack_precondition
.apply_partial_bindings(partials, &scope_bindings)
.unwrap();
self.end_node = node;
Ok(())
}
}
impl Node {
pub(crate) fn append_to_partial_stacks(
&self,
graph: &StackGraph,
partials: &mut PartialPaths,
symbol_stack_precondition: &mut PartialSymbolStack,
scope_stack_precondition: &mut PartialScopeStack,
symbol_stack_postcondition: &mut PartialSymbolStack,
scope_stack_postcondition: &mut PartialScopeStack,
) -> Result<(), PathResolutionError> {
match self {
Self::DropScopes(_) => {
*scope_stack_postcondition = PartialScopeStack::empty();
}
Self::JumpTo(_) => {}
Self::PopScopedSymbol(sink) => {
if let Some(top) = symbol_stack_postcondition.pop_front(partials) {
if top.symbol != sink.symbol {
return Err(PathResolutionError::IncorrectPoppedSymbol);
}
let new_scope_stack = match top.scopes.into_option() {
Some(scopes) => scopes,
None => return Err(PathResolutionError::MissingAttachedScopeList),
};
*scope_stack_postcondition = new_scope_stack;
} else if symbol_stack_postcondition.has_variable() {
let scope_stack_variable =
PartialPath::fresh_scope_stack_variable_for_partial_stack(
partials,
symbol_stack_precondition,
scope_stack_precondition,
);
let precondition_symbol = PartialScopedSymbol {
symbol: sink.symbol,
scopes: ControlledOption::some(PartialScopeStack::from_variable(
scope_stack_variable,
)),
};
symbol_stack_precondition.push_back(partials, precondition_symbol);
*scope_stack_postcondition =
PartialScopeStack::from_variable(scope_stack_variable);
} else {
return Err(PathResolutionError::SymbolStackUnsatisfied);
}
}
Self::PopSymbol(sink) => {
if let Some(top) = symbol_stack_postcondition.pop_front(partials) {
if top.symbol != sink.symbol {
return Err(PathResolutionError::IncorrectPoppedSymbol);
}
if top.scopes.is_some() {
return Err(PathResolutionError::UnexpectedAttachedScopeList);
}
} else if symbol_stack_postcondition.has_variable() {
let precondition_symbol = PartialScopedSymbol {
symbol: sink.symbol,
scopes: ControlledOption::none(),
};
symbol_stack_precondition.push_back(partials, precondition_symbol);
} else {
return Err(PathResolutionError::SymbolStackUnsatisfied);
}
}
Self::PushScopedSymbol(sink) => {
let sink_symbol = sink.symbol;
let sink_scope = graph
.node_for_id(sink.scope)
.ok_or(PathResolutionError::UnknownAttachedScope)?;
let mut attached_scopes = scope_stack_postcondition.clone();
attached_scopes.push_front(partials, sink_scope);
let postcondition_symbol = PartialScopedSymbol {
symbol: sink_symbol,
scopes: ControlledOption::some(attached_scopes),
};
symbol_stack_postcondition.push_front(partials, postcondition_symbol);
}
Self::PushSymbol(sink) => {
let sink_symbol = sink.symbol;
let postcondition_symbol = PartialScopedSymbol {
symbol: sink_symbol,
scopes: ControlledOption::none(),
};
symbol_stack_postcondition.push_front(partials, postcondition_symbol);
}
Self::Root(_) => {}
Self::Scope(_) => {}
}
Ok(())
}
fn halfopen_closed_partial_precondition(
&self,
partials: &mut PartialPaths,
symbol_stack: &mut PartialSymbolStack,
scope_stack: &mut PartialScopeStack,
) -> Result<(), PathResolutionError> {
match self {
Node::DropScopes(_) => {}
Node::JumpTo(_) => {}
Node::PopScopedSymbol(node) => {
let symbol = symbol_stack
.pop_front(partials)
.ok_or(PathResolutionError::EmptySymbolStack)?;
if symbol.symbol != node.symbol {
return Err(PathResolutionError::IncorrectPoppedSymbol);
}
*scope_stack = symbol.scopes.into_option().unwrap();
}
Node::PopSymbol(node) => {
let symbol = symbol_stack
.pop_front(partials)
.ok_or(PathResolutionError::EmptySymbolStack)?;
if symbol.symbol != node.symbol {
return Err(PathResolutionError::IncorrectPoppedSymbol);
}
}
Node::PushScopedSymbol(_) => {}
Node::PushSymbol(_) => {}
Node::Root(_) => {}
Node::Scope(_) => {}
};
Ok(())
}
fn halfopen_closed_partial_postcondition(
&self,
partials: &mut PartialPaths,
symbol_stack: &mut PartialSymbolStack,
_scope_stack: &mut PartialScopeStack,
) -> Result<(), PathResolutionError> {
match self {
Self::DropScopes(_) => {}
Self::JumpTo(_) => {}
Self::PopScopedSymbol(_) => {}
Self::PopSymbol(_) => {}
Self::PushScopedSymbol(node) => {
let symbol = symbol_stack
.pop_front(partials)
.ok_or(PathResolutionError::EmptySymbolStack)?;
if symbol.symbol != node.symbol {
return Err(PathResolutionError::IncorrectPoppedSymbol);
}
}
Self::PushSymbol(node) => {
let symbol = symbol_stack
.pop_front(partials)
.ok_or(PathResolutionError::EmptySymbolStack)?;
if symbol.symbol != node.symbol {
return Err(PathResolutionError::IncorrectPoppedSymbol);
}
}
Self::Root(_) => {}
Self::Scope(_) => {}
};
Ok(())
}
}
impl PartialPath {
#[cfg_attr(not(feature = "copious-debugging"), allow(unused_variables))]
pub fn concatenate(
&mut self,
graph: &StackGraph,
partials: &mut PartialPaths,
rhs: &PartialPath,
) -> Result<(), PathResolutionError> {
let lhs = self;
#[cfg_attr(not(feature = "copious-debugging"), allow(unused_mut))]
let mut join = Self::compute_join(graph, partials, lhs, rhs)?;
#[cfg(feature = "copious-debugging")]
{
let unified_symbol_stack = join
.unified_symbol_stack
.display(graph, partials)
.to_string();
let unified_scope_stack = join
.unified_scope_stack
.display(graph, partials)
.to_string();
let symbol_bindings = join.symbol_bindings.display(graph, partials).to_string();
let scope_bindings = join.scope_bindings.display(graph, partials).to_string();
copious_debugging!(
" via <{}> ({}) {} {}",
unified_symbol_stack,
unified_scope_stack,
symbol_bindings,
scope_bindings,
);
}
lhs.symbol_stack_precondition = lhs.symbol_stack_precondition.apply_partial_bindings(
partials,
&join.symbol_bindings,
&join.scope_bindings,
)?;
lhs.symbol_stack_postcondition = rhs.symbol_stack_postcondition.apply_partial_bindings(
partials,
&join.symbol_bindings,
&join.scope_bindings,
)?;
lhs.scope_stack_precondition = lhs
.scope_stack_precondition
.apply_partial_bindings(partials, &join.scope_bindings)?;
lhs.scope_stack_postcondition = rhs
.scope_stack_postcondition
.apply_partial_bindings(partials, &join.scope_bindings)?;
let mut edges = rhs.edges;
while let Some(edge) = edges.pop_front(partials) {
lhs.edges.push_back(partials, edge);
}
lhs.end_node = rhs.end_node;
lhs.resolve_from_postcondition(graph, partials)?;
Ok(())
}
fn compute_join(
graph: &StackGraph,
partials: &mut PartialPaths,
lhs: &PartialPath,
rhs: &PartialPath,
) -> Result<Join, PathResolutionError> {
if lhs.end_node != rhs.start_node {
return Err(PathResolutionError::IncorrectSourceNode);
}
let mut lhs_symbol_stack_postcondition = lhs.symbol_stack_postcondition;
let mut lhs_scope_stack_postcondition = lhs.scope_stack_postcondition;
let mut rhs_symbol_stack_precondition = rhs.symbol_stack_precondition;
let mut rhs_scope_stack_precondition = rhs.scope_stack_precondition;
graph[lhs.end_node]
.halfopen_closed_partial_postcondition(
partials,
&mut lhs_symbol_stack_postcondition,
&mut lhs_scope_stack_postcondition,
)
.unwrap_or_else(|e| {
panic!(
"failed to halfopen postcondition of {}: {:?}",
lhs.display(graph, partials),
e
);
});
graph[rhs.start_node]
.halfopen_closed_partial_precondition(
partials,
&mut rhs_symbol_stack_precondition,
&mut rhs_scope_stack_precondition,
)
.unwrap_or_else(|e| {
panic!(
"failed to halfopen postcondition of {}: {:?}",
rhs.display(graph, partials),
e
);
});
let mut symbol_bindings = PartialSymbolStackBindings::new();
let mut scope_bindings = PartialScopeStackBindings::new();
let unified_symbol_stack = lhs_symbol_stack_postcondition.unify(
partials,
rhs_symbol_stack_precondition,
&mut symbol_bindings,
&mut scope_bindings,
)?;
let unified_scope_stack = lhs_scope_stack_postcondition.unify(
partials,
rhs_scope_stack_precondition,
&mut scope_bindings,
)?;
Ok(Join {
unified_symbol_stack,
unified_scope_stack,
symbol_bindings,
scope_bindings,
})
}
}
struct Join {
#[cfg_attr(not(feature = "copious-debugging"), allow(dead_code))]
pub unified_symbol_stack: PartialSymbolStack,
#[cfg_attr(not(feature = "copious-debugging"), allow(dead_code))]
pub unified_scope_stack: PartialScopeStack,
pub symbol_bindings: PartialSymbolStackBindings,
pub scope_bindings: PartialScopeStackBindings,
}
pub struct PartialPaths {
pub(crate) partial_symbol_stacks: DequeArena<PartialScopedSymbol>,
pub(crate) partial_scope_stacks: DequeArena<Handle<Node>>,
pub(crate) partial_path_edges: DequeArena<PartialPathEdge>,
}
impl PartialPaths {
pub fn new() -> PartialPaths {
PartialPaths {
partial_symbol_stacks: Deque::new_arena(),
partial_scope_stacks: Deque::new_arena(),
partial_path_edges: Deque::new_arena(),
}
}
#[cfg_attr(not(feature = "storage"), allow(dead_code))]
pub(crate) fn clear(&mut self) {
self.partial_symbol_stacks.clear();
self.partial_scope_stacks.clear();
self.partial_path_edges.clear();
}
}