use rowan::{GreenNode, GreenNodeBuilder};
use super::err::TomlResult;
use super::kinds::TomlKind::{self, *};
use super::parse_tkns::Tokenizer;
use super::walk::{walk, walk_tokens};
pub type SyntaxNode = rowan::SyntaxNode<TomlLang>;
pub type SyntaxToken = rowan::SyntaxToken<TomlLang>;
pub type SyntaxElement = rowan::NodeOrToken<SyntaxNode, SyntaxToken>;
pub trait SyntaxNodeExtTrait {
fn token_text(&self) -> String;
fn deep_eq(&self, other: &Self) -> bool;
}
impl From<TomlKind> for rowan::SyntaxKind {
fn from(kind: TomlKind) -> Self {
Self(kind as u16)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TomlLang;
impl rowan::Language for TomlLang {
type Kind = TomlKind;
fn kind_from_raw(raw: rowan::SyntaxKind) -> Self::Kind {
assert!(raw.0 <= Root as u16);
unsafe { std::mem::transmute::<u16, TomlKind>(raw.0) }
}
fn kind_to_raw(kind: Self::Kind) -> rowan::SyntaxKind {
kind.into()
}
}
impl SyntaxNodeExtTrait for SyntaxNode {
fn token_text(&self) -> String {
walk_tokens(self).fold(String::default(), |mut s, tkn| {
s.push_str(tkn.text());
s
})
}
fn deep_eq(&self, other: &Self) -> bool {
for (a, b) in walk(self).zip(walk(other)) {
match (&a, &b) {
(SyntaxElement::Node(n1), SyntaxElement::Node(n2)) => {
if n1.token_text() != n2.token_text() {
return false;
}
}
(SyntaxElement::Token(t1), SyntaxElement::Token(t2)) => {
if t1.text() != t2.text() {
return false;
}
}
(_, _) => return false,
}
if a.kind() != b.kind() {
return false;
}
}
true
}
}
pub struct ParsedToml {
green: rowan::GreenNode,
}
impl ParsedToml {
pub fn syntax(&self) -> SyntaxNode {
SyntaxNode::new_root(self.green.clone())
}
}
pub struct Parser {
pub(crate) builder: GreenNodeBuilder<'static>,
}
impl Default for Parser {
fn default() -> Self {
Parser::new()
}
}
impl Parser {
pub fn new() -> Parser {
Self {
builder: GreenNodeBuilder::new(),
}
}
pub fn parse(self) -> TomlResult<ParsedToml> {
let green: GreenNode = self.builder.finish();
Ok(ParsedToml { green })
}
}
pub fn parse_it(input: &str) -> TomlResult<ParsedToml> {
let parse_builder = Parser::new();
let parsed = Tokenizer::parse(input, parse_builder)?;
parsed.parse()
}