use alloc::fmt::{Display, Error, Formatter};
use core::iter::FusedIterator;
use serde::ser::{Serialize, SerializeSeq, SerializeStruct, Serializer};
use crate::symbols::{SemanticElementTrait, Symbol};
use crate::text::{TextContext, TextPosition, TextSpan};
use crate::tokens::{Token, TokenRepository};
use crate::utils::biglist::BigList;
use crate::utils::EitherMut;
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum TableType {
None = 0,
Token = 1,
Variable = 2,
Virtual = 3
}
impl From<usize> for TableType {
fn from(x: usize) -> Self {
match x {
1 => TableType::Token,
2 => TableType::Variable,
3 => TableType::Virtual,
_ => TableType::None
}
}
}
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
pub struct TableElemRef {
data: usize
}
impl TableElemRef {
#[must_use]
pub fn new(t: TableType, index: usize) -> TableElemRef {
TableElemRef {
data: ((t as usize) << 30) | index
}
}
#[must_use]
pub fn table_type(self) -> TableType {
TableType::from(self.data >> 30)
}
#[must_use]
pub fn index(self) -> usize {
self.data & 0x3FFF_FFFF
}
}
#[derive(Debug, Default, Copy, Clone)]
pub struct AstCell {
pub label: TableElemRef,
pub count: u32,
pub first: u32
}
impl AstCell {
#[must_use]
pub fn new_empty(label: TableElemRef) -> AstCell {
AstCell {
label,
count: 0,
first: 0
}
}
#[must_use]
pub fn new(label: TableElemRef, count: u32, first: u32) -> AstCell {
AstCell {
label,
count,
first
}
}
}
#[derive(Debug, Default, Clone)]
pub struct AstImpl {
nodes: BigList<AstCell>,
root: Option<usize>
}
impl AstImpl {
#[must_use]
pub fn has_root(&self) -> bool {
self.root.is_some()
}
}
pub struct Ast<'s, 't, 'a> {
tokens: Option<TokenRepository<'s, 't, 'a>>,
pub variables: &'a [Symbol<'s>],
pub virtuals: &'a [Symbol<'s>],
data: EitherMut<'a, AstImpl>
}
impl<'s, 't, 'a> Ast<'s, 't, 'a> {
#[must_use]
pub fn new(
tokens: TokenRepository<'s, 't, 'a>,
variables: &'a [Symbol<'s>],
virtuals: &'a [Symbol<'s>],
data: &'a AstImpl
) -> Ast<'s, 't, 'a> {
Ast {
tokens: Some(tokens),
variables,
virtuals,
data: EitherMut::Immutable(data)
}
}
pub fn new_mut(
variables: &'a [Symbol<'s>],
virtuals: &'a [Symbol<'s>],
data: &'a mut AstImpl
) -> Ast<'s, 't, 'a> {
Ast {
tokens: None,
variables,
virtuals,
data: EitherMut::Mutable(data)
}
}
fn get_token(&'a self, index: usize) -> Token<'s, 't, 'a> {
self.tokens
.as_ref()
.expect("Missing token repository")
.get_token(index)
}
#[must_use]
pub fn has_root(&self) -> bool {
self.data.has_root()
}
#[must_use]
pub fn get_root(&self) -> AstNode {
self.data
.root
.map(|x| AstNode {
tree: self,
index: x
})
.expect("No root defined!")
}
#[must_use]
pub fn get_node(&self, id: usize) -> AstNode {
AstNode {
tree: self,
index: id
}
}
#[must_use]
pub fn find_node_for(&self, token: &Token) -> Option<AstNode> {
self.data
.nodes
.iter()
.enumerate()
.find(|(_, node)| {
node.label.table_type() == TableType::Token && node.label.index() == token.index
})
.map(|(index, _)| AstNode { tree: self, index })
}
#[must_use]
pub fn find_node_at_index(&self, index: usize) -> Option<AstNode> {
self.tokens
.as_ref()?
.find_token_at(index)
.and_then(|token| self.find_node_for(&token))
}
#[must_use]
pub fn find_node_at_position(&self, position: TextPosition) -> Option<AstNode> {
let tokens = self.tokens.as_ref()?;
let index = tokens.text.get_line_index(position.line) + position.column - 1;
tokens
.find_token_at(index)
.and_then(|token| self.find_node_for(&token))
}
#[must_use]
pub fn find_parent_of(&'a self, node: usize) -> Option<AstNode<'s, 't, 'a>> {
self.data
.nodes
.iter()
.enumerate()
.find(|(_, candidate)| {
candidate.count > 0
&& node >= candidate.first as usize
&& node < (candidate.first + candidate.count) as usize
})
.map(|(index, _)| AstNode { tree: self, index })
}
#[must_use]
pub fn get_total_position_and_span(&self, node: usize) -> Option<(TextPosition, TextSpan)> {
let mut total_span: Option<TextSpan> = None;
let mut position = TextPosition {
line: usize::MAX,
column: usize::MAX
};
self.traverse(node, |data, current| {
if let Some(p) = self.get_position_at(data, current) {
if p < position {
position = p;
}
}
if let Some(total_span) = total_span.as_mut() {
if let Some(span) = self.get_span_at(data, current) {
if span.index + span.length > total_span.index + total_span.length {
let margin =
(span.index + span.length) - (total_span.index + total_span.length);
total_span.length += margin;
}
if span.index < total_span.index {
let margin = total_span.index - span.index;
total_span.length += margin;
total_span.index -= margin;
}
}
} else {
total_span = self.get_span_at(data, current);
}
});
total_span.map(|span| (position, span))
}
#[must_use]
pub fn get_total_span(&self, node: usize) -> Option<TextSpan> {
self.get_total_position_and_span(node).map(|(_, span)| span)
}
fn traverse<F: FnMut(&AstImpl, usize)>(&self, from: usize, mut action: F) {
let mut stack = alloc::vec![from];
while let Some(current) = stack.pop() {
let cell = self.data.nodes[current];
for i in (0..cell.count).rev() {
stack.push((cell.first + i) as usize);
}
action(&self.data, current);
}
}
#[must_use]
fn get_span_at(&self, data: &AstImpl, node: usize) -> Option<TextSpan> {
let cell = data.nodes[node];
match cell.label.table_type() {
TableType::Token => {
let token = self.get_token(cell.label.index());
token.get_span()
}
_ => None
}
}
#[must_use]
fn get_position_at(&self, data: &AstImpl, node: usize) -> Option<TextPosition> {
let cell = data.nodes[node];
match cell.label.table_type() {
TableType::Token => {
let token = self.get_token(cell.label.index());
token.get_position()
}
_ => None
}
}
pub fn store(&mut self, nodes: &[AstCell], index: usize, count: usize) -> usize {
if count == 0 {
0
} else {
let result = self.data.nodes.push(nodes[index]);
for i in 1..count {
self.data.nodes.push(nodes[index + i]);
}
result
}
}
pub fn store_root(&mut self, node: AstCell) {
self.data.root = Some(self.data.nodes.push(node));
}
}
#[derive(Copy, Clone)]
pub struct AstNode<'s, 't, 'a> {
tree: &'a Ast<'s, 't, 'a>,
index: usize
}
impl<'s, 't, 'a> AstNode<'s, 't, 'a> {
#[must_use]
pub fn id(&self) -> usize {
self.index
}
#[must_use]
pub fn get_token_index(&self) -> Option<usize> {
let cell = self.tree.data.nodes[self.index];
match cell.label.table_type() {
TableType::Token => Some(cell.label.index()),
_ => None
}
}
#[must_use]
pub fn parent(&self) -> Option<AstNode<'s, 't, 'a>> {
self.tree.find_parent_of(self.index)
}
#[must_use]
pub fn children(&self) -> AstFamily<'s, 't, 'a> {
AstFamily {
tree: self.tree,
parent: self.index
}
}
#[must_use]
pub fn child(&self, index: usize) -> AstNode<'s, 't, 'a> {
let cell = self.tree.data.nodes[self.index];
AstNode {
tree: self.tree,
index: cell.first as usize + index
}
}
#[must_use]
pub fn children_count(&self) -> usize {
self.tree.data.nodes[self.index].count as usize
}
#[must_use]
pub fn get_total_span(&self) -> Option<TextSpan> {
self.tree.get_total_span(self.index)
}
#[must_use]
pub fn get_total_position_and_span(&self) -> Option<(TextPosition, TextSpan)> {
self.tree.get_total_position_and_span(self.index)
}
}
impl<'s, 't, 'a> SemanticElementTrait<'s, 'a> for AstNode<'s, 't, 'a> {
fn get_position(&self) -> Option<TextPosition> {
self.tree.get_position_at(&self.tree.data, self.index)
}
fn get_span(&self) -> Option<TextSpan> {
self.tree.get_span_at(&self.tree.data, self.index)
}
fn get_context(&self) -> Option<TextContext<'a>> {
let cell = self.tree.data.nodes[self.index];
match cell.label.table_type() {
TableType::Token => {
let token = self.tree.get_token(cell.label.index());
token.get_context()
}
_ => None
}
}
fn get_symbol(&self) -> Symbol<'s> {
let cell = self.tree.data.nodes[self.index];
match cell.label.table_type() {
TableType::Token => {
let token = self.tree.get_token(cell.label.index());
token.get_symbol()
}
TableType::Variable => self.tree.variables[cell.label.index()],
TableType::Virtual => self.tree.virtuals[cell.label.index()],
TableType::None => {
match &self.tree.tokens {
None => panic!("Missing token repository"),
Some(repository) => repository.terminals[0] }
}
}
}
fn get_value(&self) -> Option<&'a str> {
let cell = self.tree.data.nodes[self.index];
match cell.label.table_type() {
TableType::Token => {
let token = self.tree.get_token(cell.label.index());
token.get_value()
}
_ => None
}
}
}
impl<'s, 't, 'a> PartialEq<AstNode<'s, 't, 'a>> for AstNode<'s, 't, 'a> {
fn eq(&self, other: &AstNode<'s, 't, 'a>) -> bool {
self.index == other.index
}
}
impl<'s, 't, 'a> Eq for AstNode<'s, 't, 'a> {}
impl<'s, 't, 'a> IntoIterator for AstNode<'s, 't, 'a> {
type Item = AstNode<'s, 't, 'a>;
type IntoIter = AstFamilyIterator<'s, 't, 'a>;
fn into_iter(self) -> Self::IntoIter {
let cell = self.tree.data.nodes[self.index];
AstFamilyIterator {
tree: self.tree,
current: cell.first as usize,
end: (cell.first + cell.count) as usize
}
}
}
impl<'s, 't, 'a> Display for AstNode<'s, 't, 'a> {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
let cell = self.tree.data.nodes[self.index];
match cell.label.table_type() {
TableType::Token => {
let token = self.tree.get_token(cell.label.index());
let symbol = token.get_symbol();
let value = token.get_value();
write!(f, "{} = {}", symbol.name, value.unwrap())
}
TableType::Variable => {
let symbol = self.tree.variables[cell.label.index()];
write!(f, "{}", symbol.name)
}
TableType::Virtual => {
let symbol = self.tree.virtuals[cell.label.index()];
write!(f, "{}", symbol.name)
}
TableType::None => match &self.tree.tokens {
None => panic!("Missing token repository"),
Some(repository) => {
let symbol = repository.terminals[0];
write!(f, "{}", symbol.name)
}
}
}
}
}
impl<'s, 't, 'a> Serialize for AstNode<'s, 't, 'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer
{
let mut state = serializer.serialize_struct("AstNode", 5)?;
state.serialize_field("symbol", &self.get_symbol())?;
state.serialize_field("position", &self.get_position())?;
state.serialize_field("span", &self.get_span())?;
state.serialize_field("value", &self.get_value())?;
state.serialize_field("children", &self.children())?;
state.end()
}
}
#[derive(Clone)]
pub struct AstFamily<'s, 't, 'a> {
tree: &'a Ast<'s, 't, 'a>,
parent: usize
}
pub struct AstFamilyIterator<'s, 't, 'a> {
tree: &'a Ast<'s, 't, 'a>,
current: usize,
end: usize
}
impl<'s, 't, 'a> Iterator for AstFamilyIterator<'s, 't, 'a> {
type Item = AstNode<'s, 't, 'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.current >= self.end {
None
} else {
let result = AstNode {
tree: self.tree,
index: self.current
};
self.current += 1;
Some(result)
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let c = self.end - self.current;
(c, Some(c))
}
}
impl<'s, 't, 'a> DoubleEndedIterator for AstFamilyIterator<'s, 't, 'a> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.current >= self.end {
None
} else {
let result = AstNode {
tree: self.tree,
index: self.end - 1
};
self.end -= 1;
Some(result)
}
}
}
impl<'s, 't, 'a> ExactSizeIterator for AstFamilyIterator<'s, 't, 'a> {}
impl<'s, 't, 'a> FusedIterator for AstFamilyIterator<'s, 't, 'a> {}
impl<'s, 't, 'a> IntoIterator for AstFamily<'s, 't, 'a> {
type Item = AstNode<'s, 't, 'a>;
type IntoIter = AstFamilyIterator<'s, 't, 'a>;
fn into_iter(self) -> Self::IntoIter {
let cell = self.tree.data.nodes[self.parent];
AstFamilyIterator {
tree: self.tree,
current: cell.first as usize,
end: (cell.first + cell.count) as usize
}
}
}
impl<'s, 't, 'a> AstFamily<'s, 't, 'a> {
#[must_use]
pub fn is_empty(&self) -> bool {
self.tree.data.nodes[self.parent].count == 0
}
#[must_use]
pub fn len(&self) -> usize {
self.tree.data.nodes[self.parent].count as usize
}
#[must_use]
pub fn at(&self, index: usize) -> AstNode<'s, 't, 'a> {
let cell = self.tree.data.nodes[self.parent];
AstNode {
tree: self.tree,
index: cell.first as usize + index
}
}
#[must_use]
pub fn iter(&self) -> AstFamilyIterator<'s, 't, 'a> {
let cell = self.tree.data.nodes[self.parent];
AstFamilyIterator {
tree: self.tree,
current: cell.first as usize,
end: (cell.first + cell.count) as usize
}
}
}
impl<'s, 't, 'a> Serialize for AstFamily<'s, 't, 'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer
{
let mut seq = serializer.serialize_seq(Some(self.len()))?;
for node in self.iter() {
seq.serialize_element(&node)?;
}
seq.end()
}
}