use crate::span::Span;
use crate::token::TokenKind;
use alloc::string::String;
use alloc::sync::Arc;
use alloc::vec::Vec;
use core::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[non_exhaustive]
pub enum CstKind {
File,
Module,
ConstDecl,
TypedefDecl,
StructDecl,
UnionDecl,
EnumDecl,
BitmaskDecl,
BitsetDecl,
NativeDecl,
ExceptionDecl,
InterfaceDecl,
ValuetypeDecl,
ValueBoxDecl,
ForwardDecl,
AnnotationDecl,
RepositoryDirective,
ImportDecl,
KeylistDecl,
TemplateModuleInst,
ActualParameters,
TemplateModuleRef,
TemplateParameters,
TemplateParameter,
PortDecl,
ManagesClause,
Member,
UnionCase,
CaseLabel,
Enumerator,
BitValue,
BitField,
Operation,
Parameter,
AttributeDecl,
RaisesClause,
ContextClause,
InheritanceClause,
NamedType,
PrimitiveType,
SequenceType,
StringType,
WStringType,
MapType,
FixedType,
TypeArguments,
Declarator,
ArrayDimension,
ScopedName,
LiteralExpr,
NameExpr,
UnaryExpr,
BinaryExpr,
ParenExpr,
Annotation,
AnnotationArguments,
AnnotationArgument,
Error,
}
impl CstKind {
#[must_use]
pub const fn is_error(self) -> bool {
matches!(self, Self::Error)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct GreenToken {
kind: TokenKind,
text: Arc<str>,
}
impl GreenToken {
#[must_use]
pub fn new(kind: TokenKind, text: &str) -> Self {
Self {
kind,
text: Arc::from(text),
}
}
#[must_use]
pub const fn kind(&self) -> TokenKind {
self.kind
}
#[must_use]
pub fn text(&self) -> &str {
&self.text
}
#[must_use]
#[allow(clippy::cast_possible_truncation)]
pub fn width(&self) -> u32 {
self.text.len() as u32
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum GreenChild {
Node(Arc<GreenNode>),
Token(GreenToken),
}
impl GreenChild {
#[must_use]
pub fn width(&self) -> u32 {
match self {
Self::Node(node) => node.width(),
Self::Token(token) => token.width(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct GreenNode {
kind: CstKind,
width: u32,
children: Vec<GreenChild>,
}
impl GreenNode {
#[must_use]
pub fn new(kind: CstKind, children: Vec<GreenChild>) -> Self {
let width = children
.iter()
.fold(0u32, |sum, child| sum.saturating_add(child.width()));
Self {
kind,
width,
children,
}
}
#[must_use]
pub const fn kind(&self) -> CstKind {
self.kind
}
#[must_use]
pub const fn width(&self) -> u32 {
self.width
}
#[must_use]
pub fn children(&self) -> &[GreenChild] {
&self.children
}
#[must_use]
pub fn text(&self) -> String {
let mut out = String::with_capacity(self.width as usize);
let mut stack: Vec<&GreenChild> = self.children.iter().rev().collect();
while let Some(child) = stack.pop() {
match child {
GreenChild::Token(token) => out.push_str(token.text()),
GreenChild::Node(node) => stack.extend(node.children.iter().rev()),
}
}
out
}
}
impl Drop for GreenNode {
fn drop(&mut self) {
let mut stack: Vec<GreenChild> = core::mem::take(&mut self.children);
while let Some(child) = stack.pop() {
if let GreenChild::Node(node) = child {
if let Some(mut inner) = Arc::into_inner(node) {
stack.append(&mut inner.children);
}
}
}
}
}
#[derive(Debug, Clone)]
pub struct SyntaxNode {
green: Arc<GreenNode>,
offset: u32,
parent: Option<Arc<SyntaxNode>>,
}
impl SyntaxNode {
#[must_use]
pub const fn root(green: Arc<GreenNode>) -> Self {
Self {
green,
offset: 0,
parent: None,
}
}
#[must_use]
pub fn kind(&self) -> CstKind {
self.green.kind()
}
#[must_use]
pub fn span(&self) -> Span {
Span::new(self.offset, self.offset.saturating_add(self.green.width()))
}
#[must_use]
pub fn green(&self) -> &Arc<GreenNode> {
&self.green
}
#[must_use]
pub fn parent(&self) -> Option<&Arc<Self>> {
self.parent.as_ref()
}
#[must_use]
pub fn ancestors(&self) -> Vec<Arc<Self>> {
let mut out = Vec::new();
let mut current = self.parent.clone();
while let Some(node) = current {
current = node.parent.clone();
out.push(node);
}
out
}
#[must_use]
pub fn children(self: &Arc<Self>) -> Vec<Arc<Self>> {
let mut out = Vec::new();
let mut at = self.offset;
for child in self.green.children() {
match child {
GreenChild::Node(green) => {
out.push(Arc::new(Self {
green: green.clone(),
offset: at,
parent: Some(self.clone()),
}));
at = at.saturating_add(green.width());
}
GreenChild::Token(token) => at = at.saturating_add(token.width()),
}
}
out
}
#[must_use]
pub fn tokens(&self) -> Vec<(Span, GreenToken)> {
let mut out = Vec::new();
let mut at = self.offset;
for child in self.green.children() {
let width = child.width();
if let GreenChild::Token(token) = child {
out.push((Span::new(at, at.saturating_add(width)), token.clone()));
}
at = at.saturating_add(width);
}
out
}
#[must_use]
pub fn syntax_tokens(&self) -> Vec<(Span, GreenToken)> {
self.tokens()
.into_iter()
.filter(|(_, token)| !token.kind().is_trivia())
.collect()
}
#[must_use]
pub fn text(&self) -> String {
self.green.text()
}
#[must_use]
pub fn descendants(self: &Arc<Self>) -> Vec<Arc<Self>> {
let mut out = alloc::vec![self.clone()];
let mut index = 0;
while index < out.len() {
let node = out[index].clone();
out.extend(node.children());
index += 1;
}
out
}
#[must_use]
pub fn has_errors(self: &Arc<Self>) -> bool {
self.descendants().iter().any(|node| node.kind().is_error())
}
}
impl fmt::Display for SyntaxNode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.text())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Checkpoint {
depth: usize,
children: usize,
}
#[derive(Debug, Default)]
pub struct TreeBuilder {
stack: Vec<(CstKind, Vec<GreenChild>)>,
finished: Option<Arc<GreenNode>>,
}
impl TreeBuilder {
#[must_use]
pub const fn new() -> Self {
Self {
stack: Vec::new(),
finished: None,
}
}
pub fn start(&mut self, kind: CstKind) {
self.stack.push((kind, Vec::new()));
}
pub fn token(&mut self, kind: TokenKind, text: &str) {
if let Some((_, children)) = self.stack.last_mut() {
children.push(GreenChild::Token(GreenToken::new(kind, text)));
}
}
pub fn finish(&mut self) {
let Some((kind, children)) = self.stack.pop() else {
return;
};
let node = Arc::new(GreenNode::new(kind, children));
match self.stack.last_mut() {
Some((_, siblings)) => siblings.push(GreenChild::Node(node)),
None => self.finished = Some(node),
}
}
#[must_use]
pub fn build(mut self) -> Option<Arc<GreenNode>> {
while !self.stack.is_empty() {
self.finish();
}
self.finished
}
#[must_use]
pub fn depth(&self) -> usize {
self.stack.len()
}
#[must_use]
pub fn checkpoint(&self) -> Checkpoint {
Checkpoint {
depth: self.stack.len(),
children: self.stack.last().map_or(0, |(_, children)| children.len()),
}
}
pub fn start_at(&mut self, checkpoint: Checkpoint, kind: CstKind) {
if checkpoint.depth != self.stack.len() {
self.start(kind);
return;
}
let Some((_, children)) = self.stack.last_mut() else {
self.start(kind);
return;
};
if checkpoint.children > children.len() {
self.start(kind);
return;
}
let wrapped: Vec<GreenChild> = children.split_off(checkpoint.children);
self.stack.push((kind, wrapped));
}
}
#[derive(Debug, Clone, Default)]
pub struct SyntaxSpans {
spans: Vec<Span>,
}
impl SyntaxSpans {
#[must_use]
pub fn of(root: &Arc<SyntaxNode>) -> Self {
let mut spans = Vec::new();
let mut stack: Vec<(&GreenNode, u32)> = alloc::vec![(root.green(), root.span().start)];
while let Some((green, offset)) = stack.pop() {
let mut at = offset;
for child in green.children() {
let width = child.width();
match child {
GreenChild::Token(token) => {
if !token.kind().is_trivia() {
spans.push(Span::new(at, at.saturating_add(width)));
}
}
GreenChild::Node(node) => stack.push((node, at)),
}
at = at.saturating_add(width);
}
}
spans.sort_unstable_by_key(|span| span.start);
Self { spans }
}
#[must_use]
pub fn trim(&self, span: Span) -> Span {
if span.is_empty() {
return span;
}
let first = self.spans.partition_point(|token| token.start < span.start);
let Some(head) = self.spans.get(first) else {
return span;
};
if head.start >= span.end {
return span;
}
let last = self.spans.partition_point(|token| token.end <= span.end);
let end = match last.checked_sub(1).and_then(|index| self.spans.get(index)) {
Some(tail) if tail.end > head.start => tail.end,
_ => span.end,
};
Span::new(head.start, end)
}
}