use crate::token::{Tin, Token};
use crate::value::Value;
use crate::Lexer;
use crate::{ActionError, Context, ContextAction};
use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt;
use std::rc::Rc;
use std::sync::Arc;
pub type AltCondition = Arc<dyn Fn(&mut Rule, &mut Context) -> bool + Send + Sync>;
pub type AltConditionWithMatch =
Arc<dyn Fn(&mut Rule, &mut Context, &mut AltMatch) -> bool + Send + Sync>;
pub type AltConditionWithLexer =
Arc<dyn for<'source> Fn(&mut Rule, &mut Context, &mut Lexer<'source>) -> bool + Send + Sync>;
pub type AltConditionWithLexerAndMatch = Arc<
dyn for<'source> Fn(&mut Rule, &mut Context, &mut AltMatch, &mut Lexer<'source>) -> bool
+ Send
+ Sync,
>;
pub type AltNext = Arc<dyn Fn(&mut Rule, &mut Context) -> Option<String> + Send + Sync>;
pub type AltNextWithMatch =
Arc<dyn Fn(&mut Rule, &mut Context, &mut AltMatch) -> Option<String> + Send + Sync>;
pub type AltBack = Arc<dyn Fn(&mut Rule, &mut Context) -> usize + Send + Sync>;
pub type AltBackWithMatch =
Arc<dyn Fn(&mut Rule, &mut Context, &mut AltMatch) -> usize + Send + Sync>;
pub type AltError = Arc<dyn Fn(&mut Rule, &mut Context) -> Option<Token> + Send + Sync>;
pub type AltErrorWithMatch =
Arc<dyn Fn(&mut Rule, &mut Context, &mut AltMatch) -> Option<Token> + Send + Sync>;
pub type AltModifier = Arc<dyn Fn(AltSpec, &mut Rule, &mut Context) -> AltSpec + Send + Sync>;
pub type AltModifierWithMatch =
Arc<dyn Fn(AltMatch, &mut Rule, &mut Context, Option<&RuleSnapshot>) -> AltMatch + Send + Sync>;
pub type AltAction = Arc<
dyn Fn(&mut Rule, &mut Context, &mut AltMatch) -> Result<Option<Token>, ActionError>
+ Send
+ Sync,
>;
#[derive(Clone)]
pub enum AltActionBinding {
Named(String),
Context(ContextAction),
Matched(AltAction),
}
#[derive(Clone)]
pub enum ActionBinding {
Named(String),
Callback(ContextAction),
State(StateAction),
}
pub type StateAction = Arc<
dyn Fn(
&mut Rule,
&mut Context,
Option<&RuleSnapshot>,
Option<Token>,
) -> Result<Option<Token>, ActionError>
+ Send
+ Sync,
>;
#[derive(Clone, Default)]
pub struct AltMatch {
pub p: Option<String>,
pub r: Option<String>,
pub b: usize,
pub n: HashMap<String, i32>,
pub u: HashMap<String, Value>,
pub k: HashMap<String, Value>,
pub g: Vec<String>,
pub e: Option<Box<Token>>,
pub h: Option<AltModifierWithMatch>,
pub actions: Vec<AltActionBinding>,
pub action_configs: HashMap<String, Value>,
}
impl AltMatch {
pub(crate) fn reset(&mut self) {
self.p = None;
self.r = None;
self.b = 0;
self.e = None;
self.h = None;
if !self.n.is_empty() {
self.n.clear();
}
if !self.u.is_empty() {
self.u.clear();
}
if !self.k.is_empty() {
self.k.clear();
}
if !self.g.is_empty() {
self.g.clear();
}
if !self.actions.is_empty() {
self.actions.clear();
}
if !self.action_configs.is_empty() {
self.action_configs.clear();
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RuleState {
Open,
Close,
}
#[derive(Debug, Clone, PartialEq)]
pub struct RuleDoneAlt {
pub b: usize,
pub g: Vec<String>,
pub p: String,
pub r: String,
pub err: Option<Token>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct RuleDone {
pub state: RuleState,
pub alt: Option<RuleDoneAlt>,
pub forced: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CompareOp {
Eq,
Ne,
Lt,
Lte,
Gt,
Gte,
Exist,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Condition {
pub path: Vec<String>,
pub op: CompareOp,
pub value: Value,
}
#[derive(Clone, Default)]
pub struct AltSpec {
pub s: Vec<Vec<Tin>>,
pub s_names: Vec<Vec<String>>,
pub s_bound: Vec<Vec<Tin>>,
pub p: Option<String>,
pub p_fn: Option<AltNext>,
pub p_match: Option<AltNextWithMatch>,
pub r: Option<String>,
pub r_fn: Option<AltNext>,
pub r_match: Option<AltNextWithMatch>,
pub b: usize,
pub b_fn: Option<AltBack>,
pub b_match: Option<AltBackWithMatch>,
pub a: Vec<String>,
pub action_fns: Vec<ContextAction>,
pub action_order: Vec<AltActionBinding>,
pub matched_action_fns: Vec<AltAction>,
pub action_configs: HashMap<String, Value>,
pub c: Vec<Condition>,
pub c_ref: Option<String>,
pub c_fn: Option<AltCondition>,
pub c_match: Option<AltConditionWithMatch>,
pub c_lex: Option<AltConditionWithLexer>,
pub c_lex_match: Option<AltConditionWithLexerAndMatch>,
pub n: HashMap<String, i32>,
pub u: HashMap<String, Value>,
pub k: HashMap<String, Value>,
pub g: String,
pub h: Option<AltModifier>,
pub h_match: Option<AltModifierWithMatch>,
pub e: Option<AltError>,
pub e_match: Option<AltErrorWithMatch>,
}
impl AltSpec {
pub fn new() -> Self {
Self::default()
}
}
#[derive(Clone)]
pub struct RuleSpec {
pub name: String,
pub open: Vec<AltSpec>,
pub close: Vec<AltSpec>,
pub bo: Vec<String>,
pub ao: Vec<String>,
pub bc: Vec<String>,
pub ac: Vec<String>,
pub bo_fns: Vec<ContextAction>,
pub ao_fns: Vec<ContextAction>,
pub bc_fns: Vec<ContextAction>,
pub ac_fns: Vec<ContextAction>,
pub bo_state_fns: Vec<StateAction>,
pub ao_state_fns: Vec<StateAction>,
pub bc_state_fns: Vec<StateAction>,
pub ac_state_fns: Vec<StateAction>,
pub bo_order: Vec<ActionBinding>,
pub ao_order: Vec<ActionBinding>,
pub bc_order: Vec<ActionBinding>,
pub ac_order: Vec<ActionBinding>,
}
impl fmt::Debug for RuleSpec {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("RuleSpec")
.field("name", &self.name)
.field("open", &self.open.len())
.field("close", &self.close.len())
.field("bo", &self.bo.len())
.field("ao", &self.ao.len())
.field("bc", &self.bc.len())
.field("ac", &self.ac.len())
.finish_non_exhaustive()
}
}
impl RuleSpec {
pub fn new(name: impl Into<String>) -> Self {
RuleSpec {
name: name.into(),
open: Vec::new(),
close: Vec::new(),
bo: Vec::new(),
ao: Vec::new(),
bc: Vec::new(),
ac: Vec::new(),
bo_fns: Vec::new(),
ao_fns: Vec::new(),
bc_fns: Vec::new(),
ac_fns: Vec::new(),
bo_state_fns: Vec::new(),
ao_state_fns: Vec::new(),
bc_state_fns: Vec::new(),
ac_state_fns: Vec::new(),
bo_order: Vec::new(),
ao_order: Vec::new(),
bc_order: Vec::new(),
ac_order: Vec::new(),
}
}
pub fn clear(&mut self) -> &mut Self {
self.open.clear();
self.close.clear();
self.clear_actions(&[]);
self
}
pub fn add_open(&mut self, alt: AltSpec) -> &mut Self {
self.open.push(alt);
self
}
pub fn prepend_open(&mut self, alt: AltSpec) -> &mut Self {
self.open.insert(0, alt);
self
}
pub fn add_close(&mut self, alt: AltSpec) -> &mut Self {
self.close.push(alt);
self
}
pub fn prepend_close(&mut self, alt: AltSpec) -> &mut Self {
self.close.insert(0, alt);
self
}
pub fn clear_open(&mut self) -> &mut Self {
self.open.clear();
self
}
pub fn clear_close(&mut self) -> &mut Self {
self.close.clear();
self
}
pub fn modify_open(&mut self, mods: &crate::utility::ListMods<AltSpec>) -> &mut Self {
self.open = crate::utility::modlist(std::mem::take(&mut self.open), Some(mods));
self
}
pub fn modify_close(&mut self, mods: &crate::utility::ListMods<AltSpec>) -> &mut Self {
self.close = crate::utility::modlist(std::mem::take(&mut self.close), Some(mods));
self
}
pub fn add_bo(
&mut self,
action: impl Fn(&mut Rule, &mut Context) + Send + Sync + 'static,
) -> &mut Self {
prepare_order(
&self.bo,
&self.bo_fns,
&self.bo_state_fns,
&mut self.bo_order,
);
let action = infallible_action(action);
self.bo_fns.push(action.clone());
self.bo_order.push(ActionBinding::Callback(action));
self
}
pub fn prepend_bo(
&mut self,
action: impl Fn(&mut Rule, &mut Context) + Send + Sync + 'static,
) -> &mut Self {
prepare_order(
&self.bo,
&self.bo_fns,
&self.bo_state_fns,
&mut self.bo_order,
);
let action = infallible_action(action);
self.bo_fns.insert(0, action.clone());
self.bo_order.insert(0, ActionBinding::Callback(action));
self
}
pub fn add_ao(
&mut self,
action: impl Fn(&mut Rule, &mut Context) + Send + Sync + 'static,
) -> &mut Self {
prepare_order(
&self.ao,
&self.ao_fns,
&self.ao_state_fns,
&mut self.ao_order,
);
let action = infallible_action(action);
self.ao_fns.push(action.clone());
self.ao_order.push(ActionBinding::Callback(action));
self
}
pub fn prepend_ao(
&mut self,
action: impl Fn(&mut Rule, &mut Context) + Send + Sync + 'static,
) -> &mut Self {
prepare_order(
&self.ao,
&self.ao_fns,
&self.ao_state_fns,
&mut self.ao_order,
);
let action = infallible_action(action);
self.ao_fns.insert(0, action.clone());
self.ao_order.insert(0, ActionBinding::Callback(action));
self
}
pub fn add_bc(
&mut self,
action: impl Fn(&mut Rule, &mut Context) + Send + Sync + 'static,
) -> &mut Self {
prepare_order(
&self.bc,
&self.bc_fns,
&self.bc_state_fns,
&mut self.bc_order,
);
let action = infallible_action(action);
self.bc_fns.push(action.clone());
self.bc_order.push(ActionBinding::Callback(action));
self
}
pub fn prepend_bc(
&mut self,
action: impl Fn(&mut Rule, &mut Context) + Send + Sync + 'static,
) -> &mut Self {
prepare_order(
&self.bc,
&self.bc_fns,
&self.bc_state_fns,
&mut self.bc_order,
);
let action = infallible_action(action);
self.bc_fns.insert(0, action.clone());
self.bc_order.insert(0, ActionBinding::Callback(action));
self
}
pub fn add_ac(
&mut self,
action: impl Fn(&mut Rule, &mut Context) + Send + Sync + 'static,
) -> &mut Self {
prepare_order(
&self.ac,
&self.ac_fns,
&self.ac_state_fns,
&mut self.ac_order,
);
let action = infallible_action(action);
self.ac_fns.push(action.clone());
self.ac_order.push(ActionBinding::Callback(action));
self
}
pub fn prepend_ac(
&mut self,
action: impl Fn(&mut Rule, &mut Context) + Send + Sync + 'static,
) -> &mut Self {
prepare_order(
&self.ac,
&self.ac_fns,
&self.ac_state_fns,
&mut self.ac_order,
);
let action = infallible_action(action);
self.ac_fns.insert(0, action.clone());
self.ac_order.insert(0, ActionBinding::Callback(action));
self
}
pub fn add_bo_result(&mut self, action: ContextAction) -> &mut Self {
prepare_order(
&self.bo,
&self.bo_fns,
&self.bo_state_fns,
&mut self.bo_order,
);
self.bo_fns.push(action.clone());
self.bo_order.push(ActionBinding::Callback(action));
self
}
pub fn add_ao_result(&mut self, action: ContextAction) -> &mut Self {
prepare_order(
&self.ao,
&self.ao_fns,
&self.ao_state_fns,
&mut self.ao_order,
);
self.ao_fns.push(action.clone());
self.ao_order.push(ActionBinding::Callback(action));
self
}
pub fn add_bc_result(&mut self, action: ContextAction) -> &mut Self {
prepare_order(
&self.bc,
&self.bc_fns,
&self.bc_state_fns,
&mut self.bc_order,
);
self.bc_fns.push(action.clone());
self.bc_order.push(ActionBinding::Callback(action));
self
}
pub fn add_ac_result(&mut self, action: ContextAction) -> &mut Self {
prepare_order(
&self.ac,
&self.ac_fns,
&self.ac_state_fns,
&mut self.ac_order,
);
self.ac_fns.push(action.clone());
self.ac_order.push(ActionBinding::Callback(action));
self
}
pub fn add_bo_with_state(&mut self, action: StateAction) -> &mut Self {
prepare_order(
&self.bo,
&self.bo_fns,
&self.bo_state_fns,
&mut self.bo_order,
);
self.bo_state_fns.push(action.clone());
self.bo_order.push(ActionBinding::State(action));
self
}
pub fn prepend_bo_with_state(&mut self, action: StateAction) -> &mut Self {
prepare_order(
&self.bo,
&self.bo_fns,
&self.bo_state_fns,
&mut self.bo_order,
);
self.bo_state_fns.insert(0, action.clone());
self.bo_order.insert(0, ActionBinding::State(action));
self
}
pub fn add_ao_with_state(&mut self, action: StateAction) -> &mut Self {
prepare_order(
&self.ao,
&self.ao_fns,
&self.ao_state_fns,
&mut self.ao_order,
);
self.ao_state_fns.push(action.clone());
self.ao_order.push(ActionBinding::State(action));
self
}
pub fn prepend_ao_with_state(&mut self, action: StateAction) -> &mut Self {
prepare_order(
&self.ao,
&self.ao_fns,
&self.ao_state_fns,
&mut self.ao_order,
);
self.ao_state_fns.insert(0, action.clone());
self.ao_order.insert(0, ActionBinding::State(action));
self
}
pub fn add_bc_with_state(&mut self, action: StateAction) -> &mut Self {
prepare_order(
&self.bc,
&self.bc_fns,
&self.bc_state_fns,
&mut self.bc_order,
);
self.bc_state_fns.push(action.clone());
self.bc_order.push(ActionBinding::State(action));
self
}
pub fn prepend_bc_with_state(&mut self, action: StateAction) -> &mut Self {
prepare_order(
&self.bc,
&self.bc_fns,
&self.bc_state_fns,
&mut self.bc_order,
);
self.bc_state_fns.insert(0, action.clone());
self.bc_order.insert(0, ActionBinding::State(action));
self
}
pub fn add_ac_with_state(&mut self, action: StateAction) -> &mut Self {
prepare_order(
&self.ac,
&self.ac_fns,
&self.ac_state_fns,
&mut self.ac_order,
);
self.ac_state_fns.push(action.clone());
self.ac_order.push(ActionBinding::State(action));
self
}
pub fn prepend_ac_with_state(&mut self, action: StateAction) -> &mut Self {
prepare_order(
&self.ac,
&self.ac_fns,
&self.ac_state_fns,
&mut self.ac_order,
);
self.ac_state_fns.insert(0, action.clone());
self.ac_order.insert(0, ActionBinding::State(action));
self
}
pub fn add_bo_ref(&mut self, action: impl Into<String>) -> &mut Self {
add_named(
&mut self.bo,
&mut self.bo_fns,
&mut self.bo_state_fns,
&mut self.bo_order,
action.into(),
false,
);
self
}
pub fn prepend_bo_ref(&mut self, action: impl Into<String>) -> &mut Self {
add_named(
&mut self.bo,
&mut self.bo_fns,
&mut self.bo_state_fns,
&mut self.bo_order,
action.into(),
true,
);
self
}
pub fn add_ao_ref(&mut self, action: impl Into<String>) -> &mut Self {
add_named(
&mut self.ao,
&mut self.ao_fns,
&mut self.ao_state_fns,
&mut self.ao_order,
action.into(),
false,
);
self
}
pub fn prepend_ao_ref(&mut self, action: impl Into<String>) -> &mut Self {
add_named(
&mut self.ao,
&mut self.ao_fns,
&mut self.ao_state_fns,
&mut self.ao_order,
action.into(),
true,
);
self
}
pub fn add_bc_ref(&mut self, action: impl Into<String>) -> &mut Self {
add_named(
&mut self.bc,
&mut self.bc_fns,
&mut self.bc_state_fns,
&mut self.bc_order,
action.into(),
false,
);
self
}
pub fn prepend_bc_ref(&mut self, action: impl Into<String>) -> &mut Self {
add_named(
&mut self.bc,
&mut self.bc_fns,
&mut self.bc_state_fns,
&mut self.bc_order,
action.into(),
true,
);
self
}
pub fn add_ac_ref(&mut self, action: impl Into<String>) -> &mut Self {
add_named(
&mut self.ac,
&mut self.ac_fns,
&mut self.ac_state_fns,
&mut self.ac_order,
action.into(),
false,
);
self
}
pub fn prepend_ac_ref(&mut self, action: impl Into<String>) -> &mut Self {
add_named(
&mut self.ac,
&mut self.ac_fns,
&mut self.ac_state_fns,
&mut self.ac_order,
action.into(),
true,
);
self
}
pub fn clear_actions(&mut self, phases: &[&str]) -> &mut Self {
let clear_all = phases.is_empty();
for phase in ["bo", "ao", "bc", "ac"] {
if clear_all || phases.contains(&phase) {
match phase {
"bo" => {
self.bo.clear();
self.bo_fns.clear();
self.bo_state_fns.clear();
self.bo_order.clear();
}
"ao" => {
self.ao.clear();
self.ao_fns.clear();
self.ao_state_fns.clear();
self.ao_order.clear();
}
"bc" => {
self.bc.clear();
self.bc_fns.clear();
self.bc_state_fns.clear();
self.bc_order.clear();
}
"ac" => {
self.ac.clear();
self.ac_fns.clear();
self.ac_state_fns.clear();
self.ac_order.clear();
}
_ => unreachable!(),
}
}
}
self
}
}
fn infallible_action(
action: impl Fn(&mut Rule, &mut Context) + Send + Sync + 'static,
) -> ContextAction {
Arc::new(move |rule, context| {
action(rule, context);
Ok::<(), ActionError>(())
})
}
impl AltSpec {
pub fn add_action(
&mut self,
action: impl Fn(&mut Rule, &mut Context) + Send + Sync + 'static,
) -> &mut Self {
prepare_alt_order(
&self.a,
&self.action_fns,
&self.matched_action_fns,
&mut self.action_order,
);
let action = infallible_action(action);
self.action_fns.push(action.clone());
self.action_order.push(AltActionBinding::Context(action));
self
}
pub fn prepend_action(
&mut self,
action: impl Fn(&mut Rule, &mut Context) + Send + Sync + 'static,
) -> &mut Self {
prepare_alt_order(
&self.a,
&self.action_fns,
&self.matched_action_fns,
&mut self.action_order,
);
let action = infallible_action(action);
self.action_fns.insert(0, action.clone());
self.action_order
.insert(0, AltActionBinding::Context(action));
self
}
pub fn add_action_result(&mut self, action: ContextAction) -> &mut Self {
prepare_alt_order(
&self.a,
&self.action_fns,
&self.matched_action_fns,
&mut self.action_order,
);
self.action_fns.push(action.clone());
self.action_order.push(AltActionBinding::Context(action));
self
}
pub fn prepend_action_result(&mut self, action: ContextAction) -> &mut Self {
prepare_alt_order(
&self.a,
&self.action_fns,
&self.matched_action_fns,
&mut self.action_order,
);
self.action_fns.insert(0, action.clone());
self.action_order
.insert(0, AltActionBinding::Context(action));
self
}
pub fn add_action_with_match(
&mut self,
action: impl Fn(&mut Rule, &mut Context, &AltMatch) -> Option<Token> + Send + Sync + 'static,
) -> &mut Self {
self.add_action_with_match_result(Arc::new(move |rule, context, matched| {
Ok(action(rule, context, matched))
}))
}
pub fn prepend_action_with_match(
&mut self,
action: impl Fn(&mut Rule, &mut Context, &AltMatch) -> Option<Token> + Send + Sync + 'static,
) -> &mut Self {
self.prepend_action_with_match_result(Arc::new(move |rule, context, matched| {
Ok(action(rule, context, matched))
}))
}
pub fn add_action_with_match_result(&mut self, action: AltAction) -> &mut Self {
prepare_alt_order(
&self.a,
&self.action_fns,
&self.matched_action_fns,
&mut self.action_order,
);
self.matched_action_fns.push(action.clone());
self.action_order.push(AltActionBinding::Matched(action));
self
}
pub fn prepend_action_with_match_result(&mut self, action: AltAction) -> &mut Self {
prepare_alt_order(
&self.a,
&self.action_fns,
&self.matched_action_fns,
&mut self.action_order,
);
self.matched_action_fns.insert(0, action.clone());
self.action_order
.insert(0, AltActionBinding::Matched(action));
self
}
pub fn add_action_ref(&mut self, action: impl Into<String>) -> &mut Self {
add_alt_named(
&mut self.a,
&mut self.action_fns,
&mut self.matched_action_fns,
&mut self.action_order,
action.into(),
false,
);
self
}
pub fn prepend_action_ref(&mut self, action: impl Into<String>) -> &mut Self {
add_alt_named(
&mut self.a,
&mut self.action_fns,
&mut self.matched_action_fns,
&mut self.action_order,
action.into(),
true,
);
self
}
}
fn alt_order_matches(
named: &[String],
callbacks: &[ContextAction],
matched: &[AltAction],
order: &[AltActionBinding],
) -> bool {
if order.len() != named.len() + callbacks.len() + matched.len() {
return false;
}
let (mut next_name, mut next_callback, mut next_matched) = (0, 0, 0);
for binding in order {
match binding {
AltActionBinding::Named(name) => {
if named.get(next_name) != Some(name) {
return false;
}
next_name += 1;
}
AltActionBinding::Context(callback) => {
if !callbacks
.get(next_callback)
.is_some_and(|expected| Arc::ptr_eq(expected, callback))
{
return false;
}
next_callback += 1;
}
AltActionBinding::Matched(callback) => {
if !matched
.get(next_matched)
.is_some_and(|expected| Arc::ptr_eq(expected, callback))
{
return false;
}
next_matched += 1;
}
}
}
next_name == named.len() && next_callback == callbacks.len() && next_matched == matched.len()
}
fn prepare_alt_order(
named: &[String],
callbacks: &[ContextAction],
matched: &[AltAction],
order: &mut Vec<AltActionBinding>,
) {
if !alt_order_matches(named, callbacks, matched, order) {
*order = named
.iter()
.cloned()
.map(AltActionBinding::Named)
.chain(callbacks.iter().cloned().map(AltActionBinding::Context))
.chain(matched.iter().cloned().map(AltActionBinding::Matched))
.collect();
}
}
fn add_alt_named(
named: &mut Vec<String>,
callbacks: &mut Vec<ContextAction>,
matched: &mut Vec<AltAction>,
order: &mut Vec<AltActionBinding>,
action: String,
prepend: bool,
) {
prepare_alt_order(named, callbacks, matched, order);
if prepend {
named.insert(0, action.clone());
order.insert(0, AltActionBinding::Named(action));
} else {
named.push(action.clone());
order.push(AltActionBinding::Named(action));
}
}
pub(crate) fn resolved_alt_action_order(
named: &[String],
callbacks: &[ContextAction],
matched: &[AltAction],
order: &[AltActionBinding],
) -> Vec<AltActionBinding> {
if alt_order_matches(named, callbacks, matched, order) {
order.to_vec()
} else {
named
.iter()
.cloned()
.map(AltActionBinding::Named)
.chain(callbacks.iter().cloned().map(AltActionBinding::Context))
.chain(matched.iter().cloned().map(AltActionBinding::Matched))
.collect()
}
}
fn order_matches(
named: &[String],
callbacks: &[ContextAction],
states: &[StateAction],
order: &[ActionBinding],
) -> bool {
if order.len() != named.len() + callbacks.len() + states.len() {
return false;
}
let (mut next_name, mut next_callback, mut next_state) = (0, 0, 0);
for binding in order {
match binding {
ActionBinding::Named(name) => {
if named.get(next_name) != Some(name) {
return false;
}
next_name += 1;
}
ActionBinding::Callback(callback) => {
if !callbacks
.get(next_callback)
.is_some_and(|expected| Arc::ptr_eq(expected, callback))
{
return false;
}
next_callback += 1;
}
ActionBinding::State(callback) => {
if !states
.get(next_state)
.is_some_and(|expected| Arc::ptr_eq(expected, callback))
{
return false;
}
next_state += 1;
}
}
}
next_name == named.len() && next_callback == callbacks.len() && next_state == states.len()
}
fn prepare_order(
named: &[String],
callbacks: &[ContextAction],
states: &[StateAction],
order: &mut Vec<ActionBinding>,
) {
if !order_matches(named, callbacks, states, order) {
*order = named
.iter()
.cloned()
.map(ActionBinding::Named)
.chain(callbacks.iter().cloned().map(ActionBinding::Callback))
.chain(states.iter().cloned().map(ActionBinding::State))
.collect();
}
}
fn add_named(
named: &mut Vec<String>,
callbacks: &mut Vec<ContextAction>,
states: &mut Vec<StateAction>,
order: &mut Vec<ActionBinding>,
action: String,
prepend: bool,
) {
prepare_order(named, callbacks, states, order);
if prepend {
named.insert(0, action.clone());
order.insert(0, ActionBinding::Named(action));
} else {
named.push(action.clone());
order.push(ActionBinding::Named(action));
}
}
pub(crate) fn resolved_action_order(
named: &[String],
callbacks: &[ContextAction],
states: &[StateAction],
order: &[ActionBinding],
) -> Vec<ActionBinding> {
if order_matches(named, callbacks, states, order) {
order.to_vec()
} else {
named
.iter()
.cloned()
.map(ActionBinding::Named)
.chain(callbacks.iter().cloned().map(ActionBinding::Callback))
.chain(states.iter().cloned().map(ActionBinding::State))
.collect()
}
}
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct RuleName(Arc<str>);
impl RuleName {
pub fn as_str(&self) -> &str {
&self.0
}
}
impl std::ops::Deref for RuleName {
type Target = str;
fn deref(&self) -> &str {
&self.0
}
}
impl AsRef<str> for RuleName {
fn as_ref(&self) -> &str {
&self.0
}
}
impl std::borrow::Borrow<str> for RuleName {
fn borrow(&self) -> &str {
&self.0
}
}
impl fmt::Debug for RuleName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&*self.0, f)
}
}
impl fmt::Display for RuleName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
}
impl PartialEq<str> for RuleName {
fn eq(&self, other: &str) -> bool {
&*self.0 == other
}
}
impl PartialEq<&str> for RuleName {
fn eq(&self, other: &&str) -> bool {
&*self.0 == *other
}
}
impl PartialEq<String> for RuleName {
fn eq(&self, other: &String) -> bool {
&*self.0 == other.as_str()
}
}
impl PartialEq<RuleName> for str {
fn eq(&self, other: &RuleName) -> bool {
self == &*other.0
}
}
impl PartialEq<RuleName> for &str {
fn eq(&self, other: &RuleName) -> bool {
*self == &*other.0
}
}
impl PartialEq<RuleName> for String {
fn eq(&self, other: &RuleName) -> bool {
self.as_str() == &*other.0
}
}
impl From<&str> for RuleName {
fn from(name: &str) -> Self {
RuleName(Arc::from(name))
}
}
impl From<String> for RuleName {
fn from(name: String) -> Self {
RuleName(Arc::from(name.as_str()))
}
}
impl From<&String> for RuleName {
fn from(name: &String) -> Self {
RuleName(Arc::from(name.as_str()))
}
}
impl From<Arc<str>> for RuleName {
fn from(name: Arc<str>) -> Self {
RuleName(name)
}
}
impl From<RuleName> for String {
fn from(name: RuleName) -> Self {
name.0.to_string()
}
}
#[derive(Clone)]
pub struct Rule {
shared: Rc<RuleSnapshot>,
pub parent_node: Option<Rc<RefCell<Value>>>,
pub child_node: Value,
pub(crate) skip_befores: bool,
pub(crate) child_node_is_self: bool,
pub(crate) child_link_open: bool,
pub(crate) child_cell: Option<Rc<RefCell<Value>>>,
pub(crate) child_record: Option<Rc<RuleSnapshot>>,
pub(crate) slot: usize,
}
impl Drop for RuleSnapshot {
fn drop(&mut self) {
if self.parent_rule.is_none()
&& self.child_rule.is_none()
&& self.prev_rule.is_none()
&& self.next_rule.is_none()
{
return;
}
fn unlink(
snapshot: &mut RuleSnapshot,
cursor: &mut Option<Rc<RuleSnapshot>>,
pending: &mut Vec<Rc<RuleSnapshot>>,
) {
let mut hold = |held: Option<Rc<RuleSnapshot>>| {
if let Some(held) = held {
if cursor.is_none() {
*cursor = Some(held);
} else {
pending.push(held);
}
}
};
hold(snapshot.parent_rule.take());
hold(snapshot.child_rule.take());
hold(snapshot.prev_rule.take());
hold(snapshot.next_rule.take());
}
let mut cursor: Option<Rc<RuleSnapshot>> = None;
let mut pending: Vec<Rc<RuleSnapshot>> = Vec::new();
unlink(self, &mut cursor, &mut pending);
while let Some(mut link) = cursor.take().or_else(|| pending.pop()) {
if Rc::weak_count(&link) == 0 {
if let Some(owned) = Rc::get_mut(&mut link) {
unlink(owned, &mut cursor, &mut pending);
}
} else if let Ok(mut owned) = Rc::try_unwrap(link) {
unlink(&mut owned, &mut cursor, &mut pending);
}
}
}
}
impl std::ops::Deref for Rule {
type Target = RuleSnapshot;
fn deref(&self) -> &RuleSnapshot {
&self.shared
}
}
impl std::ops::DerefMut for Rule {
fn deref_mut(&mut self) -> &mut RuleSnapshot {
Rc::make_mut(&mut self.shared)
}
}
#[derive(Debug, Clone)]
pub struct RuleSnapshot {
pub i: usize,
pub d: usize,
pub name: RuleName,
pub spec: Arc<RuleSpec>,
pub state: RuleState,
pub bo: bool,
pub ao: bool,
pub bc: bool,
pub ac: bool,
pub need: i32,
pub node: Rc<RefCell<Value>>,
pub parent_rule: Option<Rc<RuleSnapshot>>,
pub child_rule: Option<Rc<RuleSnapshot>>,
pub prev_rule: Option<Rc<RuleSnapshot>>,
pub next_rule: Option<Rc<RuleSnapshot>>,
pub next_rule_name: Option<RuleName>,
pub n: Rc<HashMap<String, i32>>,
pub u: Rc<HashMap<String, Value>>,
pub k: Rc<HashMap<String, Value>>,
pub o: Rc<Vec<Token>>,
pub c: Rc<Vec<Token>>,
}
fn empty_counters() -> Rc<HashMap<String, i32>> {
thread_local! {
static EMPTY: Rc<HashMap<String, i32>> = Rc::new(HashMap::new());
}
EMPTY.with(Rc::clone)
}
fn empty_values() -> Rc<HashMap<String, Value>> {
thread_local! {
static EMPTY: Rc<HashMap<String, Value>> = Rc::new(HashMap::new());
}
EMPTY.with(Rc::clone)
}
fn empty_tokens() -> Rc<Vec<Token>> {
thread_local! {
static EMPTY: Rc<Vec<Token>> = Rc::new(Vec::new());
}
EMPTY.with(Rc::clone)
}
impl Rule {
pub fn n_mut(&mut self) -> &mut HashMap<String, i32> {
Rc::make_mut(&mut self.n)
}
pub fn u_mut(&mut self) -> &mut HashMap<String, Value> {
Rc::make_mut(&mut self.u)
}
pub fn k_mut(&mut self) -> &mut HashMap<String, Value> {
Rc::make_mut(&mut self.k)
}
pub fn new(name: impl Into<RuleName>, initial_node: Value) -> Self {
let name: RuleName = name.into();
let spec = Arc::new(RuleSpec::new(name.as_str()));
Rule {
shared: Rc::new(RuleSnapshot {
i: 0,
d: 0,
name,
spec,
state: RuleState::Open,
bo: true,
ao: true,
bc: true,
ac: true,
need: 0,
node: Rc::new(RefCell::new(initial_node)),
parent_rule: None,
child_rule: None,
prev_rule: None,
next_rule: None,
next_rule_name: None,
n: empty_counters(),
u: empty_values(),
k: empty_values(),
o: empty_tokens(),
c: empty_tokens(),
}),
parent_node: None,
child_node: Value::Undefined,
skip_befores: false,
child_node_is_self: false,
child_link_open: false,
child_cell: None,
child_record: None,
slot: usize::MAX,
}
}
pub fn with_shared_node(name: impl Into<RuleName>, node: Rc<RefCell<Value>>) -> Self {
Self::bound(name.into(), node, None, usize::MAX)
}
pub(crate) fn bound(
name: RuleName,
node: Rc<RefCell<Value>>,
installed: Option<&Arc<RuleSpec>>,
slot: usize,
) -> Self {
let spec = match installed {
Some(spec) => Arc::clone(spec),
None => Arc::new(RuleSpec::new(name.as_str())),
};
Rule {
shared: Rc::new(RuleSnapshot {
i: 0,
d: 0,
name,
spec,
state: RuleState::Open,
bo: true,
ao: true,
bc: true,
ac: true,
need: 0,
node,
parent_rule: None,
child_rule: None,
prev_rule: None,
next_rule: None,
next_rule_name: None,
n: empty_counters(),
u: empty_values(),
k: empty_values(),
o: empty_tokens(),
c: empty_tokens(),
}),
parent_node: None,
child_node: Value::Undefined,
skip_befores: false,
child_node_is_self: false,
child_link_open: false,
child_cell: None,
child_record: None,
slot,
}
}
pub(crate) fn bind_spec(&mut self, spec: &Arc<RuleSpec>, name: RuleName, slot: usize) {
self.name = name;
self.spec = Arc::clone(spec);
self.slot = slot;
self.bo = true;
self.ao = true;
self.bc = true;
self.ac = true;
}
pub fn o0(&self) -> Option<&Token> {
self.o.first()
}
pub fn o1(&self) -> Option<&Token> {
self.o.get(1)
}
pub fn c0(&self) -> Option<&Token> {
self.c.first()
}
pub fn c1(&self) -> Option<&Token> {
self.c.get(1)
}
pub fn os(&self) -> usize {
self.o.len()
}
pub fn cs(&self) -> usize {
self.c.len()
}
pub fn resolve_open_value(&mut self, index: usize, context: &mut Context) -> Value {
self.o
.get(index)
.cloned()
.map_or(Value::Undefined, |token| token.resolve_val(self, context))
}
pub fn resolve_close_value(&mut self, index: usize, context: &mut Context) -> Value {
self.c
.get(index)
.cloned()
.map_or(Value::Undefined, |token| token.resolve_val(self, context))
}
pub fn eq(&self, counter: &str, limit: i32) -> bool {
self.n.get(counter).copied().unwrap_or(0) == limit
}
pub fn lt(&self, counter: &str, limit: i32) -> bool {
self.n.get(counter).copied().unwrap_or(0) < limit
}
pub fn gt(&self, counter: &str, limit: i32) -> bool {
self.n.get(counter).copied().unwrap_or(0) > limit
}
pub fn lte(&self, counter: &str, limit: i32) -> bool {
self.n.get(counter).copied().unwrap_or(0) <= limit
}
pub fn gte(&self, counter: &str, limit: i32) -> bool {
self.n.get(counter).copied().unwrap_or(0) >= limit
}
pub fn exist(&self, counter: &str) -> bool {
self.n.contains_key(counter)
}
pub fn snapshot(&self) -> Rc<RuleSnapshot> {
Rc::clone(&self.shared)
}
pub(crate) fn note_child_push(&mut self, child: &Rule) {
self.child_link_open = true;
self.child_cell = Some(Rc::clone(&child.node));
self.child_record = Some(child.snapshot());
}
pub(crate) fn freeze_child(&mut self, child: &Rule) {
if self.child_link_open {
self.child_cell = Some(Rc::clone(&child.node));
self.child_record = Some(child.snapshot());
self.child_link_open = false;
}
}
pub(crate) fn accept_child_node(&mut self, child: &Rule) {
self.freeze_child(child);
let cell = self
.child_cell
.clone()
.unwrap_or_else(|| Rc::clone(&child.node));
self.child_node_is_self = Rc::ptr_eq(&self.node, &cell);
self.child_node = if self.child_node_is_self {
Value::Undefined
} else {
cell.borrow().clone()
};
}
pub fn child_value(&self) -> Value {
if self.child_node_is_self {
self.node.borrow().clone()
} else {
self.child_node.clone()
}
}
pub fn has_child_value(&self) -> bool {
if self.child_node_is_self {
!self.node.borrow().is_undefined()
} else {
!self.child_node.is_undefined()
}
}
pub(crate) fn accept_child(&mut self, child: &Rule) {
self.accept_child_node(child);
self.child_rule = self.child_record.clone().or_else(|| Some(child.snapshot()));
self.next_rule = self.child_rule.clone();
}
pub(crate) fn park_child_node(&mut self) {
if self.child_node_is_self {
self.child_node = Value::Undefined;
}
}
}
impl fmt::Display for Rule {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "[Rule {}~{}]", self.name, self.i)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn cell(text: &str) -> Rc<RefCell<Value>> {
Rc::new(RefCell::new(Value::String(text.into())))
}
#[test]
fn freeze_child_takes_the_cell_the_child_ended_on() {
let mut parent = Rule::new("parent", Value::Undefined);
let mut child = Rule::new("child", Value::Undefined);
parent.note_child_push(&child);
child.node = cell("done");
parent.freeze_child(&child);
assert_eq!(
*parent
.child_cell
.as_ref()
.expect("a frozen child cell")
.borrow(),
Value::String("done".into()),
"the freeze kept the push-time cell instead of the one the child ended on"
);
}
#[test]
fn freeze_child_ignores_every_link_after_the_first() {
let mut parent = Rule::new("parent", Value::Undefined);
let mut pushed = Rule::new("pushed", Value::Undefined);
parent.note_child_push(&pushed);
pushed.node = cell("pushed rule");
parent.freeze_child(&pushed);
let mut tail = Rule::new("tail", Value::Undefined);
tail.node = cell("chain tail");
parent.freeze_child(&tail);
assert_eq!(
*parent
.child_cell
.as_ref()
.expect("a frozen child cell")
.borrow(),
Value::String("pushed rule".into()),
"a later link of the replacement chain overwrote the child link"
);
}
#[test]
fn a_callback_replacing_the_whole_child_rule_does_not_break_the_link() {
let mut parent = Rule::new("parent", Value::Undefined);
let mut child = Rule::new("child", Value::Undefined);
parent.note_child_push(&child);
child = Rule::new("child", Value::Undefined);
child.node = cell("done");
parent.freeze_child(&child);
assert_eq!(
*parent
.child_cell
.as_ref()
.expect("a frozen child cell")
.borrow(),
Value::String("done".into()),
"replacing the rule value cost the parent its child link"
);
}
}