use std::fmt;
use crate::{
value::{self, StrPart, Value as ParsedValue, ValueError},
NodeOrToken, SyntaxElement,
SyntaxKind::{self, *},
SyntaxNode, SyntaxToken, WalkEvent,
};
macro_rules! typed {
($($kind:expr => $name:ident$(: $trait:ident)*$(: { $($block:tt)* })*),*) => {
$(
#[derive(Clone)]
pub struct $name(SyntaxNode);
impl TypedNode for $name {
fn cast(from: SyntaxNode) -> Option<Self> {
if from.kind() == $kind {
Some(Self(from))
} else {
None
}
}
fn node(&self) -> &SyntaxNode {
&self.0
}
}
$(impl $trait for $name {})*
$(impl $name { $($block)* })*
)*
}
}
macro_rules! nth {
($self:expr; $index:expr) => {
$self.node().children()
.nth($index)
};
($self:expr; ($kind:ident) $index:expr) => {
nth!($self; $index).and_then($kind::cast)
};
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum BinOpKind {
Concat,
IsSet,
Update,
Add,
Sub,
Mul,
Div,
And,
Equal,
Implication,
Less,
LessOrEq,
More,
MoreOrEq,
NotEqual,
Or,
}
impl BinOpKind {
pub fn from_token(token: SyntaxKind) -> Option<Self> {
match token {
TOKEN_CONCAT => Some(BinOpKind::Concat),
TOKEN_QUESTION => Some(BinOpKind::IsSet),
TOKEN_UPDATE => Some(BinOpKind::Update),
TOKEN_ADD => Some(BinOpKind::Add),
TOKEN_SUB => Some(BinOpKind::Sub),
TOKEN_MUL => Some(BinOpKind::Mul),
TOKEN_DIV => Some(BinOpKind::Div),
TOKEN_AND => Some(BinOpKind::And),
TOKEN_EQUAL => Some(BinOpKind::Equal),
TOKEN_IMPLICATION => Some(BinOpKind::Implication),
TOKEN_LESS => Some(BinOpKind::Less),
TOKEN_LESS_OR_EQ => Some(BinOpKind::LessOrEq),
TOKEN_MORE => Some(BinOpKind::More),
TOKEN_MORE_OR_EQ => Some(BinOpKind::MoreOrEq),
TOKEN_NOT_EQUAL => Some(BinOpKind::NotEqual),
TOKEN_OR => Some(BinOpKind::Or),
_ => None,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum UnaryOpKind {
Invert,
Negate,
}
impl UnaryOpKind {
pub fn from_token(token: SyntaxKind) -> Option<Self> {
match token {
TOKEN_INVERT => Some(UnaryOpKind::Invert),
TOKEN_SUB => Some(UnaryOpKind::Negate),
_ => None,
}
}
}
pub struct TextDump(SyntaxNode);
impl fmt::Display for TextDump {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut indent = 0;
let mut skip_newline = true;
for event in self.0.preorder_with_tokens() {
if skip_newline {
skip_newline = false;
} else {
writeln!(f)?;
}
match &event {
WalkEvent::Enter(enter) => {
write!(f, "{:i$}{:?}", "", enter.kind(), i = indent)?;
if let NodeOrToken::Token(token) = enter {
write!(f, "(\"{}\")", token.text().escape_default())?
}
write!(f, " {}..{}", enter.text_range().start(), enter.text_range().end())?;
if let NodeOrToken::Node(_) = enter {
write!(f, " {{")?;
}
indent += 2;
}
WalkEvent::Leave(leave) => {
indent -= 2;
if let NodeOrToken::Node(_) = leave {
write!(f, "{:i$}}}", "", i = indent)?;
} else {
skip_newline = true;
}
}
}
}
Ok(())
}
}
pub(crate) fn tokens(node: &SyntaxNode) -> impl Iterator<Item = SyntaxToken> {
node.children_with_tokens()
.filter_map(|element| element.into_token())
.filter(|token| !token.kind().is_trivia())
}
pub trait TypedNode: Clone {
fn cast(from: SyntaxNode) -> Option<Self>;
fn node(&self) -> &SyntaxNode;
fn errors(&self) -> Vec<SyntaxElement> {
self.node()
.descendants_with_tokens()
.filter(|node| !node.text_range().is_empty())
.filter(|node| node.kind() == NODE_ERROR || node.kind() == TOKEN_ERROR)
.collect()
}
fn first_token(&self) -> Option<SyntaxToken> {
tokens(self.node()).next()
}
fn dump(&self) -> TextDump {
TextDump(self.node().clone())
}
}
pub trait TokenWrapper: TypedNode {
fn as_str(&self) -> &str {
self.node().green().children()[0].as_token().unwrap().text().as_str()
}
}
pub trait EntryHolder: TypedNode {
fn entries(&self) -> Box<dyn Iterator<Item = KeyValue>> {
Box::new(self.node().children().filter_map(KeyValue::cast))
}
fn inherits(&self) -> Box<dyn Iterator<Item = Inherit>> {
Box::new(self.node().children().filter_map(Inherit::cast))
}
}
pub trait Wrapper: TypedNode {
fn inner(&self) -> Option<SyntaxNode> {
nth!(self; 0)
}
}
pub struct ParsedTypeError(pub SyntaxKind);
pub enum ParsedType {
Apply(Apply),
Assert(Assert),
Key(Key),
Dynamic(Dynamic),
Error(Error),
Ident(Ident),
IfElse(IfElse),
Select(Select),
Inherit(Inherit),
InheritFrom(InheritFrom),
Lambda(Lambda),
LegacyLet(LegacyLet),
LetIn(LetIn),
List(List),
BinOp(BinOp),
OrDefault(OrDefault),
Paren(Paren),
PatBind(PatBind),
PatEntry(PatEntry),
Pattern(Pattern),
Root(Root),
AttrSet(AttrSet),
KeyValue(KeyValue),
Str(Str),
UnaryOp(UnaryOp),
Value(Value),
With(With),
}
impl core::convert::TryFrom<SyntaxNode> for ParsedType {
type Error = ParsedTypeError;
fn try_from(node: SyntaxNode) -> Result<Self, ParsedTypeError> {
match node.kind() {
NODE_APPLY => Ok(ParsedType::Apply(Apply::cast(node).unwrap())),
NODE_ASSERT => Ok(ParsedType::Assert(Assert::cast(node).unwrap())),
NODE_KEY => Ok(ParsedType::Key(Key::cast(node).unwrap())),
NODE_DYNAMIC => Ok(ParsedType::Dynamic(Dynamic::cast(node).unwrap())),
NODE_ERROR => Ok(ParsedType::Error(Error::cast(node).unwrap())),
NODE_IDENT => Ok(ParsedType::Ident(Ident::cast(node).unwrap())),
NODE_IF_ELSE => Ok(ParsedType::IfElse(IfElse::cast(node).unwrap())),
NODE_SELECT => Ok(ParsedType::Select(Select::cast(node).unwrap())),
NODE_INHERIT => Ok(ParsedType::Inherit(Inherit::cast(node).unwrap())),
NODE_INHERIT_FROM => Ok(ParsedType::InheritFrom(InheritFrom::cast(node).unwrap())),
NODE_STRING => Ok(ParsedType::Str(Str::cast(node).unwrap())),
NODE_LAMBDA => Ok(ParsedType::Lambda(Lambda::cast(node).unwrap())),
NODE_LEGACY_LET => Ok(ParsedType::LegacyLet(LegacyLet::cast(node).unwrap())),
NODE_LET_IN => Ok(ParsedType::LetIn(LetIn::cast(node).unwrap())),
NODE_LIST => Ok(ParsedType::List(List::cast(node).unwrap())),
NODE_BIN_OP => Ok(ParsedType::BinOp(BinOp::cast(node).unwrap())),
NODE_OR_DEFAULT => Ok(ParsedType::OrDefault(OrDefault::cast(node).unwrap())),
NODE_PAREN => Ok(ParsedType::Paren(Paren::cast(node).unwrap())),
NODE_PATTERN => Ok(ParsedType::Pattern(Pattern::cast(node).unwrap())),
NODE_PAT_BIND => Ok(ParsedType::PatBind(PatBind::cast(node).unwrap())),
NODE_PAT_ENTRY => Ok(ParsedType::PatEntry(PatEntry::cast(node).unwrap())),
NODE_ROOT => Ok(ParsedType::Root(Root::cast(node).unwrap())),
NODE_ATTR_SET => Ok(ParsedType::AttrSet(AttrSet::cast(node).unwrap())),
NODE_KEY_VALUE => Ok(ParsedType::KeyValue(KeyValue::cast(node).unwrap())),
NODE_UNARY_OP => Ok(ParsedType::UnaryOp(UnaryOp::cast(node).unwrap())),
NODE_LITERAL => Ok(ParsedType::Value(Value::cast(node).unwrap())),
NODE_WITH => Ok(ParsedType::With(With::cast(node).unwrap())),
other => Err(ParsedTypeError(other)),
}
}
}
typed! [
NODE_IDENT => Ident: TokenWrapper: {
},
NODE_LITERAL => Value: TokenWrapper: {
pub fn to_value(&self) -> Result<ParsedValue, ValueError> {
ParsedValue::from_token(self.first_token().expect("invalid ast").kind(), self.as_str())
}
},
NODE_APPLY => Apply: {
pub fn lambda(&self) -> Option<SyntaxNode> {
nth!(self; 0)
}
pub fn value(&self) -> Option<SyntaxNode> {
nth!(self; 1)
}
},
NODE_ASSERT => Assert: {
pub fn condition(&self) -> Option<SyntaxNode> {
nth!(self; 0)
}
pub fn body(&self) -> Option<SyntaxNode> {
nth!(self; 1)
}
},
NODE_KEY => Key: {
pub fn path<'a>(&'a self) -> impl Iterator<Item = SyntaxNode> + 'a {
self.node().children()
}
},
NODE_DYNAMIC => Dynamic: Wrapper,
NODE_ERROR => Error,
NODE_IF_ELSE => IfElse: {
pub fn condition(&self) -> Option<SyntaxNode> {
nth!(self; 0)
}
pub fn body(&self) -> Option<SyntaxNode> {
nth!(self; 1)
}
pub fn else_body(&self) -> Option<SyntaxNode> {
nth!(self; 2)
}
},
NODE_SELECT => Select: {
pub fn set(&self) -> Option<SyntaxNode> {
nth!(self; 0)
}
pub fn index(&self) -> Option<SyntaxNode> {
nth!(self; 1)
}
},
NODE_INHERIT => Inherit: {
pub fn from(&self) -> Option<InheritFrom> {
self.node().children()
.find_map(InheritFrom::cast)
}
pub fn idents(&self) -> impl Iterator<Item = Ident> {
self.node().children().filter_map(Ident::cast)
}
},
NODE_INHERIT_FROM => InheritFrom: Wrapper,
NODE_STRING => Str: {
pub fn parts(&self) -> Vec<StrPart> {
value::string_parts(self)
}
},
NODE_LAMBDA => Lambda: {
pub fn arg(&self) -> Option<SyntaxNode> {
nth!(self; 0)
}
pub fn body(&self) -> Option<SyntaxNode> {
nth!(self; 1)
}
},
NODE_LEGACY_LET => LegacyLet: EntryHolder,
NODE_LET_IN => LetIn: EntryHolder: {
pub fn body(&self) -> Option<SyntaxNode> {
self.node().last_child()
}
},
NODE_LIST => List: {
pub fn items(&self) -> impl Iterator<Item = SyntaxNode> {
self.node().children()
}
},
NODE_BIN_OP => BinOp: {
pub fn lhs(&self) -> Option<SyntaxNode> {
nth!(self; 0)
}
pub fn operator(&self) -> BinOpKind {
self.first_token().and_then(|t| BinOpKind::from_token(t.kind())).expect("invalid ast")
}
pub fn rhs(&self) -> Option<SyntaxNode> {
nth!(self; 1)
}
},
NODE_OR_DEFAULT => OrDefault: {
pub fn index(&self) -> Option<Select> {
nth!(self; (Select) 0)
}
pub fn default(&self) -> Option<SyntaxNode> {
nth!(self; 1)
}
},
NODE_PAREN => Paren: Wrapper,
NODE_PAT_BIND => PatBind: {
pub fn name(&self) -> Option<Ident> {
nth!(self; (Ident) 0)
}
},
NODE_PAT_ENTRY => PatEntry: {
pub fn name(&self) -> Option<Ident> {
nth!(self; (Ident) 0)
}
pub fn default(&self) -> Option<SyntaxNode> {
self.node().children().nth(1)
}
},
NODE_PATTERN => Pattern: {
pub fn entries(&self) -> impl Iterator<Item = PatEntry> {
self.node().children().filter_map(PatEntry::cast)
}
pub fn ellipsis(&self) -> bool {
self.node().children_with_tokens().any(|node| node.kind() == TOKEN_ELLIPSIS)
}
pub fn filter_entries<F>(&self, _callback: F) -> Root
where F: FnMut(&PatEntry) -> bool
{
unimplemented!("TODO: filter_entries or better editing API")
}
},
NODE_ROOT => Root: Wrapper,
NODE_ATTR_SET => AttrSet: EntryHolder: {
pub fn recursive(&self) -> bool {
self.node().children_with_tokens().any(|node| node.kind() == TOKEN_REC)
}
pub fn filter_entries<F>(&self, _callback: F) -> Root
where F: FnMut(&KeyValue) -> bool
{
unimplemented!("TODO: filter_entries or better editing API")
}
},
NODE_KEY_VALUE => KeyValue: {
pub fn key(&self) -> Option<Key> {
nth!(self; (Key) 0)
}
pub fn value(&self) -> Option<SyntaxNode> {
nth!(self; 1)
}
},
NODE_UNARY_OP => UnaryOp: {
pub fn operator(&self) -> UnaryOpKind {
self.first_token().and_then(|t| UnaryOpKind::from_token(t.kind())).expect("invalid ast")
}
pub fn value(&self) -> Option<SyntaxNode> {
nth!(self; 0)
}
},
NODE_WITH => With: {
pub fn namespace(&self) -> Option<SyntaxNode> {
nth!(self; 0)
}
pub fn body(&self) -> Option<SyntaxNode> {
nth!(self; 1)
}
}
];