use std::cell::LazyCell;
use std::fmt::{self, Debug, Display, Formatter};
use std::ops::{Deref, Range};
use std::rc::Rc;
use std::sync::Arc;
use ecow::{EcoString, EcoVec, eco_format, eco_vec};
use typst_utils::debug;
use crate::kind::ModeAfter;
use crate::{
DiagSpan, FileId, RangeMapper, Span, SpanKind, SpanNumber, Spanned, SubRange,
SyntaxKind, SyntaxMode,
};
#[derive(Clone, Eq, PartialEq, Hash)]
pub struct SyntaxNode {
data: Node,
span: Span,
}
#[derive(Clone, Eq, PartialEq, Hash)]
enum Node {
Leaf(EcoString, SyntaxKind),
Inner(Arc<InnerNode>, SyntaxKind),
Error(Arc<ErrorNode>, SyntaxKind),
Warning(Arc<WarningWrapper>, SyntaxKind),
}
enum NodeRef<'a> {
Leaf(&'a EcoString),
Inner(&'a Arc<InnerNode>),
Error(&'a Arc<ErrorNode>),
}
impl SyntaxNode {
fn node_ref(&self) -> NodeRef<'_> {
let mut data = &self.data;
loop {
match data {
Node::Leaf(text, _) => break NodeRef::Leaf(text),
Node::Inner(inner, _) => break NodeRef::Inner(inner),
Node::Error(err, _) => break NodeRef::Error(err),
Node::Warning(warn, _) => data = &warn.child,
}
}
}
fn inner_and_span_mut(&mut self) -> Option<(&mut InnerNode, &mut Span)> {
let mut data = &mut self.data;
loop {
match data {
Node::Leaf(_, _) | Node::Error(_, _) => break None,
Node::Inner(inner, _) => {
break Some((Arc::make_mut(inner), &mut self.span));
}
Node::Warning(warn, _) => data = &mut Arc::make_mut(warn).child,
}
}
}
fn hints_mut(&mut self) -> Option<&mut EcoVec<(EcoString, Option<SubRange>)>> {
match &mut self.data {
Node::Leaf(_, _) | Node::Inner(_, _) => None,
Node::Error(err, _) => Some(&mut Arc::make_mut(err).hints),
Node::Warning(warn, _) => Some(&mut Arc::make_mut(warn).hints),
}
}
}
impl SyntaxNode {
#[track_caller]
pub fn leaf(kind: SyntaxKind, text: impl Into<EcoString>) -> Self {
debug_assert!(!kind.is_error());
Self {
data: Node::Leaf(text.into(), kind),
span: Span::detached(),
}
}
#[track_caller]
pub fn inner(kind: SyntaxKind, children: Vec<SyntaxNode>) -> Self {
debug_assert!(!kind.is_error());
Self {
data: Node::Inner(Arc::new(InnerNode::new(children)), kind),
span: Span::detached(),
}
}
pub fn error(message: impl Into<EcoString>, text: impl Into<EcoString>) -> Self {
Self {
data: Node::Error(
Arc::new(ErrorNode::new(message.into(), text.into())),
SyntaxKind::Error,
),
span: Span::detached(),
}
}
pub fn warn(&mut self, message: impl Into<EcoString>) {
let kind = self.kind();
let child = std::mem::replace(&mut self.data, Node::Leaf(EcoString::new(), kind));
let warn = Arc::new(WarningWrapper::new(child, None, message.into()));
self.data = Node::Warning(warn, kind);
}
#[track_caller]
pub fn warn_at(
&mut self,
Range { start, end }: Range<usize>,
message: impl Into<EcoString>,
) {
assert!(end <= self.len()); let sub_range = SubRange::new(start, end).expect("a valid sub-range");
let kind = self.kind();
let child = std::mem::replace(&mut self.data, Node::Leaf(EcoString::new(), kind));
let warn = Arc::new(WarningWrapper::new(child, Some(sub_range), message.into()));
self.data = Node::Warning(warn, kind);
}
#[track_caller]
pub fn hint(&mut self, hint: impl Into<EcoString>) {
let hints = self.hints_mut().expect("expected an error or warning");
hints.push((hint.into(), None));
}
#[track_caller]
pub fn hint_at(
&mut self,
Range { start, end }: Range<usize>,
hint: impl Into<EcoString>,
) {
assert!(end <= self.len()); let sub_range = SubRange::new(start, end).expect("a valid sub-range");
let hints = self.hints_mut().expect("expected an error or warning");
hints.push((hint.into(), Some(sub_range)));
}
#[track_caller]
pub fn with_hints(mut self, new_hints: impl IntoIterator<Item = EcoString>) -> Self {
let hints = self.hints_mut().expect("expected an error or warning");
let iter = new_hints.into_iter().map(|h| (h, None));
hints.extend(iter);
self
}
#[track_caller]
pub const fn placeholder(kind: SyntaxKind) -> Self {
if kind.is_error() {
panic!("cannot create error placeholder");
}
Self {
data: Node::Leaf(EcoString::new(), kind),
span: Span::detached(),
}
}
pub fn kind(&self) -> SyntaxKind {
match self.data {
Node::Leaf(_, kind)
| Node::Inner(_, kind)
| Node::Error(_, kind)
| Node::Warning(_, kind) => kind,
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn len(&self) -> usize {
match self.node_ref() {
NodeRef::Leaf(text) => text.len(),
NodeRef::Inner(inner) => inner.len,
NodeRef::Error(err) => err.text.len(),
}
}
pub fn span(&self) -> Span {
self.span
}
pub fn leaf_text(&self) -> &EcoString {
static EMPTY: EcoString = EcoString::new();
match self.node_ref() {
NodeRef::Leaf(text) => text,
NodeRef::Inner(_) => &EMPTY,
NodeRef::Error(err) => &err.text,
}
}
pub fn full_text(&self) -> EcoString {
match &self.data {
Node::Leaf(leaf, _) => leaf.clone(),
Node::Error(err, _) => err.text.clone(),
Node::Inner(_, _) | Node::Warning(_, _) => {
let mut buffer = EcoString::with_capacity(self.len());
self.traverse(|node| {
match node.node_ref() {
NodeRef::Leaf(text) => buffer.push_str(text),
NodeRef::Inner(_) => {}
NodeRef::Error(err) => buffer.push_str(&err.text),
}
node.children()
});
buffer
}
}
}
pub fn children(&self) -> std::slice::Iter<'_, SyntaxNode> {
match self.node_ref() {
NodeRef::Leaf(_) | NodeRef::Error(_) => [].iter(),
NodeRef::Inner(inner) => inner.children.iter(),
}
}
pub fn diagnosis(&self) -> Diagnosis {
let diagnosis = match self.node_ref() {
NodeRef::Leaf(_) => Diagnosis::default(),
NodeRef::Inner(inner) => inner.diagnosis,
NodeRef::Error(_) => Diagnosis { errors: true, warnings: false },
};
match &self.data {
Node::Warning(_, _) => Diagnosis { warnings: true, errors: diagnosis.errors },
_ => diagnosis,
}
}
pub fn errors_and_warnings(&self) -> (Vec<SyntaxDiagnostic>, Vec<SyntaxDiagnostic>) {
let mut errors = Vec::new();
let mut warnings = Vec::new();
self.traverse(|node| {
let mut data = &node.data;
loop {
match data {
Node::Inner(inner, _) if inner.diagnosis.either() => {
break inner.children.iter();
}
Node::Leaf(_, _) | Node::Inner(_, _) => break [].iter(),
Node::Error(err, _) => {
errors.push(err.diagnostic(node.span));
break [].iter();
}
Node::Warning(warn, _) => {
warnings.push(warn.diagnostic(node.span));
data = &warn.child;
}
}
}
});
(errors, warnings)
}
pub fn synthesize(&mut self, span: Span) {
self.synthesize_with(0, &|_, _| span, &|_, sub_range| *sub_range = None);
}
pub fn synthesize_mapped(
&mut self,
id: FileId,
mapper: &RangeMapper,
) -> Result<(), EcoString> {
if self.len() > mapper.total_len() {
return Err(eco_format!(
"text length ({}) is greater than mapper length ({})",
self.len(),
mapper.total_len(),
));
}
self.synthesize_with(
0,
&|offset, len| Span::from_range(id, mapper.map(offset..offset + len)),
&|offset, sub_range| {
if let Some(sr) = sub_range {
*sr = mapper.map_sub_range(offset, *sr);
}
},
);
Ok(())
}
fn synthesize_with(
&mut self,
mut offset: usize,
map_span: &impl Fn(usize, usize) -> Span,
update_sub_range: &impl Fn(usize, &mut Option<SubRange>),
) {
let mut data = &mut self.data;
loop {
match data {
Node::Leaf(leaf, _) => {
self.span = map_span(offset, leaf.len());
break;
}
Node::Inner(inner, _) => {
let inner = Arc::make_mut(inner);
self.span = map_span(offset, inner.len);
inner.upper = self.span.number();
for child in &mut inner.children {
child.synthesize_with(offset, map_span, update_sub_range);
offset += child.len();
}
break;
}
Node::Error(err, _) => {
let err = Arc::make_mut(err);
for (_hint, sub_range) in err.hints.make_mut() {
update_sub_range(offset, sub_range);
}
self.span = map_span(offset, err.text.len());
break;
}
Node::Warning(warn, _) => {
let warn = Arc::make_mut(warn);
update_sub_range(offset, &mut warn.sub_range);
for (_hint, sub_range) in warn.hints.make_mut() {
update_sub_range(offset, sub_range);
}
data = &mut warn.child;
}
}
}
}
pub fn spanless_eq(&self, other: &Self) -> bool {
self.kind() == other.kind() && {
let mut data_a = &self.data;
let mut data_b = &other.data;
loop {
match (data_a, data_b) {
(Node::Leaf(a, _), Node::Leaf(b, _)) => break a == b,
(Node::Inner(a, _), Node::Inner(b, _)) => {
break a.spanless_eq(b);
}
(Node::Error(a, _), Node::Error(b, _)) => break a == b,
(Node::Warning(a, _), Node::Warning(b, _))
if a.message == b.message && a.hints == b.hints =>
{
data_a = &a.child;
data_b = &b.child;
}
_ => break false,
}
}
}
}
}
impl SyntaxNode {
#[track_caller]
pub(super) fn convert_to_kind(&mut self, new_kind: SyntaxKind) {
if new_kind.is_error() {
panic!("cannot convert to an error, use `convert_to_error` instead");
} else if self.kind().is_error() {
panic!("cannot convert an error to a different kind");
}
let mut data = &mut self.data;
loop {
match data {
Node::Leaf(_, kind) | Node::Inner(_, kind) => {
*kind = new_kind;
break;
}
Node::Error(_, _) => unreachable!(),
Node::Warning(warn, kind) => {
*kind = new_kind;
data = &mut Arc::make_mut(warn).child;
}
}
}
}
pub(super) fn convert_to_error(&mut self, message: impl Into<EcoString>) {
if !self.kind().is_error() {
let text = std::mem::take(self).full_text();
*self = SyntaxNode::error(message.into(), text);
}
}
pub(super) fn expected(&mut self, expected: &str) {
let kind = self.kind();
self.convert_to_error(eco_format!("expected {expected}, found {}", kind.name()));
if kind.is_keyword() && matches!(expected, "identifier" | "pattern") {
self.hint(eco_format!(
"keyword `{text}` is not allowed as an identifier; try `{text}_` instead",
text = self.leaf_text(),
));
}
}
pub(super) fn unexpected(&mut self) {
self.convert_to_error(eco_format!("unexpected {}", self.kind().name()));
}
pub(super) fn numberize(
&mut self,
id: FileId,
within: Range<u64>,
) -> NumberingResult {
if within.start >= within.end {
Err(Unnumberable)
} else if let Some((inner, span)) = self.inner_and_span_mut() {
inner.numberize(span, id, None, within)
} else {
self.span =
Span::from_number(id, SpanNumber((within.start + within.end) / 2));
Ok(())
}
}
fn traverse(&self, mut f: impl FnMut(&Self) -> std::slice::Iter<'_, Self>) {
fn recursive_step(
node: &SyntaxNode,
f: &mut impl FnMut(&SyntaxNode) -> std::slice::Iter<'_, SyntaxNode>,
) {
for child in f(node) {
recursive_step(child, f);
}
}
recursive_step(self, &mut f);
}
pub(super) fn is_leaf(&self) -> bool {
matches!(self.node_ref(), NodeRef::Leaf(_))
}
pub(super) fn is_inner(&self) -> bool {
matches!(self.node_ref(), NodeRef::Inner(_))
}
pub(super) fn descendants(&self) -> usize {
match self.node_ref() {
NodeRef::Leaf(_) | NodeRef::Error(_) => 1,
NodeRef::Inner(inner) => inner.descendants,
}
}
pub(super) fn children_mut(&mut self) -> &mut [SyntaxNode] {
if let Some((inner, _)) = self.inner_and_span_mut() {
&mut inner.children
} else {
&mut []
}
}
pub(super) fn replace_children(
&mut self,
range: Range<usize>,
replacement: Vec<SyntaxNode>,
) -> NumberingResult {
if let Some((inner, span)) = self.inner_and_span_mut() {
inner.replace_children(span, range, replacement)
} else {
Ok(())
}
}
pub(super) fn update_parent(
&mut self,
prev_len: usize,
new_len: usize,
prev_descendants: usize,
new_descendants: usize,
) {
if let Some((inner, _)) = self.inner_and_span_mut() {
inner.update_parent(prev_len, new_len, prev_descendants, new_descendants)
}
}
pub(super) fn upper(&self) -> u64 {
match self.node_ref() {
NodeRef::Leaf(_) | NodeRef::Error(_) => self.span.number() + 1,
NodeRef::Inner(inner) => inner.upper,
}
}
}
impl Debug for SyntaxNode {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.data.fmt(f)
}
}
impl Debug for Node {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Node::Leaf(text, kind) => write!(f, "{kind:?}: {text:?}"),
Node::Inner(inner, kind) => inner.debug_fmt(f, *kind),
Node::Error(err, _) => err.fmt(f),
Node::Warning(warn, _) => warn.fmt(f),
}
}
}
impl Default for SyntaxNode {
fn default() -> Self {
Self::leaf(SyntaxKind::End, EcoString::new())
}
}
#[derive(Clone, Eq, PartialEq, Hash)]
struct InnerNode {
len: usize,
descendants: usize,
diagnosis: Diagnosis,
upper: u64,
children: Vec<SyntaxNode>,
}
impl InnerNode {
fn new(children: Vec<SyntaxNode>) -> Self {
let mut len = 0;
let mut descendants = 1;
let mut diagnosis = Diagnosis::default();
for child in &children {
len += child.len();
descendants += child.descendants();
diagnosis = diagnosis.or(child.diagnosis());
}
Self { len, descendants, diagnosis, upper: 0, children }
}
fn numberize(
&mut self,
span: &mut Span,
id: FileId,
range: Option<Range<usize>>,
within: Range<u64>,
) -> NumberingResult {
let descendants = match &range {
Some(range) if range.is_empty() => return Ok(()),
Some(range) => self.children[range.clone()]
.iter()
.map(SyntaxNode::descendants)
.sum::<usize>(),
None => self.descendants,
};
let space = within.end - within.start;
let mut stride = space / (2 * descendants as u64);
if stride == 0 {
stride = space / self.descendants as u64;
if stride == 0 {
return Err(Unnumberable);
}
}
let mut start = within.start;
if range.is_none() {
let end = start + stride;
*span = Span::from_number(id, SpanNumber((start + end) / 2));
self.upper = within.end;
start = end;
}
let len = self.children.len();
for child in &mut self.children[range.unwrap_or(0..len)] {
let end = start + child.descendants() as u64 * stride;
child.numberize(id, start..end)?;
start = end;
}
Ok(())
}
fn spanless_eq(&self, other: &Self) -> bool {
self.len == other.len
&& self.descendants == other.descendants
&& self.diagnosis == other.diagnosis
&& self.children.len() == other.children.len()
&& self
.children
.iter()
.zip(&other.children)
.all(|(a, b)| a.spanless_eq(b))
}
fn replace_children(
&mut self,
span: &mut Span,
mut range: Range<usize>,
replacement: Vec<SyntaxNode>,
) -> NumberingResult {
let Some(id) = span.id() else { return Err(Unnumberable) };
let mut replacement_range = 0..replacement.len();
while range.start < range.end
&& replacement_range.start < replacement_range.end
&& self.children[range.start]
.spanless_eq(&replacement[replacement_range.start])
{
range.start += 1;
replacement_range.start += 1;
}
while range.start < range.end
&& replacement_range.start < replacement_range.end
&& self.children[range.end - 1]
.spanless_eq(&replacement[replacement_range.end - 1])
{
range.end -= 1;
replacement_range.end -= 1;
}
let mut replacement_vec = replacement;
let replacement = &replacement_vec[replacement_range.clone()];
let superseded = &self.children[range.clone()];
self.len = self.len + replacement.iter().map(SyntaxNode::len).sum::<usize>()
- superseded.iter().map(SyntaxNode::len).sum::<usize>();
self.descendants = self.descendants
+ replacement.iter().map(SyntaxNode::descendants).sum::<usize>()
- superseded.iter().map(SyntaxNode::descendants).sum::<usize>();
let replaced_diagnosis = Diagnosis::any(replacement);
if !self.diagnosis.either() || replaced_diagnosis.both() {
self.diagnosis = replaced_diagnosis;
} else {
self.diagnosis = replaced_diagnosis.or(Diagnosis::or(
Diagnosis::any(&self.children[..range.start]),
Diagnosis::any(&self.children[range.end..]),
));
}
self.children
.splice(range.clone(), replacement_vec.drain(replacement_range.clone()));
range.end = range.start + replacement_range.len();
let mut left = 0;
let mut right = 0;
let max_left = range.start;
let max_right = self.children.len() - range.end;
loop {
let renumber = range.start - left..range.end + right;
let start_number = renumber
.start
.checked_sub(1)
.and_then(|i| self.children.get(i))
.map_or(span.number() + 1, |child| child.upper());
let end_number = self
.children
.get(renumber.end)
.map_or(self.upper, |next| next.span().number());
let within = start_number..end_number;
if self.numberize(span, id, Some(renumber), within).is_ok() {
return Ok(());
}
if left == max_left && right == max_right {
return Err(Unnumberable);
}
left = (left + 1).next_power_of_two().min(max_left);
right = (right + 1).next_power_of_two().min(max_right);
}
}
fn update_parent(
&mut self,
prev_len: usize,
new_len: usize,
prev_descendants: usize,
new_descendants: usize,
) {
self.len = self.len + new_len - prev_len;
self.descendants = self.descendants + new_descendants - prev_descendants;
self.diagnosis = Diagnosis::any(&self.children);
}
fn debug_fmt(&self, f: &mut Formatter, kind: SyntaxKind) -> fmt::Result {
write!(f, "{kind:?}: {}", self.len)?;
if !self.children.is_empty() {
f.write_str(" ")?;
f.debug_list().entries(&self.children).finish()?;
}
Ok(())
}
}
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash)]
pub struct Diagnosis {
pub errors: bool,
pub warnings: bool,
}
impl Diagnosis {
pub fn either(self) -> bool {
self.errors | self.warnings
}
pub fn both(self) -> bool {
self.errors & self.warnings
}
pub fn or(mut self, other: Self) -> Self {
self.errors |= other.errors;
self.warnings |= other.warnings;
self
}
fn any(slice: &[SyntaxNode]) -> Self {
slice
.iter()
.map(SyntaxNode::diagnosis)
.fold(Self::default(), Self::or)
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct SyntaxDiagnostic {
pub is_error: bool,
pub span: DiagSpan,
pub message: EcoString,
pub hints: EcoVec<Spanned<EcoString, DiagSpan>>,
}
#[derive(Clone, Eq, PartialEq, Hash)]
struct ErrorNode {
text: EcoString,
message: EcoString,
hints: EcoVec<(EcoString, Option<SubRange>)>,
}
impl ErrorNode {
fn new(message: EcoString, text: EcoString) -> Self {
Self { text, message, hints: eco_vec![] }
}
fn diagnostic(&self, span: Span) -> SyntaxDiagnostic {
SyntaxDiagnostic {
is_error: true,
span: span.into(),
message: self.message.clone(),
hints: build_diagnostic_hints(span, &self.hints),
}
}
}
impl Debug for ErrorNode {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
if self.text.is_empty() && self.hints.is_empty() {
write!(f, "Error: {:?}", self.message)
} else {
let mut out = f.debug_struct("Error:");
out.field("text", &self.text);
out.field("message", &self.message);
for (hint, sub_range) in &self.hints {
let field = if let Some(sub_range) = sub_range {
let selected = &self.text[sub_range.to_relative()];
&format!("hint @({selected:?})")
} else {
"hint"
};
out.field(field, hint);
}
out.finish()
}
}
}
#[derive(Clone, Eq, PartialEq, Hash)]
struct WarningWrapper {
child: Node,
sub_range: Option<SubRange>,
message: EcoString,
hints: EcoVec<(EcoString, Option<SubRange>)>,
}
impl WarningWrapper {
fn new(child: Node, sub_range: Option<SubRange>, message: EcoString) -> Self {
Self { child, sub_range, message, hints: eco_vec![] }
}
fn diagnostic(&self, span: Span) -> SyntaxDiagnostic {
SyntaxDiagnostic {
is_error: false,
span: DiagSpan::from_span(span, self.sub_range),
message: self.message.clone(),
hints: build_diagnostic_hints(span, &self.hints),
}
}
}
impl Debug for WarningWrapper {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
let full_text = LazyCell::new(|| {
let data = self.child.clone();
let temp_node = SyntaxNode { data, span: Span::detached() };
temp_node.full_text()
});
let debug_field = |field, message, sub_range: Option<SubRange>| {
let full_text = &full_text;
debug(move |f| {
if let Some(sr) = sub_range {
let selected = &full_text[sr.to_relative()];
write!(f, "{field} @({selected:?}): {message:?}")
} else {
write!(f, "{field}: {message:?}")
}
})
};
write!(f, "Warning: ")?;
let mut out = f.debug_set();
out.entry(&debug_field("message", &self.message, self.sub_range));
for (hint, sub_range) in &self.hints {
out.entry(&debug_field("hint", hint, *sub_range));
}
out.entry(&self.child);
out.finish()
}
}
fn build_diagnostic_hints(
parent_span: Span,
hints: &EcoVec<(EcoString, Option<SubRange>)>,
) -> EcoVec<Spanned<EcoString, DiagSpan>> {
hints
.iter()
.map(|(message, sub_range)| {
let msg = message.clone();
match *sub_range {
Some(sr) => Spanned::new(msg, DiagSpan::from_span(parent_span, Some(sr))),
None => Spanned::detached(msg),
}
})
.collect()
}
#[derive(Clone)]
pub struct LinkedNode<'a> {
node: &'a SyntaxNode,
parent: Option<Rc<Self>>,
index: usize,
offset: usize,
}
impl<'a> LinkedNode<'a> {
pub fn new(root: &'a SyntaxNode) -> Self {
Self { node: root, parent: None, index: 0, offset: 0 }
}
pub fn get(&self) -> &'a SyntaxNode {
self.node
}
pub fn index(&self) -> usize {
self.index
}
pub fn offset(&self) -> usize {
self.offset
}
pub fn range(&self) -> Range<usize> {
self.offset..self.offset + self.node.len()
}
pub fn children(&self) -> LinkedChildren<'a> {
LinkedChildren {
parent: Rc::new(self.clone()),
iter: self.node.children().enumerate(),
front: self.offset,
back: self.offset + self.len(),
}
}
pub fn find(&self, span: Span) -> Option<Self> {
match span.get() {
SpanKind::Detached => None,
SpanKind::Number { id: _, num } => self.find_number(num),
SpanKind::Range { id: _, range } => self.find_range(range.start, range.end),
}
}
pub(crate) fn find_number(&self, target: SpanNumber) -> Option<Self> {
let number = self.span().number();
if number == target.0 {
return Some(self.clone());
}
if self.node.is_inner() && number < target.0 {
let mut children = self.children().peekable();
while let Some(child) = children.next() {
if children.peek().is_none_or(|next| next.span().number() > target.0)
&& let Some(found) = child.find_number(target)
{
return Some(found);
}
}
}
None
}
pub(crate) fn find_range(&self, start: usize, end: usize) -> Option<Self> {
if start == self.offset && end == self.offset + self.len() {
return Some(self.clone());
}
for child in self.children() {
if child.offset <= start && end <= child.offset + child.len() {
return child.find_range(start, end);
}
}
None
}
pub fn mode_after(&self) -> Option<SyntaxMode> {
match self.kind().mode_after() {
ModeAfter::Known(mode) => Some(mode),
ModeAfter::None => None,
ModeAfter::Text if self.parent_kind() == Some(SyntaxKind::Raw) => None,
ModeAfter::RawDelim if self.index == 0 => None,
ModeAfter::Text => Some(SyntaxMode::Markup),
ModeAfter::Dollar if self.index == 0 => Some(SyntaxMode::Math),
ModeAfter::Space if self.parent_kind() == Some(SyntaxKind::Equation) => {
Some(SyntaxMode::Math)
}
ModeAfter::Embeddable
if self
.prev_sibling_with_trivia()
.is_some_and(|prev| prev.kind() == SyntaxKind::Hash) =>
{
Some(SyntaxMode::Code)
}
ModeAfter::Parent
| ModeAfter::RawDelim
| ModeAfter::Space
| ModeAfter::Dollar
| ModeAfter::Embeddable => self.parent_mode(),
}
}
pub fn parent_mode(&self) -> Option<SyntaxMode> {
self.parent().and_then(Self::mode_after)
}
}
impl LinkedNode<'_> {
pub fn parent(&self) -> Option<&Self> {
self.parent.as_deref()
}
pub fn prev_sibling(&self) -> Option<Self> {
let parent = self.parent.as_ref()?;
let children = parent.node.children().as_slice();
let mut offset = self.offset;
for (index, node) in children[..self.index].iter().enumerate().rev() {
offset -= node.len();
if !node.kind().is_trivia() {
let parent = Some(parent.clone());
return Some(Self { node, parent, index, offset });
}
}
None
}
pub fn prev_sibling_with_trivia(&self) -> Option<Self> {
let parent = self.parent.as_ref()?;
let children = parent.node.children().as_slice();
let (index, node) = children[..self.index].iter().enumerate().next_back()?;
let offset = self.offset - node.len();
let parent = Some(parent.clone());
Some(Self { node, parent, index, offset })
}
pub fn next_sibling(&self) -> Option<Self> {
let parent = self.parent.as_ref()?;
let children = parent.node.children();
let mut offset = self.offset + self.len();
for (index, node) in children.enumerate().skip(self.index + 1) {
if !node.kind().is_trivia() {
let parent = Some(parent.clone());
return Some(Self { node, parent, index, offset });
}
offset += node.len();
}
None
}
pub fn next_sibling_with_trivia(&self) -> Option<Self> {
let parent = self.parent.as_ref()?;
let children = parent.node.children();
let (index, node) = children.enumerate().nth(self.index + 1)?;
let offset = self.offset + self.len();
let parent = Some(parent.clone());
Some(Self { node, parent, index, offset })
}
pub fn parent_kind(&self) -> Option<SyntaxKind> {
Some(self.parent()?.node.kind())
}
pub fn prev_sibling_kind(&self) -> Option<SyntaxKind> {
Some(self.prev_sibling()?.node.kind())
}
pub fn next_sibling_kind(&self) -> Option<SyntaxKind> {
Some(self.next_sibling()?.node.kind())
}
}
#[derive(Debug, Clone)]
pub enum Side {
Before,
After,
}
impl LinkedNode<'_> {
pub fn prev_leaf(&self) -> Option<Self> {
let mut node = self.clone();
while let Some(prev) = node.prev_sibling() {
if let Some(leaf) = prev.rightmost_leaf() {
return Some(leaf);
}
node = prev;
}
self.parent()?.prev_leaf()
}
pub fn leftmost_leaf(&self) -> Option<Self> {
if self.is_leaf() && !self.kind().is_trivia() && !self.kind().is_error() {
return Some(self.clone());
}
for child in self.children() {
if let Some(leaf) = child.leftmost_leaf() {
return Some(leaf);
}
}
None
}
fn leaf_before(&self, cursor: usize) -> Option<Self> {
if self.node.children().len() == 0 && cursor <= self.offset + self.len() {
return Some(self.clone());
}
let mut offset = self.offset;
let count = self.node.children().len();
for (i, child) in self.children().enumerate() {
let len = child.len();
if (offset < cursor && cursor <= offset + len)
|| (offset == cursor && i + 1 == count)
{
return child.leaf_before(cursor);
}
offset += len;
}
None
}
fn leaf_after(&self, cursor: usize) -> Option<Self> {
if self.node.children().len() == 0 && cursor < self.offset + self.len() {
return Some(self.clone());
}
let mut offset = self.offset;
for child in self.children() {
let len = child.len();
if offset <= cursor && cursor < offset + len {
return child.leaf_after(cursor);
}
offset += len;
}
None
}
pub fn leaf_at(&self, cursor: usize, side: Side) -> Option<Self> {
match side {
Side::Before => self.leaf_before(cursor),
Side::After => self.leaf_after(cursor),
}
}
pub fn rightmost_leaf(&self) -> Option<Self> {
if self.is_leaf() && !self.kind().is_trivia() {
return Some(self.clone());
}
for child in self.children().rev() {
if let Some(leaf) = child.rightmost_leaf() {
return Some(leaf);
}
}
None
}
pub fn next_leaf(&self) -> Option<Self> {
let mut node = self.clone();
while let Some(next) = node.next_sibling() {
if let Some(leaf) = next.leftmost_leaf() {
return Some(leaf);
}
node = next;
}
self.parent()?.next_leaf()
}
}
impl Deref for LinkedNode<'_> {
type Target = SyntaxNode;
fn deref(&self) -> &Self::Target {
self.get()
}
}
impl Debug for LinkedNode<'_> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
self.node.fmt(f)
}
}
pub struct LinkedChildren<'a> {
parent: Rc<LinkedNode<'a>>,
iter: std::iter::Enumerate<std::slice::Iter<'a, SyntaxNode>>,
front: usize,
back: usize,
}
impl<'a> Iterator for LinkedChildren<'a> {
type Item = LinkedNode<'a>;
fn next(&mut self) -> Option<Self::Item> {
let (index, node) = self.iter.next()?;
let offset = self.front;
self.front += node.len();
Some(LinkedNode {
node,
parent: Some(self.parent.clone()),
index,
offset,
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl DoubleEndedIterator for LinkedChildren<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
let (index, node) = self.iter.next_back()?;
self.back -= node.len();
Some(LinkedNode {
node,
parent: Some(self.parent.clone()),
index,
offset: self.back,
})
}
}
impl ExactSizeIterator for LinkedChildren<'_> {}
pub(super) type NumberingResult = Result<(), Unnumberable>;
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub(super) struct Unnumberable;
impl Display for Unnumberable {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.pad("cannot number within this interval")
}
}
impl std::error::Error for Unnumberable {}
#[cfg(test)]
mod tests {
use super::*;
use crate::Source;
#[test]
fn test_debug() {
assert_eq!(
format!("{:#?}", crate::parse("= Head <label>")),
"\
Markup: 14 [
Heading: 6 [
HeadingMarker: \"=\",
Space: \" \",
Markup: 4 [
Text: \"Head\",
],
],
Space: \" \",
Label: \"<label>\",
]"
);
assert_eq!(
format!("{:#?}", crate::parse("#")),
"\
Markup: 1 [
Hash: \"#\",
Error: \"expected expression\",
]"
);
assert_eq!(
format!("{:#?}", crate::parse("##")),
"\
Markup: 2 [
Hash: \"#\",
Error: {
text: \"#\",
message: \"the character `#` is not valid in code\",
hint: \"the preceding hash is causing this to parse in code mode\",
hint: \"try escaping the preceding hash: `\\\\#`\",
},
]"
);
assert_eq!(
format!("{:#?}", crate::parse("**")),
"\
Markup: 2 [
Warning: {
message: \"no text within stars\",
hint: \"using multiple consecutive stars (e.g. **) has no additional effect\",
Strong: 2 [
Star: \"*\",
Markup: 0,
Star: \"*\",
],
},
]"
);
}
#[test]
fn test_debug_sub_range() {
let mut root = crate::parse("= =head");
let heading_body = &mut root.children_mut()[0];
heading_body.warn_at(0..3, "equal space equal!");
heading_body.hint("try equal equal space?");
assert_eq!(
format!("{root:#?}"),
"\
Markup: 7 [
Warning: {
message @(\"= =\"): \"equal space equal!\",
hint: \"try equal equal space?\",
Heading: 7 [
HeadingMarker: \"=\",
Space: \" \",
Markup: 5 [
Text: \"=head\",
],
],
},
]"
);
let mut root = crate::parse("<unclosed");
let node = &mut root.children_mut()[0];
node.hint_at(0..1, "greater");
node.hint_at(3..8, "open!");
node.warn_at(3..9, "opened?");
node.hint_at(0..9, "full text"); assert_eq!(
format!("{root:#?}"),
"\
Markup: 9 [
Warning: {
message @(\"closed\"): \"opened?\",
hint @(\"<unclosed\"): \"full text\",
Error: {
text: \"<unclosed\",
message: \"unclosed label\",
hint @(\"<\"): \"greater\",
hint @(\"close\"): \"open!\",
},
},
]"
);
}
#[test]
fn test_linked_node() {
let source = Source::detached("#set text(12pt, red)");
let node = LinkedNode::new(source.root()).leaf_at(7, Side::Before).unwrap();
assert_eq!(node.offset(), 5);
assert_eq!(node.leaf_text(), "text");
let node = LinkedNode::new(source.root()).leaf_at(7, Side::After).unwrap();
assert_eq!(node.offset(), 5);
assert_eq!(node.leaf_text(), "text");
let prev = node.prev_sibling().unwrap();
assert_eq!(prev.offset(), 1);
assert_eq!(prev.leaf_text(), "set");
}
#[test]
fn test_linked_node_non_trivia_leaf() {
let source = Source::detached("#set fun(12pt, red)");
let leaf = LinkedNode::new(source.root()).leaf_at(6, Side::Before).unwrap();
let prev = leaf.prev_leaf().unwrap();
assert_eq!(leaf.leaf_text(), "fun");
assert_eq!(prev.leaf_text(), "set");
let source = Source::detached("#let x = 10");
let leaf = LinkedNode::new(source.root()).leaf_at(9, Side::Before).unwrap();
let prev = leaf.prev_leaf().unwrap();
let next = leaf.next_leaf().unwrap();
assert_eq!(prev.leaf_text(), "=");
assert_eq!(leaf.leaf_text(), " ");
assert_eq!(next.leaf_text(), "10");
let source = Source::detached("#let x = 10");
let leaf = LinkedNode::new(source.root()).leaf_at(9, Side::After).unwrap();
let prev = leaf.prev_leaf().unwrap();
assert!(leaf.next_leaf().is_none());
assert_eq!(prev.leaf_text(), "=");
assert_eq!(leaf.leaf_text(), "10");
}
}