use std::fmt;
use crate::grammars::{GlobalRuleRef, GrammarId, ROOT_RULE_ID};
use crate::scope::Scope;
#[derive(Clone, Debug)]
pub struct StackFrame {
pub rule_ref: GlobalRuleRef,
pub name_scopes: Vec<Scope>,
pub content_scopes: Vec<Scope>,
pub end_pattern: Option<String>,
pub begin_rule_has_captured_eol: bool,
pub anchor_position: Option<usize>,
pub enter_position: Option<usize>,
}
#[derive(Clone)]
pub struct StateStack {
pub frames: Vec<StackFrame>,
}
impl StateStack {
pub fn new(grammar_id: GrammarId, grammar_scope: Scope) -> Self {
Self {
frames: vec![StackFrame {
rule_ref: GlobalRuleRef {
grammar: grammar_id,
rule: ROOT_RULE_ID,
},
name_scopes: vec![grammar_scope],
content_scopes: vec![grammar_scope],
end_pattern: None,
begin_rule_has_captured_eol: false,
anchor_position: None,
enter_position: None,
}],
}
}
pub fn push(
&mut self,
rule_ref: GlobalRuleRef,
anchor_position: Option<usize>,
begin_rule_has_captured_eol: bool,
enter_position: Option<usize>,
) {
let content_scopes = self.top().content_scopes.clone();
self.frames.push(StackFrame {
rule_ref,
name_scopes: content_scopes.clone(),
content_scopes,
end_pattern: None,
begin_rule_has_captured_eol,
anchor_position,
enter_position,
});
}
pub fn push_with_scopes(
&mut self,
rule_ref: GlobalRuleRef,
anchor_position: Option<usize>,
begin_rule_has_captured_eol: bool,
enter_position: Option<usize>,
scopes: Vec<Scope>,
) {
self.frames.push(StackFrame {
rule_ref,
name_scopes: scopes.clone(),
content_scopes: scopes,
end_pattern: None,
begin_rule_has_captured_eol,
anchor_position,
enter_position,
});
}
pub fn set_content_scopes(&mut self, content_scopes: Vec<Scope>) {
self.top_mut().content_scopes = content_scopes;
}
pub fn set_end_pattern(&mut self, end_pattern: String) {
self.top_mut().end_pattern = Some(end_pattern);
}
pub fn pop(&mut self) -> Option<StackFrame> {
if self.frames.len() > 1 {
self.frames.pop()
} else {
None
}
}
pub fn safe_pop(&mut self) {
if self.frames.len() > 1 {
self.frames.pop();
}
}
pub fn reset(&mut self) {
for frame in &mut self.frames {
frame.enter_position = None;
frame.anchor_position = None;
}
}
pub fn top(&self) -> &StackFrame {
self.frames.last().expect("stack never empty")
}
pub fn top_mut(&mut self) -> &mut StackFrame {
self.frames.last_mut().expect("stack never empty")
}
}
impl fmt::Debug for StateStack {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "StateStack:")?;
for (depth, frame) in self.frames.iter().enumerate() {
let indent = " ".repeat(depth);
write!(
f,
"{}grammar={}, rule={}",
indent, frame.rule_ref.grammar.0, frame.rule_ref.rule.0
)?;
if !frame.name_scopes.is_empty() {
write!(f, " name=[")?;
for (i, scope) in frame.name_scopes.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", scope.build_string())?;
}
write!(f, "]")?;
}
if !frame.content_scopes.is_empty() {
write!(f, ", content=[")?;
for (i, scope) in frame.content_scopes.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", scope.build_string())?;
}
write!(f, "]")?;
}
if let Some(pattern) = &frame.end_pattern {
write!(f, ", end_pattern=\"{}\"", pattern)?;
}
write!(f, ", anchor_pos={:?}", frame.anchor_position)?;
if let Some(enter_pos) = frame.enter_position
&& frame.anchor_position != Some(enter_pos)
{
write!(f, ", enter_pos={}", enter_pos)?;
}
write!(
f,
", begin_rule_has_captured_eol={}",
frame.begin_rule_has_captured_eol
)?;
writeln!(f)?;
}
Ok(())
}
}