1use rowan::TextRange;
12use rowan::ast::support;
13
14use crate::ast::AstNode;
15use crate::ast::nodes::{
16 Arg, ArgList, AssignmentExpr, BinaryExpr, BlockExpr, CallExpr, ForExpr, FunctionExpr, IfExpr,
17 ParenExpr, RepeatExpr, Subset2Expr, SubsetExpr, UnaryExpr, WhileExpr,
18};
19use crate::ast::tokens::{AstToken, ComplexLit, FloatLit, Ident, IntLit, StringLit};
20use crate::syntax::{RLanguage, SyntaxElement, SyntaxKind, SyntaxNode};
21
22#[derive(Debug, Clone, PartialEq, Eq, Hash)]
25pub enum Expr {
26 Assignment(AssignmentExpr),
27 Binary(BinaryExpr),
28 Unary(UnaryExpr),
29 Paren(ParenExpr),
30 Call(CallExpr),
31 Subset(SubsetExpr),
32 Subset2(Subset2Expr),
33 If(IfExpr),
34 For(ForExpr),
35 While(WhileExpr),
36 Repeat(RepeatExpr),
37 Function(FunctionExpr),
38 Block(BlockExpr),
39 Name(Ident),
42 IntLiteral(IntLit),
43 FloatLiteral(FloatLit),
44 StringLiteral(StringLit),
45 ComplexLiteral(ComplexLit),
46}
47
48macro_rules! for_each_variant {
50 ($self:ident, $x:ident => $body:expr) => {
51 match $self {
52 Expr::Assignment($x) => $body,
53 Expr::Binary($x) => $body,
54 Expr::Unary($x) => $body,
55 Expr::Paren($x) => $body,
56 Expr::Call($x) => $body,
57 Expr::Subset($x) => $body,
58 Expr::Subset2($x) => $body,
59 Expr::If($x) => $body,
60 Expr::For($x) => $body,
61 Expr::While($x) => $body,
62 Expr::Repeat($x) => $body,
63 Expr::Function($x) => $body,
64 Expr::Block($x) => $body,
65 Expr::Name($x) => $body,
66 Expr::IntLiteral($x) => $body,
67 Expr::FloatLiteral($x) => $body,
68 Expr::StringLiteral($x) => $body,
69 Expr::ComplexLiteral($x) => $body,
70 }
71 };
72}
73
74impl Expr {
75 pub fn cast(element: SyntaxElement) -> Option<Expr> {
79 match element {
80 SyntaxElement::Node(node) => Self::cast_node(node),
81 SyntaxElement::Token(token) => Some(match token.kind() {
82 SyntaxKind::IDENT => Expr::Name(Ident::cast(token)?),
83 SyntaxKind::INT => Expr::IntLiteral(IntLit::cast(token)?),
84 SyntaxKind::FLOAT => Expr::FloatLiteral(FloatLit::cast(token)?),
85 SyntaxKind::STRING => Expr::StringLiteral(StringLit::cast(token)?),
86 SyntaxKind::COMPLEX => Expr::ComplexLiteral(ComplexLit::cast(token)?),
87 _ => return None,
88 }),
89 }
90 }
91
92 pub fn cast_node(node: SyntaxNode) -> Option<Expr> {
96 Some(match node.kind() {
97 SyntaxKind::ASSIGNMENT_EXPR => Expr::Assignment(AssignmentExpr::cast(node)?),
98 SyntaxKind::BINARY_EXPR => Expr::Binary(BinaryExpr::cast(node)?),
99 SyntaxKind::UNARY_EXPR => Expr::Unary(UnaryExpr::cast(node)?),
100 SyntaxKind::PAREN_EXPR => Expr::Paren(ParenExpr::cast(node)?),
101 SyntaxKind::CALL_EXPR => Expr::Call(CallExpr::cast(node)?),
102 SyntaxKind::SUBSET_EXPR => Expr::Subset(SubsetExpr::cast(node)?),
103 SyntaxKind::SUBSET2_EXPR => Expr::Subset2(Subset2Expr::cast(node)?),
104 SyntaxKind::IF_EXPR => Expr::If(IfExpr::cast(node)?),
105 SyntaxKind::FOR_EXPR => Expr::For(ForExpr::cast(node)?),
106 SyntaxKind::WHILE_EXPR => Expr::While(WhileExpr::cast(node)?),
107 SyntaxKind::REPEAT_EXPR => Expr::Repeat(RepeatExpr::cast(node)?),
108 SyntaxKind::FUNCTION_EXPR => Expr::Function(FunctionExpr::cast(node)?),
109 SyntaxKind::BLOCK_EXPR => Expr::Block(BlockExpr::cast(node)?),
110 _ => return None,
111 })
112 }
113
114 pub fn syntax(&self) -> SyntaxElement {
117 for_each_variant!(self, x => x.syntax().clone().into())
118 }
119
120 pub fn text_range(&self) -> TextRange {
122 self.syntax().text_range()
123 }
124
125 pub fn is_atom(&self) -> bool {
130 matches!(
131 self,
132 Expr::Name(_)
133 | Expr::IntLiteral(_)
134 | Expr::FloatLiteral(_)
135 | Expr::StringLiteral(_)
136 | Expr::ComplexLiteral(_)
137 | Expr::Call(_)
138 | Expr::Paren(_)
139 | Expr::Subset(_)
140 | Expr::Subset2(_)
141 )
142 }
143}
144
145pub trait HasArgList: AstNode<Language = RLanguage> {
148 fn arg_list(&self) -> Option<ArgList> {
150 support::child(self.syntax())
151 }
152
153 fn args(&self) -> impl Iterator<Item = Arg> {
155 self.arg_list()
156 .map(|list| list.args().collect::<Vec<_>>())
157 .unwrap_or_default()
158 .into_iter()
159 }
160
161 fn nth_positional(&self, n: usize) -> Option<SyntaxElement> {
163 self.args()
164 .filter(|arg| !arg.is_named())
165 .nth(n)
166 .and_then(|arg| arg.value())
167 }
168
169 fn named_arg(&self, name: &str) -> Option<SyntaxElement> {
171 self.args()
172 .find(|arg| arg.name().as_deref() == Some(name))
173 .and_then(|arg| arg.value())
174 }
175}
176
177impl HasArgList for CallExpr {}
178impl HasArgList for SubsetExpr {}
179impl HasArgList for Subset2Expr {}