use crate::diagnostic::Diagnostic;
use crate::span::Span;
use crate::syntax::{NodeKind, SyntaxElement, SyntaxNode, SyntaxToken};
use crate::token::TokenKind;
trait AstNode<'a>: Sized {
fn cast(node: SyntaxNode<'a>) -> Option<Self>;
}
macro_rules! node {
($(#[$doc:meta])* $name:ident = $kind:ident) => {
$(#[$doc])*
#[derive(Debug, Clone, Copy)]
pub struct $name<'a>(SyntaxNode<'a>);
impl<'a> $name<'a> {
pub fn cast(node: SyntaxNode<'a>) -> Option<Self> {
(node.kind() == NodeKind::$kind).then_some(Self(node))
}
pub fn syntax(self) -> SyntaxNode<'a> {
self.0
}
}
impl<'a> AstNode<'a> for $name<'a> {
fn cast(node: SyntaxNode<'a>) -> Option<Self> {
Self::cast(node)
}
}
};
}
macro_rules! choice {
(
$(#[$doc:meta])*
$name:ident { $($(#[$variant_doc:meta])* $variant:ident($ty:ident),)* }
) => {
$(#[$doc])*
#[derive(Debug, Clone, Copy)]
pub enum $name<'a> {
$($(#[$variant_doc])* $variant($ty<'a>),)*
}
impl<'a> $name<'a> {
pub fn cast(node: SyntaxNode<'a>) -> Option<Self> {
$(
if let Some(inner) = $ty::cast(node) {
return Some(Self::$variant(inner));
}
)*
None
}
pub fn syntax(self) -> SyntaxNode<'a> {
match self {
$(Self::$variant(inner) => inner.syntax(),)*
}
}
}
impl<'a> AstNode<'a> for $name<'a> {
fn cast(node: SyntaxNode<'a>) -> Option<Self> {
Self::cast(node)
}
}
};
}
fn child<'a, N: AstNode<'a>>(node: SyntaxNode<'a>) -> Option<N> {
node.children().find_map(N::cast)
}
fn children<'a, N: AstNode<'a>>(node: SyntaxNode<'a>) -> impl Iterator<Item = N> {
node.children().filter_map(N::cast)
}
fn tokens(node: SyntaxNode<'_>) -> impl Iterator<Item = SyntaxToken<'_>> {
node.children_with_tokens()
.filter_map(|element| match element {
SyntaxElement::Token(token) => Some(token),
SyntaxElement::Node(_) => None,
})
}
fn token(node: SyntaxNode<'_>, kind: TokenKind) -> Option<SyntaxToken<'_>> {
tokens(node).find(|token| token.kind() == kind)
}
fn is_name(token: &SyntaxToken<'_>) -> bool {
matches!(token.kind(), TokenKind::Ident | TokenKind::TypeIdent)
}
fn names(node: SyntaxNode<'_>) -> impl Iterator<Item = SyntaxToken<'_>> {
tokens(node).filter(is_name)
}
fn child_after<'a, N: AstNode<'a>>(
node: SyntaxNode<'a>,
after: TokenKind,
before: &[TokenKind],
) -> Option<N> {
let mut seen = false;
for element in node.children_with_tokens() {
match element {
SyntaxElement::Token(token) if !seen => seen = token.kind() == after,
SyntaxElement::Token(token) if before.contains(&token.kind()) => return None,
SyntaxElement::Node(node) if seen => {
if let Some(found) = N::cast(node) {
return Some(found);
}
}
_ => {}
}
}
None
}
fn name_after(node: SyntaxNode<'_>, after: TokenKind) -> Option<SyntaxToken<'_>> {
tokens(node)
.skip_while(|token| token.kind() != after)
.skip(1)
.find(is_name)
}
fn binding_name(node: SyntaxNode<'_>) -> Option<SyntaxToken<'_>> {
tokens(node).find(|token| is_name(token) || token.kind() == TokenKind::SymWord)
}
fn first_key<'a>(mut elements: impl Iterator<Item = SyntaxElement<'a>>) -> Option<Key<'a>> {
elements.find_map(Key::from_element)
}
fn first_token(node: SyntaxNode<'_>) -> Option<SyntaxToken<'_>> {
let mut node = node;
loop {
match node.children_with_tokens().next()? {
SyntaxElement::Token(token) => return Some(token),
SyntaxElement::Node(child) => node = child,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum FileKind {
Entry,
Library,
Part,
}
node! {
SourceFile = File
}
impl<'a> SourceFile<'a> {
pub(crate) fn from_root(root: SyntaxNode<'a>) -> Self {
Self(root)
}
pub fn items(self) -> impl Iterator<Item = Item<'a>> {
children(self.0)
}
pub fn validate(self, kind: FileKind) -> Vec<Diagnostic> {
let mut diagnostics = Vec::new();
for item in self.items() {
let node = item.syntax();
let span = first_token(node).map_or(node.span(), SyntaxToken::span);
match (kind, item) {
(FileKind::Library, Item::Stmt(stmt)) if !matches!(stmt, Stmt::Let(_)) => {
diagnostics.push(
Diagnostic::error("E0209", span, "a library cannot contain statements")
.with_help("move the statement into an entry file or a part file"),
);
}
(FileKind::Part, Item::Struct(_) | Item::Type(_) | Item::Fn(_)) => {
let keyword = first_token(node).map_or("", SyntaxToken::text);
diagnostics.push(
Diagnostic::error(
"E0214",
span,
format!("a part file cannot contain a `{keyword}` declaration"),
)
.with_help("move the declaration into a library and import it"),
);
}
_ => {}
}
}
diagnostics
}
}
choice! {
Item {
Import(Import),
Struct(StructDecl),
Type(TypeDecl),
Fn(FnDecl),
Stmt(Stmt),
}
}
node! {
Import = Import
}
impl<'a> Import<'a> {
pub fn path(self) -> Option<Str<'a>> {
child(self.0)
}
pub fn alias(self) -> Option<SyntaxToken<'a>> {
name_after(self.0, TokenKind::AsKw)
}
}
node! {
StructDecl = Struct
}
impl<'a> StructDecl<'a> {
pub fn name(self) -> Option<SyntaxToken<'a>> {
names(self.0).next()
}
pub fn fields(self) -> impl Iterator<Item = Field<'a>> {
children(self.0)
}
}
node! {
Field = Field
}
impl<'a> Field<'a> {
pub fn name(self) -> Option<SyntaxToken<'a>> {
binding_name(self.0)
}
pub fn ty(self) -> Option<Type<'a>> {
child(self.0)
}
pub fn default(self) -> Option<Expr<'a>> {
child_after(self.0, TokenKind::Eq, &[])
}
pub fn block_kind(self) -> Option<SyntaxToken<'a>> {
name_after(self.0, TokenKind::BlockKw)
}
}
node! {
TypeDecl = TypeDecl
}
impl<'a> TypeDecl<'a> {
pub fn name(self) -> Option<SyntaxToken<'a>> {
names(self.0).next()
}
pub fn variants(self) -> impl Iterator<Item = Variant<'a>> {
children(self.0)
}
}
node! {
Variant = Variant
}
impl<'a> Variant<'a> {
pub fn name(self) -> Option<SyntaxToken<'a>> {
names(self.0).next()
}
pub fn params(self) -> Option<ParamList<'a>> {
child(self.0)
}
}
node! {
FnDecl = FnDecl
}
impl<'a> FnDecl<'a> {
pub fn name(self) -> Option<SyntaxToken<'a>> {
names(self.0).next()
}
pub fn params(self) -> Option<ParamList<'a>> {
child(self.0)
}
pub fn return_type(self) -> Option<Type<'a>> {
child_after(self.0, TokenKind::Arrow, &[])
}
pub fn body(self) -> Option<Expr<'a>> {
child_after(self.0, TokenKind::Eq, &[])
}
}
node! {
ParamList = ParamList
}
impl<'a> ParamList<'a> {
pub fn params(self) -> impl Iterator<Item = Param<'a>> {
children(self.0)
}
}
node! {
Param = Param
}
impl<'a> Param<'a> {
pub fn name(self) -> Option<SyntaxToken<'a>> {
binding_name(self.0)
}
pub fn ty(self) -> Option<Type<'a>> {
child(self.0)
}
pub fn default(self) -> Option<Expr<'a>> {
child_after(self.0, TokenKind::Eq, &[])
}
}
node! {
Let = Let
}
impl<'a> Let<'a> {
pub fn name(self) -> Option<SyntaxToken<'a>> {
binding_name(self.0)
}
pub fn ty(self) -> Option<Type<'a>> {
child(self.0)
}
pub fn value(self) -> Option<Expr<'a>> {
child_after(self.0, TokenKind::Eq, &[])
}
}
choice! {
Stmt {
Let(Let),
Attr(Attr),
Block(Block),
Include(Include),
If(IfStmt),
For(ForStmt),
}
}
node! {
Body = Body
}
impl<'a> Body<'a> {
pub fn statements(self) -> impl Iterator<Item = Stmt<'a>> {
children(self.0)
}
}
node! {
Attr = Attr
}
impl<'a> Attr<'a> {
pub fn path(self) -> Option<AttrPath<'a>> {
child(self.0)
}
pub fn value(self) -> Option<Expr<'a>> {
child_after(self.0, TokenKind::Eq, &[])
}
}
node! {
AttrPath = AttrPath
}
impl<'a> AttrPath<'a> {
pub fn keys(self) -> impl Iterator<Item = Key<'a>> {
self.0.children_with_tokens().filter_map(Key::from_element)
}
}
#[derive(Debug, Clone, Copy)]
pub enum Key<'a> {
Name(SyntaxToken<'a>),
Str(Str<'a>),
}
impl<'a> Key<'a> {
fn from_element(element: SyntaxElement<'a>) -> Option<Self> {
match element {
SyntaxElement::Token(token) if is_name(&token) => Some(Self::Name(token)),
SyntaxElement::Node(node) => Str::cast(node).map(Self::Str),
SyntaxElement::Token(_) => None,
}
}
pub fn span(self) -> Span {
match self {
Self::Name(token) => token.span(),
Self::Str(string) => string.syntax().span(),
}
}
}
node! {
Block = Block
}
impl<'a> Block<'a> {
pub fn kind(self) -> Option<SyntaxToken<'a>> {
names(self.0).next()
}
pub fn label(self) -> Option<Key<'a>> {
first_key(
self.0
.children_with_tokens()
.skip_while(|element| !matches!(element, SyntaxElement::Token(t) if is_name(t)))
.skip(1),
)
}
pub fn body(self) -> Option<Body<'a>> {
child(self.0)
}
}
node! {
Include = Include
}
impl<'a> Include<'a> {
pub fn value(self) -> Option<Expr<'a>> {
child(self.0)
}
}
node! {
IfStmt = IfStmt
}
impl<'a> IfStmt<'a> {
pub fn condition(self) -> Option<Expr<'a>> {
child(self.0)
}
pub fn then_body(self) -> Option<Body<'a>> {
child(self.0)
}
pub fn else_branch(self) -> Option<ElseBranch<'a>> {
child_after(self.0, TokenKind::ElseKw, &[])
}
}
choice! {
ElseBranch {
Body(Body),
If(IfStmt),
}
}
node! {
ForStmt = ForStmt
}
impl<'a> ForStmt<'a> {
pub fn names(self) -> impl Iterator<Item = SyntaxToken<'a>> {
loop_names(self.0)
}
pub fn collection(self) -> Option<Expr<'a>> {
child(self.0)
}
pub fn body(self) -> Option<Body<'a>> {
child(self.0)
}
}
fn loop_names(node: SyntaxNode<'_>) -> impl Iterator<Item = SyntaxToken<'_>> {
tokens(node)
.skip_while(|token| token.kind() != TokenKind::ForKw)
.take_while(|token| token.kind() != TokenKind::InKw)
.filter(is_name)
}
choice! {
Expr {
Literal(Literal),
Str(Str),
Name(Name),
Symbol(Symbol),
SelfExpr(SelfExpr),
List(List),
ListComp(ListComp),
Map(Map),
MapComp(MapComp),
StructLit(StructLit),
Paren(Paren),
Call(Call),
Field(FieldExpr),
Index(IndexExpr),
Binary(BinaryExpr),
Unary(UnaryExpr),
If(IfExpr),
Match(MatchExpr),
Let(LetExpr),
Lambda(Lambda),
Part(PartExpr),
}
}
node! {
Literal = Literal
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum LiteralKind {
Int,
Float,
Path,
True,
False,
None,
}
impl<'a> Literal<'a> {
pub fn token(self) -> Option<SyntaxToken<'a>> {
tokens(self.0).next()
}
pub fn kind(self) -> Option<LiteralKind> {
Some(match self.token()?.kind() {
TokenKind::Int => LiteralKind::Int,
TokenKind::Float => LiteralKind::Float,
TokenKind::Path => LiteralKind::Path,
TokenKind::TrueKw => LiteralKind::True,
TokenKind::FalseKw => LiteralKind::False,
TokenKind::NoneKw => LiteralKind::None,
_ => return None,
})
}
}
node! {
Str = Str
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum StrKind {
Plain,
Multi,
Raw,
RawMulti,
}
#[derive(Debug, Clone, Copy)]
pub enum StrPart<'a> {
Text(SyntaxToken<'a>),
Escape(SyntaxToken<'a>),
Interp(Interp<'a>),
}
impl<'a> Str<'a> {
pub fn kind(self) -> Option<StrKind> {
Some(match tokens(self.0).next()?.kind() {
TokenKind::StrStart => StrKind::Plain,
TokenKind::MStrStart => StrKind::Multi,
TokenKind::RawStrStart => StrKind::Raw,
TokenKind::RawMStrStart => StrKind::RawMulti,
_ => return None,
})
}
pub fn parts(self) -> impl Iterator<Item = StrPart<'a>> {
self.0
.children_with_tokens()
.filter_map(|element| match element {
SyntaxElement::Token(token) => match token.kind() {
TokenKind::StrText => Some(StrPart::Text(token)),
TokenKind::StrEscape => Some(StrPart::Escape(token)),
_ => None,
},
SyntaxElement::Node(node) => Interp::cast(node).map(StrPart::Interp),
})
}
pub fn value(self) -> Option<String> {
let mut value = String::new();
for part in self.parts() {
match part {
StrPart::Text(token) => value.push_str(token.text()),
StrPart::Escape(token) => value.push(unescape(token.text())?),
StrPart::Interp(_) => return None,
}
}
Some(value)
}
}
pub(crate) fn unescape(escape: &str) -> Option<char> {
let rest = escape.strip_prefix('\\')?;
if let Some(hex) = rest.strip_prefix("u{") {
let digits = hex.strip_suffix('}')?;
if digits.is_empty() || digits.len() > 6 {
return None;
}
return u32::from_str_radix(digits, 16)
.ok()
.and_then(char::from_u32);
}
let mut chars = rest.chars();
let c = match chars.next()? {
'\\' => '\\',
'"' => '"',
'n' => '\n',
't' => '\t',
'r' => '\r',
'0' => '\0',
'#' => '#',
_ => return None,
};
chars.next().is_none().then_some(c)
}
node! {
Interp = Interp
}
impl<'a> Interp<'a> {
pub fn expr(self) -> Option<Expr<'a>> {
child(self.0)
}
}
node! {
Name = Name
}
impl<'a> Name<'a> {
pub fn token(self) -> Option<SyntaxToken<'a>> {
tokens(self.0).next()
}
}
node! {
Symbol = Symbol
}
impl<'a> Symbol<'a> {
pub fn token(self) -> Option<SyntaxToken<'a>> {
tokens(self.0).next()
}
pub fn name(self) -> &'a str {
let text = self.text();
text.find(['@', ':']).map_or(text, |end| &text[..end])
}
pub fn version(self) -> Option<&'a str> {
let text = self.text();
let start = text.find('@')? + 1;
let end = text[start..]
.find(':')
.map_or(text.len(), |end| start + end);
Some(&text[start..end])
}
pub fn variant(self) -> Option<&'a str> {
let text = self.text();
text.find(':').map(|colon| &text[colon + 1..])
}
fn text(self) -> &'a str {
self.token().map_or("", SyntaxToken::text)
}
}
node! {
SelfExpr = SelfExpr
}
node! {
List = List
}
impl<'a> List<'a> {
pub fn items(self) -> impl Iterator<Item = Expr<'a>> {
children(self.0)
}
}
node! {
ListComp = ListComp
}
impl<'a> ListComp<'a> {
pub fn names(self) -> impl Iterator<Item = SyntaxToken<'a>> {
loop_names(self.0)
}
pub fn source(self) -> Option<Expr<'a>> {
child_after(
self.0,
TokenKind::InKw,
&[TokenKind::IfKw, TokenKind::Arrow],
)
}
pub fn guard(self) -> Option<Expr<'a>> {
child_after(self.0, TokenKind::IfKw, &[TokenKind::Arrow])
}
pub fn value(self) -> Option<Expr<'a>> {
child_after(self.0, TokenKind::Arrow, &[])
}
}
node! {
Map = Map
}
impl<'a> Map<'a> {
pub fn entries(self) -> impl Iterator<Item = MapEntry<'a>> {
children(self.0)
}
}
node! {
MapEntry = MapEntry
}
impl<'a> MapEntry<'a> {
pub fn key(self) -> Option<Key<'a>> {
first_key(self.0.children_with_tokens())
}
pub fn value(self) -> Option<Expr<'a>> {
child_after(self.0, TokenKind::Eq, &[])
}
}
node! {
MapComp = MapComp
}
impl<'a> MapComp<'a> {
pub fn names(self) -> impl Iterator<Item = SyntaxToken<'a>> {
loop_names(self.0)
}
pub fn source(self) -> Option<Expr<'a>> {
child_after(
self.0,
TokenKind::InKw,
&[TokenKind::IfKw, TokenKind::Arrow],
)
}
pub fn guard(self) -> Option<Expr<'a>> {
child_after(self.0, TokenKind::IfKw, &[TokenKind::Arrow])
}
pub fn key(self) -> Option<Key<'a>> {
first_key(
self.0
.children_with_tokens()
.skip_while(|element| {
!matches!(element, SyntaxElement::Token(t) if t.kind() == TokenKind::Arrow)
})
.skip(1),
)
}
pub fn value(self) -> Option<Expr<'a>> {
child_after(self.0, TokenKind::Eq, &[])
}
}
node! {
StructLit = StructLit
}
impl<'a> StructLit<'a> {
pub fn type_path(self) -> Option<TypePath<'a>> {
child(self.0)
}
pub fn entries(self) -> impl Iterator<Item = MapEntry<'a>> {
child::<Map<'a>>(self.0).into_iter().flat_map(Map::entries)
}
}
node! {
Paren = Paren
}
impl<'a> Paren<'a> {
pub fn expr(self) -> Option<Expr<'a>> {
child(self.0)
}
}
node! {
Call = Call
}
impl<'a> Call<'a> {
pub fn callee(self) -> Option<Expr<'a>> {
child(self.0)
}
pub fn args(self) -> Option<ArgList<'a>> {
child(self.0)
}
}
node! {
ArgList = ArgList
}
impl<'a> ArgList<'a> {
pub fn args(self) -> impl Iterator<Item = Arg<'a>> {
children(self.0)
}
}
node! {
Arg = Arg
}
impl<'a> Arg<'a> {
pub fn name(self) -> Option<SyntaxToken<'a>> {
token(self.0, TokenKind::Eq).and_then(|_| names(self.0).next())
}
pub fn value(self) -> Option<Expr<'a>> {
child(self.0)
}
}
node! {
FieldExpr = FieldExpr
}
impl<'a> FieldExpr<'a> {
pub fn base(self) -> Option<Expr<'a>> {
child(self.0)
}
pub fn field(self) -> Option<SyntaxToken<'a>> {
names(self.0).next()
}
pub fn is_optional(self) -> bool {
token(self.0, TokenKind::QuestionDot).is_some()
}
}
node! {
IndexExpr = IndexExpr
}
impl<'a> IndexExpr<'a> {
pub fn base(self) -> Option<Expr<'a>> {
child(self.0)
}
pub fn index(self) -> Option<Expr<'a>> {
child_after(self.0, TokenKind::LBracket, &[])
}
}
node! {
BinaryExpr = BinaryExpr
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum BinaryOp {
Coalesce,
Or,
And,
Eq,
NotEq,
Lt,
LtEq,
Gt,
GtEq,
Add,
Sub,
Concat,
Mul,
Div,
Rem,
}
impl BinaryOp {
fn from_token(kind: TokenKind) -> Option<Self> {
Some(match kind {
TokenKind::QuestionQuestion => Self::Coalesce,
TokenKind::OrOr => Self::Or,
TokenKind::AndAnd => Self::And,
TokenKind::EqEq => Self::Eq,
TokenKind::NotEq => Self::NotEq,
TokenKind::Lt => Self::Lt,
TokenKind::LtEq => Self::LtEq,
TokenKind::Gt => Self::Gt,
TokenKind::GtEq => Self::GtEq,
TokenKind::Plus => Self::Add,
TokenKind::Minus => Self::Sub,
TokenKind::PlusPlus => Self::Concat,
TokenKind::Star => Self::Mul,
TokenKind::Slash => Self::Div,
TokenKind::Percent => Self::Rem,
_ => return None,
})
}
}
impl<'a> BinaryExpr<'a> {
pub fn lhs(self) -> Option<Expr<'a>> {
child(self.0)
}
pub fn op_token(self) -> Option<SyntaxToken<'a>> {
tokens(self.0).find(|token| BinaryOp::from_token(token.kind()).is_some())
}
pub fn op(self) -> Option<BinaryOp> {
BinaryOp::from_token(self.op_token()?.kind())
}
pub fn rhs(self) -> Option<Expr<'a>> {
let op = self.op_token()?.kind();
child_after(self.0, op, &[])
}
}
node! {
UnaryExpr = UnaryExpr
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum UnaryOp {
Not,
Neg,
}
impl<'a> UnaryExpr<'a> {
pub fn op(self) -> Option<UnaryOp> {
match tokens(self.0).next()?.kind() {
TokenKind::Bang => Some(UnaryOp::Not),
TokenKind::Minus => Some(UnaryOp::Neg),
_ => None,
}
}
pub fn operand(self) -> Option<Expr<'a>> {
child(self.0)
}
}
node! {
IfExpr = IfExpr
}
impl<'a> IfExpr<'a> {
pub fn condition(self) -> Option<Expr<'a>> {
child_after(self.0, TokenKind::IfKw, &[TokenKind::LBrace])
}
pub fn then_branch(self) -> Option<Expr<'a>> {
child_after(self.0, TokenKind::LBrace, &[TokenKind::RBrace])
}
pub fn else_branch(self) -> Option<Expr<'a>> {
child_after(self.0, TokenKind::ElseKw, &[])
}
}
node! {
MatchExpr = MatchExpr
}
impl<'a> MatchExpr<'a> {
pub fn scrutinee(self) -> Option<Expr<'a>> {
child_after(self.0, TokenKind::MatchKw, &[TokenKind::LBrace])
}
pub fn arms(self) -> impl Iterator<Item = MatchArm<'a>> {
children(self.0)
}
}
node! {
MatchArm = MatchArm
}
impl<'a> MatchArm<'a> {
pub fn pattern(self) -> Option<Pattern<'a>> {
child(self.0)
}
pub fn guard(self) -> Option<Expr<'a>> {
child_after(self.0, TokenKind::IfKw, &[TokenKind::FatArrow])
}
pub fn value(self) -> Option<Expr<'a>> {
child_after(self.0, TokenKind::FatArrow, &[])
}
}
node! {
LetExpr = LetExpr
}
impl<'a> LetExpr<'a> {
pub fn bindings(self) -> impl Iterator<Item = Binding<'a>> {
children(self.0)
}
pub fn body(self) -> Option<Expr<'a>> {
child_after(self.0, TokenKind::InKw, &[])
}
}
node! {
Binding = Binding
}
impl<'a> Binding<'a> {
pub fn name(self) -> Option<SyntaxToken<'a>> {
binding_name(self.0)
}
pub fn ty(self) -> Option<Type<'a>> {
child(self.0)
}
pub fn value(self) -> Option<Expr<'a>> {
child_after(self.0, TokenKind::Eq, &[])
}
}
node! {
Lambda = Lambda
}
impl<'a> Lambda<'a> {
pub fn params(self) -> Option<ParamList<'a>> {
child(self.0)
}
pub fn return_type(self) -> Option<Type<'a>> {
child_after(self.0, TokenKind::Arrow, &[])
}
pub fn body(self) -> Option<Expr<'a>> {
child_after(self.0, TokenKind::Eq, &[])
}
}
node! {
PartExpr = PartExpr
}
impl<'a> PartExpr<'a> {
pub fn body(self) -> Option<Body<'a>> {
child(self.0)
}
}
choice! {
Type {
Named(NamedType),
Fn(FnType),
Refined(RefinedType),
}
}
node! {
TypePath = TypePath
}
impl<'a> TypePath<'a> {
pub fn segments(self) -> impl Iterator<Item = SyntaxToken<'a>> {
names(self.0)
}
pub fn name(self) -> Option<SyntaxToken<'a>> {
self.segments().last()
}
}
node! {
NamedType = NamedType
}
impl<'a> NamedType<'a> {
pub fn path(self) -> Option<TypePath<'a>> {
child(self.0)
}
pub fn args(self) -> impl Iterator<Item = Type<'a>> {
self.0
.children()
.find(|node| node.kind() == NodeKind::TypeArgList)
.into_iter()
.flat_map(children)
}
}
node! {
FnType = FnType
}
impl<'a> FnType<'a> {
pub fn params(self) -> impl Iterator<Item = Type<'a>> {
self.0
.children_with_tokens()
.take_while(|element| {
!matches!(element, SyntaxElement::Token(t) if t.kind() == TokenKind::Arrow)
})
.filter_map(|element| match element {
SyntaxElement::Node(node) => Type::cast(node),
SyntaxElement::Token(_) => None,
})
}
pub fn return_type(self) -> Option<Type<'a>> {
child_after(self.0, TokenKind::Arrow, &[])
}
}
node! {
RefinedType = RefinedType
}
impl<'a> RefinedType<'a> {
pub fn base(self) -> Option<Type<'a>> {
child(self.0)
}
pub fn predicates(self) -> impl Iterator<Item = Predicate<'a>> {
children(self.0)
}
}
choice! {
Predicate {
Range(RangePredicate),
Named(NamedPredicate),
}
}
node! {
RangePredicate = RangePredicate
}
impl<'a> RangePredicate<'a> {
pub fn start(self) -> Option<Expr<'a>> {
self.0
.children_with_tokens()
.take_while(|element| !matches!(element, SyntaxElement::Token(t) if is_range_op(t)))
.find_map(|element| match element {
SyntaxElement::Node(node) => Expr::cast(node),
SyntaxElement::Token(_) => None,
})
}
pub fn end(self) -> Option<Expr<'a>> {
self.0
.children_with_tokens()
.skip_while(|element| !matches!(element, SyntaxElement::Token(t) if is_range_op(t)))
.find_map(|element| match element {
SyntaxElement::Node(node) => Expr::cast(node),
SyntaxElement::Token(_) => None,
})
}
pub fn is_inclusive(self) -> bool {
token(self.0, TokenKind::DotDotEq).is_some()
}
}
fn is_range_op(token: &SyntaxToken<'_>) -> bool {
matches!(token.kind(), TokenKind::DotDot | TokenKind::DotDotEq)
}
node! {
NamedPredicate = NamedPredicate
}
impl<'a> NamedPredicate<'a> {
pub fn segments(self) -> impl Iterator<Item = SyntaxToken<'a>> {
names(self.0)
}
pub fn args(self) -> Option<ArgList<'a>> {
child(self.0)
}
}
choice! {
Pattern {
Wildcard(WildcardPat),
Literal(LiteralPat),
Name(NamePat),
Variant(VariantPat),
Or(OrPat),
}
}
node! {
WildcardPat = WildcardPat
}
node! {
LiteralPat = LiteralPat
}
impl<'a> LiteralPat<'a> {
pub fn expr(self) -> Option<Expr<'a>> {
child(self.0)
}
}
node! {
NamePat = NamePat
}
impl<'a> NamePat<'a> {
pub fn segments(self) -> impl Iterator<Item = SyntaxToken<'a>> {
names(self.0)
}
}
node! {
VariantPat = VariantPat
}
impl<'a> VariantPat<'a> {
pub fn segments(self) -> impl Iterator<Item = SyntaxToken<'a>> {
names(self.0)
}
pub fn fields(self) -> impl Iterator<Item = FieldPat<'a>> {
children(self.0)
}
pub fn has_rest(self) -> bool {
token(self.0, TokenKind::DotDot).is_some()
}
}
node! {
FieldPat = FieldPat
}
impl<'a> FieldPat<'a> {
pub fn name(self) -> Option<SyntaxToken<'a>> {
names(self.0).next()
}
pub fn pattern(self) -> Option<Pattern<'a>> {
child(self.0)
}
}
node! {
OrPat = OrPat
}
impl<'a> OrPat<'a> {
pub fn alternatives(self) -> impl Iterator<Item = Pattern<'a>> {
children(self.0)
}
}
#[cfg(test)]
#[path = "ast_tests.rs"]
mod tests;