use crate::SyntaxKind::{
self, AMP, AMP_AMP, BANG, BANG_EQ, BANG_QUESTION, CARET, COLON, DIVERT, DOLLAR, EQ, EQ_EQ,
FLOAT, GT, GT_EQ, HASH, IDENT, INTEGER, KW_AND, KW_CYCLE, KW_DONE, KW_ELSE, KW_END, KW_FALSE,
KW_FUNCTION, KW_HAS, KW_HASNT, KW_MOD, KW_NOT, KW_ONCE, KW_OR, KW_REF, KW_SHUFFLE, KW_STOPPING,
KW_TODO, KW_TRUE, LT, LT_EQ, MINUS, MINUS_EQ, NEWLINE, PERCENT, PIPE, PLUS, PLUS_EQ, QUESTION,
SLASH, STAR, TILDE,
};
use crate::ast::AstNode as _;
use crate::ast::ast_node;
use crate::ast::support;
use crate::{SyntaxNode, SyntaxToken};
ast_node!(SourceFile, SOURCE_FILE);
ast_node!(IncludeStmt, INCLUDE_STMT);
ast_node!(FilePath, FILE_PATH);
ast_node!(ExternalDecl, EXTERNAL_DECL);
ast_node!(KnotDef, KNOT_DEF);
ast_node!(KnotHeader, KNOT_HEADER);
ast_node!(KnotBody, KNOT_BODY);
ast_node!(KnotParams, KNOT_PARAMS);
ast_node!(KnotParamDecl, KNOT_PARAM_DECL);
ast_node!(StitchDef, STITCH_DEF);
ast_node!(StitchHeader, STITCH_HEADER);
ast_node!(StitchBody, STITCH_BODY);
ast_node!(EmptyLine, EMPTY_LINE);
ast_node!(AuthorWarning, AUTHOR_WARNING);
ast_node!(LogicLine, LOGIC_LINE);
ast_node!(ContentLine, CONTENT_LINE);
ast_node!(TagLine, TAG_LINE);
ast_node!(StrayClosingBrace, STRAY_CLOSING_BRACE);
ast_node!(ReturnStmt, RETURN_STMT);
ast_node!(TempDecl, TEMP_DECL);
ast_node!(Assignment, ASSIGNMENT);
ast_node!(MixedContent, MIXED_CONTENT);
ast_node!(Text, TEXT);
ast_node!(Escape, ESCAPE);
ast_node!(GlueNode, GLUE_NODE);
ast_node!(Choice, CHOICE);
ast_node!(ChoiceBullets, CHOICE_BULLETS);
ast_node!(Label, LABEL);
ast_node!(ChoiceCondition, CHOICE_CONDITION);
ast_node!(ChoiceStartContent, CHOICE_START_CONTENT);
ast_node!(ChoiceBracketContent, CHOICE_BRACKET_CONTENT);
ast_node!(ChoiceInnerContent, CHOICE_INNER_CONTENT);
ast_node!(Gather, GATHER);
ast_node!(GatherDashes, GATHER_DASHES);
ast_node!(Tags, TAGS);
ast_node!(Tag, TAG);
ast_node!(InlineLogic, INLINE_LOGIC);
ast_node!(MultilineBlock, MULTILINE_BLOCK);
ast_node!(SequenceWithAnnotation, SEQUENCE_WITH_ANNOTATION);
ast_node!(SequenceSymbolAnnotation, SEQUENCE_SYMBOL_ANNOTATION);
ast_node!(SequenceWordAnnotation, SEQUENCE_WORD_ANNOTATION);
ast_node!(InlineBranchesSeq, INLINE_BRANCHES_SEQ);
ast_node!(MultilineBranchesSeq, MULTILINE_BRANCHES_SEQ);
ast_node!(MultilineBranchSeq, MULTILINE_BRANCH_SEQ);
ast_node!(BranchContent, BRANCH_CONTENT);
ast_node!(ConditionalWithExpr, CONDITIONAL_WITH_EXPR);
ast_node!(BranchlessCondBody, BRANCHLESS_COND_BODY);
ast_node!(ElseBranch, ELSE_BRANCH);
ast_node!(InlineBranchesCond, INLINE_BRANCHES_COND);
ast_node!(MultilineBranchesCond, MULTILINE_BRANCHES_COND);
ast_node!(MultilineConditional, MULTILINE_CONDITIONAL);
ast_node!(MultilineBranchCond, MULTILINE_BRANCH_COND);
ast_node!(MultilineBranchBody, MULTILINE_BRANCH_BODY);
ast_node!(ImplicitSequence, IMPLICIT_SEQUENCE);
ast_node!(InnerExpression, INNER_EXPRESSION);
ast_node!(PrefixExpr, PREFIX_EXPR);
ast_node!(PostfixExpr, POSTFIX_EXPR);
ast_node!(InfixExpr, INFIX_EXPR);
ast_node!(ParenExpr, PAREN_EXPR);
ast_node!(FunctionCall, FUNCTION_CALL);
ast_node!(ArgList, ARG_LIST);
ast_node!(DivertTargetExpr, DIVERT_TARGET_EXPR);
ast_node!(ListExpr, LIST_EXPR);
ast_node!(DivertNode, DIVERT_NODE);
ast_node!(SimpleDivert, SIMPLE_DIVERT);
ast_node!(DivertTargetWithArgs, DIVERT_TARGET_WITH_ARGS);
ast_node!(ThreadStart, THREAD_START);
ast_node!(TunnelOnwardsNode, TUNNEL_ONWARDS_NODE);
ast_node!(TunnelCallNode, TUNNEL_CALL_NODE);
ast_node!(Identifier, IDENTIFIER);
ast_node!(Path, PATH);
ast_node!(VarDecl, VAR_DECL);
ast_node!(ConstDecl, CONST_DECL);
ast_node!(ListDecl, LIST_DECL);
ast_node!(ListDef, LIST_DEF);
ast_node!(ListMember, LIST_MEMBER);
ast_node!(ListMemberOn, LIST_MEMBER_ON);
ast_node!(ListMemberOff, LIST_MEMBER_OFF);
ast_node!(FunctionParamList, FUNCTION_PARAM_LIST);
ast_node!(IntegerLit, INTEGER_LIT);
ast_node!(FloatLit, FLOAT_LIT);
ast_node!(StringLit, STRING_LIT);
ast_node!(BooleanLit, BOOLEAN_LIT);
ast_node!(Error, ERROR);
#[derive(Clone, PartialEq, Eq, Hash)]
pub enum Expr {
Prefix(PrefixExpr),
Postfix(PostfixExpr),
Infix(InfixExpr),
Paren(ParenExpr),
FunctionCall(FunctionCall),
IntegerLit(IntegerLit),
FloatLit(FloatLit),
StringLit(StringLit),
BooleanLit(BooleanLit),
Path(Path),
ListExpr(ListExpr),
DivertTarget(DivertTargetExpr),
}
impl std::fmt::Debug for Expr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(self.syntax(), f)
}
}
impl std::fmt::Display for Expr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&self.syntax().text(), f)
}
}
impl crate::ast::AstNode for Expr {
fn can_cast(kind: SyntaxKind) -> bool {
matches!(
kind,
SyntaxKind::PREFIX_EXPR
| SyntaxKind::POSTFIX_EXPR
| SyntaxKind::INFIX_EXPR
| SyntaxKind::PAREN_EXPR
| SyntaxKind::FUNCTION_CALL
| SyntaxKind::INTEGER_LIT
| SyntaxKind::FLOAT_LIT
| SyntaxKind::STRING_LIT
| SyntaxKind::BOOLEAN_LIT
| SyntaxKind::PATH
| SyntaxKind::LIST_EXPR
| SyntaxKind::DIVERT_TARGET_EXPR
)
}
fn cast(node: SyntaxNode) -> Option<Self> {
match node.kind() {
SyntaxKind::PREFIX_EXPR => PrefixExpr::cast(node).map(Expr::Prefix),
SyntaxKind::POSTFIX_EXPR => PostfixExpr::cast(node).map(Expr::Postfix),
SyntaxKind::INFIX_EXPR => InfixExpr::cast(node).map(Expr::Infix),
SyntaxKind::PAREN_EXPR => ParenExpr::cast(node).map(Expr::Paren),
SyntaxKind::FUNCTION_CALL => FunctionCall::cast(node).map(Expr::FunctionCall),
SyntaxKind::INTEGER_LIT => IntegerLit::cast(node).map(Expr::IntegerLit),
SyntaxKind::FLOAT_LIT => FloatLit::cast(node).map(Expr::FloatLit),
SyntaxKind::STRING_LIT => StringLit::cast(node).map(Expr::StringLit),
SyntaxKind::BOOLEAN_LIT => BooleanLit::cast(node).map(Expr::BooleanLit),
SyntaxKind::PATH => Path::cast(node).map(Expr::Path),
SyntaxKind::LIST_EXPR => ListExpr::cast(node).map(Expr::ListExpr),
SyntaxKind::DIVERT_TARGET_EXPR => DivertTargetExpr::cast(node).map(Expr::DivertTarget),
_ => None,
}
}
fn syntax(&self) -> &SyntaxNode {
match self {
Expr::Prefix(n) => n.syntax(),
Expr::Postfix(n) => n.syntax(),
Expr::Infix(n) => n.syntax(),
Expr::Paren(n) => n.syntax(),
Expr::FunctionCall(n) => n.syntax(),
Expr::IntegerLit(n) => n.syntax(),
Expr::FloatLit(n) => n.syntax(),
Expr::StringLit(n) => n.syntax(),
Expr::BooleanLit(n) => n.syntax(),
Expr::Path(n) => n.syntax(),
Expr::ListExpr(n) => n.syntax(),
Expr::DivertTarget(n) => n.syntax(),
}
}
}
macro_rules! content_node_accessors {
($name:ident) => {
impl $name {
pub fn texts(&self) -> impl Iterator<Item = Text> {
support::children(&self.syntax)
}
pub fn inline_logics(&self) -> impl Iterator<Item = InlineLogic> {
support::children(&self.syntax)
}
pub fn glue_nodes(&self) -> impl Iterator<Item = GlueNode> {
support::children(&self.syntax)
}
pub fn escapes(&self) -> impl Iterator<Item = Escape> {
support::children(&self.syntax)
}
}
};
}
content_node_accessors!(ChoiceStartContent);
content_node_accessors!(ChoiceBracketContent);
content_node_accessors!(ChoiceInnerContent);
content_node_accessors!(BranchContent);
impl SourceFile {
pub fn knots(&self) -> impl Iterator<Item = KnotDef> {
support::children(&self.syntax)
}
pub fn includes(&self) -> impl Iterator<Item = IncludeStmt> {
support::children(&self.syntax)
}
pub fn externals(&self) -> impl Iterator<Item = ExternalDecl> {
support::children(&self.syntax)
}
pub fn stitches(&self) -> impl Iterator<Item = StitchDef> {
support::children(&self.syntax)
}
pub fn var_decls(&self) -> impl Iterator<Item = VarDecl> {
support::children(&self.syntax)
}
pub fn const_decls(&self) -> impl Iterator<Item = ConstDecl> {
support::children(&self.syntax)
}
pub fn list_decls(&self) -> impl Iterator<Item = ListDecl> {
support::children(&self.syntax)
}
pub fn content_lines(&self) -> impl Iterator<Item = ContentLine> {
support::children(&self.syntax)
}
pub fn logic_lines(&self) -> impl Iterator<Item = LogicLine> {
support::children(&self.syntax)
}
pub fn choices(&self) -> impl Iterator<Item = Choice> {
support::children(&self.syntax)
}
pub fn gathers(&self) -> impl Iterator<Item = Gather> {
support::children(&self.syntax)
}
}
impl IncludeStmt {
pub fn file_path(&self) -> Option<FilePath> {
support::child(&self.syntax)
}
}
impl FilePath {
pub fn text(&self) -> String {
self.syntax.text().to_string()
}
}
impl ExternalDecl {
pub fn identifier(&self) -> Option<Identifier> {
support::child(&self.syntax)
}
pub fn name(&self) -> Option<String> {
self.identifier().and_then(|id| id.name())
}
pub fn param_list(&self) -> Option<FunctionParamList> {
support::child(&self.syntax)
}
}
impl KnotDef {
pub fn header(&self) -> Option<KnotHeader> {
support::child(&self.syntax)
}
pub fn body(&self) -> Option<KnotBody> {
support::child(&self.syntax)
}
}
impl KnotHeader {
pub fn function_kw(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, KW_FUNCTION)
}
pub fn is_function(&self) -> bool {
self.function_kw().is_some()
}
pub fn identifier(&self) -> Option<Identifier> {
support::child(&self.syntax)
}
pub fn name(&self) -> Option<String> {
self.identifier().and_then(|id| id.name())
}
pub fn params(&self) -> Option<KnotParams> {
support::child(&self.syntax)
}
}
impl KnotBody {
pub fn stitches(&self) -> impl Iterator<Item = StitchDef> {
support::children(&self.syntax)
}
pub fn content_lines(&self) -> impl Iterator<Item = ContentLine> {
support::children(&self.syntax)
}
pub fn logic_lines(&self) -> impl Iterator<Item = LogicLine> {
support::children(&self.syntax)
}
pub fn choices(&self) -> impl Iterator<Item = Choice> {
support::children(&self.syntax)
}
pub fn gathers(&self) -> impl Iterator<Item = Gather> {
support::children(&self.syntax)
}
}
impl KnotParams {
pub fn params(&self) -> impl Iterator<Item = KnotParamDecl> {
support::children(&self.syntax)
}
}
impl KnotParamDecl {
pub fn divert_token(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, DIVERT)
}
pub fn is_divert(&self) -> bool {
self.divert_token().is_some()
}
pub fn ref_kw(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, KW_REF)
}
pub fn is_ref(&self) -> bool {
self.ref_kw().is_some()
}
pub fn identifier(&self) -> Option<Identifier> {
support::child(&self.syntax)
}
pub fn name(&self) -> Option<String> {
self.identifier().and_then(|id| id.name())
}
}
impl StitchDef {
pub fn header(&self) -> Option<StitchHeader> {
support::child(&self.syntax)
}
pub fn body(&self) -> Option<StitchBody> {
support::child(&self.syntax)
}
}
impl StitchHeader {
pub fn identifier(&self) -> Option<Identifier> {
support::child(&self.syntax)
}
pub fn name(&self) -> Option<String> {
self.identifier().and_then(|id| id.name())
}
pub fn params(&self) -> Option<KnotParams> {
support::child(&self.syntax)
}
}
impl StitchBody {
pub fn content_lines(&self) -> impl Iterator<Item = ContentLine> {
support::children(&self.syntax)
}
pub fn logic_lines(&self) -> impl Iterator<Item = LogicLine> {
support::children(&self.syntax)
}
pub fn choices(&self) -> impl Iterator<Item = Choice> {
support::children(&self.syntax)
}
pub fn gathers(&self) -> impl Iterator<Item = Gather> {
support::children(&self.syntax)
}
}
impl ContentLine {
pub fn mixed_content(&self) -> Option<MixedContent> {
support::child(&self.syntax)
}
pub fn divert(&self) -> Option<DivertNode> {
support::child(&self.syntax)
}
pub fn tags(&self) -> Option<Tags> {
support::child(&self.syntax)
}
}
impl LogicLine {
pub fn return_stmt(&self) -> Option<ReturnStmt> {
support::child(&self.syntax)
}
pub fn temp_decl(&self) -> Option<TempDecl> {
support::child(&self.syntax)
}
pub fn assignment(&self) -> Option<Assignment> {
support::child(&self.syntax)
}
}
impl TagLine {
pub fn tags(&self) -> Option<Tags> {
support::child(&self.syntax)
}
}
impl ReturnStmt {
pub fn value(&self) -> Option<Expr> {
support::child(&self.syntax)
}
pub fn has_value(&self) -> bool {
self.value().is_some()
}
}
impl TempDecl {
pub fn identifier(&self) -> Option<Identifier> {
support::child(&self.syntax)
}
pub fn name(&self) -> Option<String> {
self.identifier().and_then(|id| id.name())
}
pub fn eq_token(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, EQ)
}
pub fn value(&self) -> Option<Expr> {
support::child(&self.syntax)
}
}
impl Assignment {
pub fn target(&self) -> Option<Expr> {
self.syntax.children().find_map(Expr::cast)
}
pub fn op_token(&self) -> Option<SyntaxToken> {
self.syntax
.children_with_tokens()
.filter_map(rowan::NodeOrToken::into_token)
.find(|tok| matches!(tok.kind(), EQ | PLUS_EQ | MINUS_EQ))
}
pub fn value(&self) -> Option<Expr> {
self.syntax.children().filter_map(Expr::cast).nth(1)
}
}
impl MixedContent {
pub fn texts(&self) -> impl Iterator<Item = Text> {
support::children(&self.syntax)
}
pub fn glue_nodes(&self) -> impl Iterator<Item = GlueNode> {
support::children(&self.syntax)
}
pub fn inline_logics(&self) -> impl Iterator<Item = InlineLogic> {
support::children(&self.syntax)
}
pub fn escapes(&self) -> impl Iterator<Item = Escape> {
support::children(&self.syntax)
}
}
impl Choice {
pub fn bullets(&self) -> Option<ChoiceBullets> {
support::child(&self.syntax)
}
pub fn label(&self) -> Option<Label> {
support::child(&self.syntax)
}
pub fn conditions(&self) -> impl Iterator<Item = ChoiceCondition> {
support::children(&self.syntax)
}
pub fn start_content(&self) -> Option<ChoiceStartContent> {
support::child(&self.syntax)
}
pub fn bracket_content(&self) -> Option<ChoiceBracketContent> {
support::child(&self.syntax)
}
pub fn inner_content(&self) -> Option<ChoiceInnerContent> {
support::child(&self.syntax)
}
pub fn divert(&self) -> Option<DivertNode> {
support::child(&self.syntax)
}
pub fn tags(&self) -> Option<Tags> {
support::child(&self.syntax)
}
pub fn all_tags(&self) -> impl Iterator<Item = Tags> {
support::children(&self.syntax)
}
}
impl ChoiceBullets {
pub fn depth(&self) -> usize {
self.syntax
.children_with_tokens()
.filter_map(rowan::NodeOrToken::into_token)
.filter(|tok| matches!(tok.kind(), STAR | PLUS))
.count()
}
pub fn is_sticky(&self) -> bool {
self.syntax
.children_with_tokens()
.filter_map(rowan::NodeOrToken::into_token)
.find(|tok| matches!(tok.kind(), STAR | PLUS))
.is_some_and(|tok| tok.kind() == PLUS)
}
pub fn is_mixed(&self) -> bool {
let mut has_star = false;
let mut has_plus = false;
for tok in self
.syntax
.children_with_tokens()
.filter_map(rowan::NodeOrToken::into_token)
{
match tok.kind() {
STAR => has_star = true,
PLUS => has_plus = true,
_ => {}
}
}
has_star && has_plus
}
}
impl Label {
pub fn identifier(&self) -> Option<Identifier> {
support::child(&self.syntax)
}
pub fn name(&self) -> Option<String> {
self.identifier().and_then(|id| id.name())
}
}
impl Gather {
pub fn dashes(&self) -> Option<GatherDashes> {
support::child(&self.syntax)
}
pub fn label(&self) -> Option<Label> {
support::child(&self.syntax)
}
pub fn mixed_content(&self) -> Option<MixedContent> {
support::child(&self.syntax)
}
pub fn choice(&self) -> Option<Choice> {
support::child(&self.syntax)
}
pub fn divert(&self) -> Option<DivertNode> {
support::child(&self.syntax)
}
pub fn tags(&self) -> Option<Tags> {
support::child(&self.syntax)
}
}
impl GatherDashes {
pub fn depth(&self) -> usize {
support::tokens(&self.syntax, MINUS).count()
}
}
impl Tags {
pub fn tags(&self) -> impl Iterator<Item = Tag> {
support::children(&self.syntax)
}
}
impl Tag {
pub fn text(&self) -> String {
self.syntax
.children_with_tokens()
.filter_map(rowan::NodeOrToken::into_token)
.filter(|tok| tok.kind() != HASH)
.map(|tok| tok.text().to_string())
.collect::<String>()
.trim()
.to_string()
}
}
impl InlineLogic {
pub fn inner_expression(&self) -> Option<InnerExpression> {
support::child(&self.syntax)
}
pub fn conditional(&self) -> Option<ConditionalWithExpr> {
support::child(&self.syntax)
}
pub fn sequence(&self) -> Option<SequenceWithAnnotation> {
support::child(&self.syntax)
}
pub fn implicit_sequence(&self) -> Option<ImplicitSequence> {
support::child(&self.syntax)
}
pub fn multiline_conditional(&self) -> Option<MultilineConditional> {
support::child(&self.syntax)
}
}
impl MultilineBlock {
pub fn conditional(&self) -> Option<ConditionalWithExpr> {
support::child(&self.syntax)
}
pub fn sequence(&self) -> Option<SequenceWithAnnotation> {
support::child(&self.syntax)
}
pub fn branches_cond(&self) -> Option<MultilineBranchesCond> {
support::child(&self.syntax)
}
}
impl SequenceWithAnnotation {
pub fn symbol_annotation(&self) -> Option<SequenceSymbolAnnotation> {
support::child(&self.syntax)
}
pub fn word_annotation(&self) -> Option<SequenceWordAnnotation> {
support::child(&self.syntax)
}
pub fn inline_branches(&self) -> Option<InlineBranchesSeq> {
support::child(&self.syntax)
}
pub fn multiline_branches(&self) -> Option<MultilineBranchesSeq> {
support::child(&self.syntax)
}
}
impl SequenceSymbolAnnotation {
pub fn amp_token(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, AMP)
}
pub fn bang_token(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, BANG)
}
pub fn tilde_token(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, TILDE)
}
pub fn dollar_token(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, DOLLAR)
}
}
impl SequenceWordAnnotation {
pub fn stopping_kw(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, KW_STOPPING)
}
pub fn cycle_kw(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, KW_CYCLE)
}
pub fn shuffle_kw(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, KW_SHUFFLE)
}
pub fn once_kw(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, KW_ONCE)
}
}
impl InlineBranchesSeq {
pub fn branches(&self) -> impl Iterator<Item = BranchContent> {
support::children(&self.syntax)
}
}
impl InlineBranchesCond {
pub fn branches(&self) -> impl Iterator<Item = BranchContent> {
support::children(&self.syntax)
}
}
impl MultilineBranchesSeq {
pub fn branches(&self) -> impl Iterator<Item = MultilineBranchSeq> {
support::children(&self.syntax)
}
}
impl MultilineBranchesCond {
pub fn branches(&self) -> impl Iterator<Item = MultilineBranchCond> {
support::children(&self.syntax)
}
}
impl MultilineBranchSeq {
pub fn body(&self) -> Option<MultilineBranchBody> {
support::child(&self.syntax)
}
}
impl MultilineBranchCond {
pub fn condition(&self) -> Option<Expr> {
support::child(&self.syntax)
}
pub fn body(&self) -> Option<MultilineBranchBody> {
support::child(&self.syntax)
}
pub fn else_kw(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, KW_ELSE)
}
pub fn is_else(&self) -> bool {
self.else_kw().is_some()
}
}
impl ConditionalWithExpr {
pub fn condition(&self) -> Option<Expr> {
support::child(&self.syntax)
}
pub fn inline_branches(&self) -> Option<InlineBranchesCond> {
support::child(&self.syntax)
}
pub fn multiline_branches(&self) -> Option<MultilineBranchesCond> {
support::child(&self.syntax)
}
pub fn branchless_body(&self) -> Option<BranchlessCondBody> {
support::child(&self.syntax)
}
}
impl BranchlessCondBody {
pub fn texts(&self) -> impl Iterator<Item = Text> {
support::children(&self.syntax)
}
pub fn inline_logics(&self) -> impl Iterator<Item = InlineLogic> {
support::children(&self.syntax)
}
pub fn glue_nodes(&self) -> impl Iterator<Item = GlueNode> {
support::children(&self.syntax)
}
pub fn escapes(&self) -> impl Iterator<Item = Escape> {
support::children(&self.syntax)
}
pub fn logic_lines(&self) -> impl Iterator<Item = LogicLine> {
support::children(&self.syntax)
}
pub fn divert(&self) -> Option<DivertNode> {
support::child(&self.syntax)
}
pub fn content_lines(&self) -> impl Iterator<Item = ContentLine> {
support::children(&self.syntax)
}
pub fn else_branch(&self) -> Option<ElseBranch> {
support::child(&self.syntax)
}
}
impl ElseBranch {
pub fn branch(&self) -> Option<MultilineBranchCond> {
support::child(&self.syntax)
}
}
impl MultilineConditional {
pub fn branches(&self) -> impl Iterator<Item = MultilineBranchCond> {
support::children(&self.syntax)
}
}
impl ImplicitSequence {
pub fn branches(&self) -> impl Iterator<Item = BranchContent> {
support::children(&self.syntax)
}
}
impl PrefixExpr {
pub fn op_token(&self) -> Option<SyntaxToken> {
self.syntax
.children_with_tokens()
.filter_map(rowan::NodeOrToken::into_token)
.find(|tok| matches!(tok.kind(), MINUS | BANG | KW_NOT))
}
pub fn operand(&self) -> Option<Expr> {
support::child(&self.syntax)
}
}
impl PostfixExpr {
pub fn op_token(&self) -> Option<SyntaxToken> {
self.syntax
.children_with_tokens()
.filter_map(rowan::NodeOrToken::into_token)
.find(|tok| matches!(tok.kind(), PLUS | MINUS))
}
pub fn operand(&self) -> Option<Expr> {
support::child(&self.syntax)
}
}
impl InfixExpr {
pub fn op_token(&self) -> Option<SyntaxToken> {
self.syntax
.children_with_tokens()
.filter_map(rowan::NodeOrToken::into_token)
.find(|tok| {
matches!(
tok.kind(),
PLUS | MINUS
| STAR
| SLASH
| PERCENT
| CARET
| EQ_EQ
| BANG_EQ
| LT
| GT
| LT_EQ
| GT_EQ
| KW_AND
| AMP_AMP
| KW_OR
| PIPE
| KW_MOD
| KW_HAS
| KW_HASNT
| QUESTION
| BANG_QUESTION
| PLUS_EQ
| MINUS_EQ
)
})
}
pub fn lhs(&self) -> Option<Expr> {
self.syntax.children().find_map(Expr::cast)
}
pub fn rhs(&self) -> Option<Expr> {
self.syntax.children().filter_map(Expr::cast).nth(1)
}
}
impl FunctionCall {
pub fn identifier(&self) -> Option<Identifier> {
support::child(&self.syntax)
}
pub fn name(&self) -> Option<String> {
self.identifier().and_then(|id| id.name())
}
pub fn arg_list(&self) -> Option<ArgList> {
support::child(&self.syntax)
}
}
impl ArgList {
pub fn arg_count(&self) -> usize {
self.syntax
.children()
.filter(|child| child.kind() != SyntaxKind::ERROR)
.count()
}
pub fn args(&self) -> impl Iterator<Item = Expr> {
support::children(&self.syntax)
}
}
impl DivertTargetExpr {
pub fn target(&self) -> Option<Path> {
support::child(&self.syntax)
}
}
impl ListExpr {
pub fn items(&self) -> impl Iterator<Item = Path> {
support::children(&self.syntax)
}
}
impl DivertNode {
pub fn thread_start(&self) -> Option<ThreadStart> {
support::child(&self.syntax)
}
pub fn tunnel_onwards(&self) -> Option<TunnelOnwardsNode> {
support::child(&self.syntax)
}
pub fn tunnel_call(&self) -> Option<TunnelCallNode> {
support::child(&self.syntax)
}
pub fn simple_divert(&self) -> Option<SimpleDivert> {
support::child(&self.syntax)
}
}
impl SimpleDivert {
pub fn targets(&self) -> impl Iterator<Item = DivertTargetWithArgs> {
support::children(&self.syntax)
}
}
impl DivertTargetWithArgs {
pub fn path(&self) -> Option<Path> {
support::child(&self.syntax)
}
pub fn done_kw(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, KW_DONE)
}
pub fn end_kw(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, KW_END)
}
pub fn arg_list(&self) -> Option<ArgList> {
support::child(&self.syntax)
}
}
impl ThreadStart {
pub fn target(&self) -> Option<Path> {
support::child(&self.syntax)
}
pub fn arg_list(&self) -> Option<ArgList> {
support::child(&self.syntax)
}
}
impl TunnelOnwardsNode {
pub fn targets(&self) -> impl Iterator<Item = DivertTargetWithArgs> {
support::children(&self.syntax)
}
pub fn tunnel_call(&self) -> Option<TunnelCallNode> {
support::child(&self.syntax)
}
}
impl TunnelCallNode {
pub fn targets(&self) -> impl Iterator<Item = DivertTargetWithArgs> {
support::children(&self.syntax)
}
}
impl Identifier {
pub fn ident_token(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, IDENT)
}
pub fn name(&self) -> Option<String> {
self.ident_token()
.or_else(|| {
self.syntax
.children_with_tokens()
.filter_map(rowan::NodeOrToken::into_token)
.find(|t| t.kind().is_keyword())
})
.map(|t| t.text().to_string())
}
}
impl Path {
pub fn segments(&self) -> impl Iterator<Item = SyntaxToken> {
self.syntax
.children_with_tokens()
.filter_map(rowan::NodeOrToken::into_token)
.filter(|t| t.kind() == IDENT || t.kind().is_keyword())
}
pub fn full_name(&self) -> String {
self.segments()
.map(|t| t.text().to_string())
.collect::<Vec<_>>()
.join(".")
}
}
impl VarDecl {
pub fn identifier(&self) -> Option<Identifier> {
support::child(&self.syntax)
}
pub fn name(&self) -> Option<String> {
self.identifier().and_then(|id| id.name())
}
pub fn value(&self) -> Option<Expr> {
support::child(&self.syntax)
}
}
impl ConstDecl {
pub fn identifier(&self) -> Option<Identifier> {
support::child(&self.syntax)
}
pub fn name(&self) -> Option<String> {
self.identifier().and_then(|id| id.name())
}
pub fn value(&self) -> Option<Expr> {
support::child(&self.syntax)
}
}
impl ListDecl {
pub fn identifier(&self) -> Option<Identifier> {
support::child(&self.syntax)
}
pub fn name(&self) -> Option<String> {
self.identifier().and_then(|id| id.name())
}
pub fn definition(&self) -> Option<ListDef> {
support::child(&self.syntax)
}
}
impl ListDef {
pub fn members(&self) -> impl Iterator<Item = ListMember> {
support::children(&self.syntax)
}
}
impl ListMember {
pub fn on_member(&self) -> Option<ListMemberOn> {
support::child(&self.syntax)
}
pub fn off_member(&self) -> Option<ListMemberOff> {
support::child(&self.syntax)
}
}
impl ListMemberOn {
pub fn name_token(&self) -> Option<SyntaxToken> {
support::ident_or_keyword_token(&self.syntax)
}
pub fn name(&self) -> Option<String> {
self.name_token().map(|t| t.text().to_string())
}
pub fn value_token(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, INTEGER)
}
pub fn value(&self) -> Option<i64> {
self.value_token()
.and_then(|t| t.text().parse::<i64>().ok())
}
}
impl ListMemberOff {
pub fn name_token(&self) -> Option<SyntaxToken> {
support::ident_or_keyword_token(&self.syntax)
}
pub fn name(&self) -> Option<String> {
self.name_token().map(|t| t.text().to_string())
}
pub fn value_token(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, INTEGER)
}
pub fn value(&self) -> Option<i64> {
self.value_token()
.and_then(|t| t.text().parse::<i64>().ok())
}
}
impl FunctionParamList {
pub fn params(&self) -> impl Iterator<Item = Identifier> {
support::children(&self.syntax)
}
}
impl IntegerLit {
pub fn value_token(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, INTEGER)
}
pub fn value(&self) -> Option<i64> {
self.value_token()
.and_then(|t| t.text().parse::<i64>().ok())
}
}
impl FloatLit {
pub fn value_token(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, FLOAT)
}
pub fn value(&self) -> Option<f64> {
self.value_token()
.and_then(|t| t.text().parse::<f64>().ok())
}
}
impl StringLit {
pub fn raw_text(&self) -> String {
let full = self.syntax.text().to_string();
let trimmed = full.strip_prefix('"').unwrap_or(&full);
trimmed.strip_suffix('"').unwrap_or(trimmed).to_string()
}
}
impl BooleanLit {
pub fn value(&self) -> Option<bool> {
let tok = self
.syntax
.children_with_tokens()
.filter_map(rowan::NodeOrToken::into_token)
.find(|tok| matches!(tok.kind(), KW_TRUE | KW_FALSE))?;
match tok.kind() {
KW_TRUE => Some(true),
KW_FALSE => Some(false),
_ => None,
}
}
}
impl AuthorWarning {
pub fn text(&self) -> String {
self.syntax
.children_with_tokens()
.filter_map(rowan::NodeOrToken::into_token)
.skip_while(|tok| matches!(tok.kind(), KW_TODO | COLON) || tok.kind().is_trivia())
.take_while(|tok| tok.kind() != NEWLINE)
.map(|tok| tok.text().to_string())
.collect::<String>()
.trim()
.to_string()
}
}
impl ChoiceCondition {
pub fn expr(&self) -> Option<Expr> {
support::child(&self.syntax)
}
}
impl InnerExpression {
pub fn expr(&self) -> Option<Expr> {
support::child(&self.syntax)
}
}
impl ParenExpr {
pub fn inner(&self) -> Option<Expr> {
support::child(&self.syntax)
}
}
impl BranchContent {
pub fn divert(&self) -> Option<DivertNode> {
support::child(&self.syntax)
}
}
impl MultilineBranchBody {
pub fn texts(&self) -> impl Iterator<Item = Text> {
support::children(&self.syntax)
}
pub fn inline_logics(&self) -> impl Iterator<Item = InlineLogic> {
support::children(&self.syntax)
}
pub fn glue_nodes(&self) -> impl Iterator<Item = GlueNode> {
support::children(&self.syntax)
}
pub fn escapes(&self) -> impl Iterator<Item = Escape> {
support::children(&self.syntax)
}
pub fn logic_lines(&self) -> impl Iterator<Item = LogicLine> {
support::children(&self.syntax)
}
pub fn divert(&self) -> Option<DivertNode> {
support::child(&self.syntax)
}
pub fn content_lines(&self) -> impl Iterator<Item = ContentLine> {
support::children(&self.syntax)
}
pub fn choices(&self) -> impl Iterator<Item = Choice> {
support::children(&self.syntax)
}
}