use crate::syntax::{SyntaxKind, SyntaxNode, SyntaxToken};
use super::support::{AstChildren, child, child_token, children};
use super::traits::AstNode;
#[derive(Clone, Debug)]
pub enum Expression {
BinaryExpr(BinaryExpr),
UnaryExpr(UnaryExpr),
Atom(Atom),
}
impl AstNode for Expression {
fn can_cast(kind: SyntaxKind) -> bool {
BinaryExpr::can_cast(kind) || UnaryExpr::can_cast(kind) || Atom::can_cast(kind)
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if BinaryExpr::can_cast(syntax.kind()) {
return BinaryExpr::cast(syntax).map(Expression::BinaryExpr);
}
if UnaryExpr::can_cast(syntax.kind()) {
return UnaryExpr::cast(syntax).map(Expression::UnaryExpr);
}
Atom::cast(syntax).map(Expression::Atom)
}
fn syntax(&self) -> &SyntaxNode {
match self {
Expression::BinaryExpr(it) => it.syntax(),
Expression::UnaryExpr(it) => it.syntax(),
Expression::Atom(it) => it.syntax(),
}
}
}
#[derive(Clone, Debug)]
pub struct BinaryExpr(SyntaxNode);
impl AstNode for BinaryExpr {
fn can_cast(kind: SyntaxKind) -> bool {
matches!(
kind,
SyntaxKind::OR_EXPR
| SyntaxKind::XOR_EXPR
| SyntaxKind::AND_EXPR
| SyntaxKind::COMPARISON_EXPR
| SyntaxKind::ADD_SUB_EXPR
| SyntaxKind::MUL_DIV_MOD_EXPR
| SyntaxKind::POWER_EXPR
| SyntaxKind::STRING_LIST_NULL_EXPR
| SyntaxKind::LIST_OP_EXPR
| SyntaxKind::STRING_OP_EXPR
| SyntaxKind::NULL_OP_EXPR
| SyntaxKind::PROPERTY_OR_LABELS_EXPR
)
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(BinaryExpr(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl BinaryExpr {
pub fn op_kind(&self) -> Option<BinOp> {
match self.0.kind() {
SyntaxKind::OR_EXPR => Some(BinOp::Or),
SyntaxKind::XOR_EXPR => Some(BinOp::Xor),
SyntaxKind::AND_EXPR => Some(BinOp::And),
SyntaxKind::COMPARISON_EXPR => {
if child_token(&self.0, SyntaxKind::EQ).is_some() {
Some(BinOp::Eq)
} else if child_token(&self.0, SyntaxKind::NE).is_some() {
Some(BinOp::Ne)
} else if child_token(&self.0, SyntaxKind::LT).is_some() {
Some(BinOp::Lt)
} else if child_token(&self.0, SyntaxKind::GT).is_some() {
Some(BinOp::Gt)
} else if child_token(&self.0, SyntaxKind::LE).is_some() {
Some(BinOp::Le)
} else if child_token(&self.0, SyntaxKind::GE).is_some() {
Some(BinOp::Ge)
} else if child_token(&self.0, SyntaxKind::TILDE_EQ).is_some() {
Some(BinOp::RegexMatch)
} else {
None
}
}
SyntaxKind::ADD_SUB_EXPR => {
if child_token(&self.0, SyntaxKind::PLUS).is_some() {
Some(BinOp::Add)
} else {
Some(BinOp::Sub)
}
}
SyntaxKind::MUL_DIV_MOD_EXPR => {
if child_token(&self.0, SyntaxKind::STAR).is_some() {
Some(BinOp::Mul)
} else if child_token(&self.0, SyntaxKind::SLASH).is_some() {
Some(BinOp::Div)
} else {
Some(BinOp::Mod)
}
}
SyntaxKind::POWER_EXPR => Some(BinOp::Power),
SyntaxKind::STRING_LIST_NULL_EXPR | SyntaxKind::STRING_OP_EXPR => {
if child_token(&self.0, SyntaxKind::KW_STARTS).is_some() {
Some(BinOp::StartsWith)
} else if child_token(&self.0, SyntaxKind::KW_ENDS).is_some() {
Some(BinOp::EndsWith)
} else if child_token(&self.0, SyntaxKind::KW_CONTAINS).is_some() {
Some(BinOp::Contains)
} else if child_token(&self.0, SyntaxKind::KW_IN).is_some() {
Some(BinOp::In)
} else if child_token(&self.0, SyntaxKind::KW_IS).is_some() {
if child_token(&self.0, SyntaxKind::KW_NOT).is_some() {
Some(BinOp::IsNotNull)
} else {
Some(BinOp::IsNull)
}
} else {
None
}
}
SyntaxKind::LIST_OP_EXPR => {
if child_token(&self.0, SyntaxKind::KW_IN).is_some() {
Some(BinOp::In)
} else {
Some(BinOp::Index)
}
}
SyntaxKind::NULL_OP_EXPR => {
if child_token(&self.0, SyntaxKind::KW_NOT).is_some() {
Some(BinOp::IsNotNull)
} else {
Some(BinOp::IsNull)
}
}
SyntaxKind::PROPERTY_OR_LABELS_EXPR => {
if child_token(&self.0, SyntaxKind::DOT).is_some() {
Some(BinOp::PropertyLookup)
} else if self
.0
.children()
.any(|child| child.kind() == SyntaxKind::NODE_LABELS)
{
Some(BinOp::HasLabel)
} else {
None
}
}
_ => None,
}
}
pub fn lhs(&self) -> Option<Expression> {
self.0
.prev_sibling()
.and_then(Expression::cast)
.or_else(|| self.0.children().find_map(Expression::cast))
.or_else(|| {
self.0
.prev_sibling()
.and_then(Variable::cast)
.map(|v| Expression::Atom(Atom::Variable(v)))
})
}
pub fn rhs(&self) -> Option<Expression> {
self.0.children().filter_map(Expression::cast).last()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BinOp {
Or,
Xor,
And,
Eq,
Ne,
Lt,
Gt,
Le,
Ge,
RegexMatch,
Add,
Sub,
Mul,
Div,
Mod,
Power,
StartsWith,
EndsWith,
Contains,
In,
IsNull,
IsNotNull,
Index,
PropertyLookup,
HasLabel,
}
#[derive(Clone, Debug)]
pub struct UnaryExpr(SyntaxNode);
impl AstNode for UnaryExpr {
fn can_cast(kind: SyntaxKind) -> bool {
matches!(kind, SyntaxKind::NOT_EXPR | SyntaxKind::UNARY_ADD_SUB_EXPR)
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(UnaryExpr(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl UnaryExpr {
pub fn op(&self) -> Option<UnOp> {
if self.0.kind() == SyntaxKind::NOT_EXPR {
Some(UnOp::Not)
} else if child_token(&self.0, SyntaxKind::PLUS).is_some() {
Some(UnOp::Pos)
} else if child_token(&self.0, SyntaxKind::MINUS).is_some() {
Some(UnOp::Neg)
} else {
None
}
}
pub fn operand(&self) -> Option<Expression> {
self.0.children().filter_map(Expression::cast).last()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum UnOp {
Not,
Pos,
Neg,
}
#[derive(Clone, Debug)]
pub enum Atom {
Literal(Literal),
Variable(Variable),
Parameter(Parameter),
FunctionInvocation(FunctionInvocation),
Parenthesized(ParenthesizedExpr),
Case(CaseExpr),
ListLiteral(ListLiteral),
MapLiteral(MapLiteral),
ListComprehension(ListComprehension),
PatternComprehension(PatternComprehension),
FilterExpression(FilterExpression),
ExistsSubquery(ExistsSubquery),
CountSubquery(CountSubquery),
CollectSubquery(CollectSubquery),
MapProjection(MapProjection),
ImplicitProcedureInvocation(ImplicitProcedureInvocation),
PropertyLookup(PropertyLookup),
Null(NullLiteral),
}
impl AstNode for Atom {
fn can_cast(kind: SyntaxKind) -> bool {
matches!(
kind,
SyntaxKind::LITERAL
| SyntaxKind::NUMBER_LITERAL
| SyntaxKind::STRING_LITERAL
| SyntaxKind::BOOLEAN_LITERAL
| SyntaxKind::NULL_KW
| SyntaxKind::VARIABLE
| SyntaxKind::PARAMETER
| SyntaxKind::FUNCTION_INVOCATION
| SyntaxKind::PARENTHESIZED_EXPR
| SyntaxKind::CASE_EXPR
| SyntaxKind::LIST_LITERAL
| SyntaxKind::MAP_LITERAL
| SyntaxKind::LIST_COMPREHENSION
| SyntaxKind::PATTERN_COMPREHENSION
| SyntaxKind::FILTER_EXPRESSION
| SyntaxKind::EXISTS_SUBQUERY
| SyntaxKind::COUNT_SUBQUERY
| SyntaxKind::COLLECT_SUBQUERY
| SyntaxKind::MAP_PROJECTION
| SyntaxKind::IMPLICIT_PROCEDURE_INVOCATION
| SyntaxKind::PROPERTY_LOOKUP
)
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
match syntax.kind() {
SyntaxKind::LITERAL
| SyntaxKind::NUMBER_LITERAL
| SyntaxKind::STRING_LITERAL
| SyntaxKind::BOOLEAN_LITERAL => Literal::cast(syntax).map(Atom::Literal),
SyntaxKind::NULL_KW => NullLiteral::cast(syntax).map(Atom::Null),
SyntaxKind::VARIABLE => Variable::cast(syntax).map(Atom::Variable),
SyntaxKind::PARAMETER => Parameter::cast(syntax).map(Atom::Parameter),
SyntaxKind::FUNCTION_INVOCATION => {
FunctionInvocation::cast(syntax).map(Atom::FunctionInvocation)
}
SyntaxKind::PARENTHESIZED_EXPR => {
ParenthesizedExpr::cast(syntax).map(Atom::Parenthesized)
}
SyntaxKind::CASE_EXPR => CaseExpr::cast(syntax).map(Atom::Case),
SyntaxKind::LIST_LITERAL => ListLiteral::cast(syntax).map(Atom::ListLiteral),
SyntaxKind::MAP_LITERAL => MapLiteral::cast(syntax).map(Atom::MapLiteral),
SyntaxKind::LIST_COMPREHENSION => {
ListComprehension::cast(syntax).map(Atom::ListComprehension)
}
SyntaxKind::PATTERN_COMPREHENSION => {
PatternComprehension::cast(syntax).map(Atom::PatternComprehension)
}
SyntaxKind::FILTER_EXPRESSION => {
FilterExpression::cast(syntax).map(Atom::FilterExpression)
}
SyntaxKind::EXISTS_SUBQUERY => ExistsSubquery::cast(syntax).map(Atom::ExistsSubquery),
SyntaxKind::COUNT_SUBQUERY => CountSubquery::cast(syntax).map(Atom::CountSubquery),
SyntaxKind::COLLECT_SUBQUERY => {
CollectSubquery::cast(syntax).map(Atom::CollectSubquery)
}
SyntaxKind::MAP_PROJECTION => MapProjection::cast(syntax).map(Atom::MapProjection),
SyntaxKind::IMPLICIT_PROCEDURE_INVOCATION => {
ImplicitProcedureInvocation::cast(syntax).map(Atom::ImplicitProcedureInvocation)
}
SyntaxKind::PROPERTY_LOOKUP => PropertyLookup::cast(syntax).map(Atom::PropertyLookup),
_ => None,
}
}
fn syntax(&self) -> &SyntaxNode {
match self {
Atom::Literal(it) => it.syntax(),
Atom::Variable(it) => it.syntax(),
Atom::Parameter(it) => it.syntax(),
Atom::FunctionInvocation(it) => it.syntax(),
Atom::Parenthesized(it) => it.syntax(),
Atom::Case(it) => it.syntax(),
Atom::ListLiteral(it) => it.syntax(),
Atom::MapLiteral(it) => it.syntax(),
Atom::ListComprehension(it) => it.syntax(),
Atom::PatternComprehension(it) => it.syntax(),
Atom::FilterExpression(it) => it.syntax(),
Atom::ExistsSubquery(it) => it.syntax(),
Atom::CountSubquery(it) => it.syntax(),
Atom::CollectSubquery(it) => it.syntax(),
Atom::MapProjection(it) => it.syntax(),
Atom::ImplicitProcedureInvocation(it) => it.syntax(),
Atom::PropertyLookup(it) => it.syntax(),
Atom::Null(it) => it.syntax(),
}
}
}
#[derive(Clone, Debug)]
pub enum Literal {
Number(NumberLiteral),
String(StringLiteral),
Boolean(BooleanLiteral),
Null(NullLiteral),
}
impl AstNode for Literal {
fn can_cast(kind: SyntaxKind) -> bool {
matches!(
kind,
SyntaxKind::LITERAL
| SyntaxKind::NUMBER_LITERAL
| SyntaxKind::STRING_LITERAL
| SyntaxKind::BOOLEAN_LITERAL
| SyntaxKind::NULL_KW
)
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
match syntax.kind() {
SyntaxKind::LITERAL | SyntaxKind::NUMBER_LITERAL => {
NumberLiteral::cast(syntax).map(Literal::Number)
}
SyntaxKind::STRING_LITERAL => StringLiteral::cast(syntax).map(Literal::String),
SyntaxKind::BOOLEAN_LITERAL => BooleanLiteral::cast(syntax).map(Literal::Boolean),
SyntaxKind::NULL_KW => Some(Literal::Null(NullLiteral(syntax))),
_ => None,
}
}
fn syntax(&self) -> &SyntaxNode {
match self {
Literal::Number(it) => it.syntax(),
Literal::String(it) => it.syntax(),
Literal::Boolean(it) => it.syntax(),
Literal::Null(it) => it.syntax(),
}
}
}
#[derive(Clone, Debug)]
pub struct NumberLiteral(SyntaxNode);
impl AstNode for NumberLiteral {
fn can_cast(kind: SyntaxKind) -> bool {
matches!(kind, SyntaxKind::NUMBER_LITERAL | SyntaxKind::LITERAL)
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(NumberLiteral(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl NumberLiteral {
pub fn token(&self) -> Option<SyntaxToken> {
child_token(&self.0, SyntaxKind::INTEGER)
.or_else(|| child_token(&self.0, SyntaxKind::FLOAT))
}
}
#[derive(Clone, Debug)]
pub struct StringLiteral(SyntaxNode);
impl AstNode for StringLiteral {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::STRING_LITERAL
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(StringLiteral(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl StringLiteral {
pub fn token(&self) -> Option<SyntaxToken> {
child_token(&self.0, SyntaxKind::STRING)
}
}
#[derive(Clone, Debug)]
pub struct BooleanLiteral(SyntaxNode);
impl AstNode for BooleanLiteral {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::BOOLEAN_LITERAL
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(BooleanLiteral(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl BooleanLiteral {
pub fn token(&self) -> Option<SyntaxToken> {
child_token(&self.0, SyntaxKind::TRUE_KW)
.or_else(|| child_token(&self.0, SyntaxKind::FALSE_KW))
}
pub fn value(&self) -> bool {
child_token(&self.0, SyntaxKind::TRUE_KW).is_some()
}
}
#[derive(Clone, Debug)]
pub struct NullLiteral(SyntaxNode);
impl AstNode for NullLiteral {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::NULL_KW
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(NullLiteral(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
#[derive(Clone, Debug)]
pub struct Variable(SyntaxNode);
impl AstNode for Variable {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::VARIABLE
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(Variable(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl Variable {
pub fn name(&self) -> Option<super::top_level::SymbolicName> {
child(&self.0)
}
}
#[derive(Clone, Debug)]
pub struct Parameter(SyntaxNode);
impl AstNode for Parameter {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::PARAMETER
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(Parameter(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl Parameter {
pub fn name_token(&self) -> Option<SyntaxToken> {
self.0.children_with_tokens().find_map(|c| {
c.into_token().filter(|t| {
!matches!(
t.kind(),
SyntaxKind::DOLLAR | SyntaxKind::WHITESPACE | SyntaxKind::COMMENT
)
})
})
}
}
#[derive(Clone, Debug)]
pub struct FunctionInvocation(SyntaxNode);
impl AstNode for FunctionInvocation {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::FUNCTION_INVOCATION
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(FunctionInvocation(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl FunctionInvocation {
pub fn name(&self) -> Option<FunctionName> {
self.0
.children()
.find_map(FunctionName::cast)
.or_else(|| self.0.prev_sibling().and_then(FunctionName::cast))
}
pub fn arguments(&self) -> impl Iterator<Item = Expression> {
let mut args = Vec::new();
let mut current = None;
for child in self.0.children_with_tokens() {
if child
.as_token()
.is_some_and(|t| t.kind() == SyntaxKind::COMMA)
{
if let Some(expr) = current.take() {
args.push(expr);
}
continue;
}
if let Some(node) = child.as_node() {
if matches!(
node.kind(),
SyntaxKind::FUNCTION_NAME | SyntaxKind::NAMESPACE | SyntaxKind::VARIABLE
) {
continue;
}
if let Some(expr) = Expression::cast(node.clone()) {
current = Some(expr);
}
}
}
if let Some(expr) = current {
args.push(expr);
}
args.into_iter()
}
pub fn distinct_token(&self) -> Option<SyntaxToken> {
child_token(&self.0, SyntaxKind::KW_DISTINCT)
}
pub fn star_token(&self) -> Option<SyntaxToken> {
child_token(&self.0, SyntaxKind::STAR)
}
}
#[derive(Clone, Debug)]
pub struct FunctionName(SyntaxNode);
impl AstNode for FunctionName {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::FUNCTION_NAME || kind == SyntaxKind::VARIABLE
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(FunctionName(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl FunctionName {
pub fn namespace(&self) -> Option<Namespace> {
self.0
.children()
.filter(|n| n.kind() == SyntaxKind::SYMBOLIC_NAME)
.take(1)
.next()
.and_then(|n| {
if self
.0
.children()
.filter(|n| n.kind() == SyntaxKind::SYMBOLIC_NAME)
.count()
> 1
{
Some(Namespace(n))
} else {
None
}
})
}
pub fn symbolic_names(&self) -> impl Iterator<Item = super::top_level::SymbolicName> {
self.0
.children()
.filter_map(super::top_level::SymbolicName::cast)
}
}
#[derive(Clone, Debug)]
pub struct Namespace(SyntaxNode);
impl AstNode for Namespace {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::NAMESPACE
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(Namespace(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
#[derive(Clone, Debug)]
pub struct ParenthesizedExpr(SyntaxNode);
impl AstNode for ParenthesizedExpr {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::PARENTHESIZED_EXPR
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(ParenthesizedExpr(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl ParenthesizedExpr {
pub fn expr(&self) -> Option<Expression> {
self.0.children().filter_map(Expression::cast).last()
}
}
#[derive(Clone, Debug)]
pub struct CaseExpr(SyntaxNode);
impl AstNode for CaseExpr {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::CASE_EXPR
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(CaseExpr(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl CaseExpr {
pub fn value(&self) -> Option<Expression> {
let mut last: Option<Expression> = None;
for child in self.0.children_with_tokens() {
if let Some(tok) = child.as_token() {
if matches!(tok.kind(), SyntaxKind::KW_WHEN | SyntaxKind::KW_ELSE) {
break;
}
continue;
}
if let Some(node) = child.as_node() {
if node.kind() == SyntaxKind::CASE_ALTERNATIVE {
break;
}
if let Some(e) = Expression::cast(node.clone()) {
last = Some(e);
}
}
}
last
}
pub fn alternatives(&self) -> AstChildren<CaseAlternative> {
children(&self.0)
}
pub fn else_expr(&self) -> Option<Expression> {
let mut seen_else = false;
let mut last: Option<Expression> = None;
for child in self.0.children_with_tokens() {
if let Some(tok) = child.as_token() {
if tok.kind() == SyntaxKind::KW_ELSE {
seen_else = true;
}
continue;
}
if seen_else
&& let Some(node) = child.as_node()
&& let Some(e) = Expression::cast(node.clone())
{
last = Some(e);
}
}
last
}
}
#[derive(Clone, Debug)]
pub struct CaseAlternative(SyntaxNode);
impl AstNode for CaseAlternative {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::CASE_ALTERNATIVE
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(CaseAlternative(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl CaseAlternative {
pub fn when_expr(&self) -> Option<Expression> {
let mut last: Option<Expression> = None;
for child in self.0.children_with_tokens() {
if child
.as_token()
.is_some_and(|t| t.kind() == SyntaxKind::KW_THEN)
{
break;
}
if let Some(node) = child.as_node()
&& let Some(e) = Expression::cast(node.clone())
{
last = Some(e);
}
}
last
}
pub fn then_expr(&self) -> Option<Expression> {
let mut seen_then = false;
let mut last: Option<Expression> = None;
for child in self.0.children_with_tokens() {
if let Some(tok) = child.as_token() {
if tok.kind() == SyntaxKind::KW_THEN {
seen_then = true;
}
continue;
}
if seen_then
&& let Some(node) = child.as_node()
&& let Some(expr) = Expression::cast(node.clone())
{
last = Some(expr);
}
}
last
}
}
#[derive(Clone, Debug)]
pub struct ListLiteral(SyntaxNode);
impl AstNode for ListLiteral {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::LIST_LITERAL
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(ListLiteral(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl ListLiteral {
pub fn elements(&self) -> impl Iterator<Item = Expression> {
self.0.children().filter_map(Expression::cast)
}
}
#[derive(Clone, Debug)]
pub struct MapLiteral(SyntaxNode);
impl AstNode for MapLiteral {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::MAP_LITERAL
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(MapLiteral(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl MapLiteral {
pub fn entries(&self) -> AstChildren<MapEntry> {
children(&self.0)
}
}
#[derive(Clone, Debug)]
pub struct MapEntry(SyntaxNode);
impl AstNode for MapEntry {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::MAP_ENTRY
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(MapEntry(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl MapEntry {
pub fn key(&self) -> Option<PropertyKeyName> {
child(&self.0)
}
pub fn value(&self) -> Option<Expression> {
self.0
.children()
.filter(|n| {
n.kind() != SyntaxKind::PROPERTY_KEY_NAME && n.kind() != SyntaxKind::SYMBOLIC_NAME
})
.find_map(Expression::cast)
}
}
#[derive(Clone, Debug)]
pub struct PropertyKeyName(SyntaxNode);
impl AstNode for PropertyKeyName {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::PROPERTY_KEY_NAME
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(PropertyKeyName(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl PropertyKeyName {
pub fn symbolic_name(&self) -> Option<super::top_level::SymbolicName> {
child(&self.0)
}
}
#[derive(Clone, Debug)]
pub struct ListComprehension(SyntaxNode);
impl AstNode for ListComprehension {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::LIST_COMPREHENSION
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(ListComprehension(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl ListComprehension {
pub fn filter(&self) -> Option<FilterExpression> {
child(&self.0)
}
pub fn body(&self) -> Option<Expression> {
self.0.children().filter_map(Expression::cast).last()
}
}
#[derive(Clone, Debug)]
pub struct PatternComprehension(SyntaxNode);
impl AstNode for PatternComprehension {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::PATTERN_COMPREHENSION
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(PatternComprehension(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl PatternComprehension {
pub fn variable(&self) -> Option<Variable> {
self.0
.children()
.take_while(|n| {
n.kind() != SyntaxKind::RELATIONSHIPS_PATTERN
&& n.kind() != SyntaxKind::NODE_PATTERN
&& n.kind() != SyntaxKind::PATTERN_ELEMENT_CHAIN
})
.find_map(Variable::cast)
}
pub fn pattern(&self) -> Option<SyntaxNode> {
self.0.children().find(|n| {
matches!(
n.kind(),
SyntaxKind::RELATIONSHIPS_PATTERN
| SyntaxKind::NODE_PATTERN
| SyntaxKind::PATTERN_ELEMENT_CHAIN
)
})
}
pub fn where_clause(&self) -> Option<super::clauses::WhereClause> {
child(&self.0)
}
pub fn body(&self) -> Option<Expression> {
self.0.children().filter_map(Expression::cast).last()
}
}
#[derive(Clone, Debug)]
pub struct FilterExpression(SyntaxNode);
impl AstNode for FilterExpression {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::FILTER_EXPRESSION
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(FilterExpression(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl FilterExpression {
pub fn id_in_coll(&self) -> Option<IdInColl> {
child(&self.0)
}
pub fn where_clause(&self) -> Option<super::clauses::WhereClause> {
self.0
.children()
.filter(|n| n.kind() != SyntaxKind::ID_IN_COLL)
.find_map(super::clauses::WhereClause::cast)
}
}
#[derive(Clone, Debug)]
pub struct IdInColl(SyntaxNode);
impl AstNode for IdInColl {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::ID_IN_COLL
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(IdInColl(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl IdInColl {
pub fn variable(&self) -> Option<Variable> {
child(&self.0)
}
pub fn collection(&self) -> Option<Expression> {
self.0
.children()
.filter(|n| n.kind() != SyntaxKind::VARIABLE && n.kind() != SyntaxKind::SYMBOLIC_NAME)
.find_map(Expression::cast)
}
}
#[derive(Clone, Debug)]
pub struct ExistsSubquery(SyntaxNode);
impl AstNode for ExistsSubquery {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::EXISTS_SUBQUERY
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(ExistsSubquery(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl ExistsSubquery {
pub fn pattern(&self) -> Option<SyntaxNode> {
self.0.children().find(|n| {
matches!(
n.kind(),
SyntaxKind::NODE_PATTERN
| SyntaxKind::RELATIONSHIPS_PATTERN
| SyntaxKind::PATTERN_ELEMENT_CHAIN
)
})
}
pub fn where_clause(&self) -> Option<super::clauses::WhereClause> {
child(&self.0)
}
pub fn clauses(&self) -> AstChildren<super::clauses::Clause> {
children(&self.0)
}
}
#[derive(Clone, Debug)]
pub struct CountSubquery(SyntaxNode);
impl AstNode for CountSubquery {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::COUNT_SUBQUERY
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(CountSubquery(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl CountSubquery {
pub fn clauses(&self) -> AstChildren<super::clauses::Clause> {
children(&self.0)
}
}
#[derive(Clone, Debug)]
pub struct CollectSubquery(SyntaxNode);
impl AstNode for CollectSubquery {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::COLLECT_SUBQUERY
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(CollectSubquery(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl CollectSubquery {
pub fn clauses(&self) -> AstChildren<super::clauses::Clause> {
children(&self.0)
}
}
#[derive(Clone, Debug)]
pub struct MapProjection(SyntaxNode);
impl AstNode for MapProjection {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::MAP_PROJECTION
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(MapProjection(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl MapProjection {
pub fn variable(&self) -> Option<Variable> {
child(&self.0)
}
pub fn items(&self) -> impl Iterator<Item = MapProjectionItem> {
self.0.children().filter_map(MapProjectionItem::cast)
}
}
#[derive(Clone, Debug)]
pub struct MapProjectionItem(SyntaxNode);
impl AstNode for MapProjectionItem {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::MAP_PROJECTION_ITEM
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(MapProjectionItem(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl MapProjectionItem {
pub fn is_star(&self) -> bool {
child_token(&self.0, SyntaxKind::STAR).is_some()
}
pub fn property_name(&self) -> Option<PropertyKeyName> {
child(&self.0)
}
pub fn expression(&self) -> Option<Expression> {
self.0
.children()
.filter(|n| {
n.kind() != SyntaxKind::PROPERTY_KEY_NAME && n.kind() != SyntaxKind::SYMBOLIC_NAME
})
.find_map(Expression::cast)
}
}
#[derive(Clone, Debug)]
pub struct PropertyLookup(SyntaxNode);
impl AstNode for PropertyLookup {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::PROPERTY_LOOKUP
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(PropertyLookup(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl PropertyLookup {
pub fn key(&self) -> Option<PropertyKeyName> {
child(&self.0)
}
pub fn base(&self) -> Option<Expression> {
self.0.prev_sibling().and_then(Expression::cast)
}
}
#[derive(Clone, Debug)]
pub struct PropertyExpression(SyntaxNode);
impl AstNode for PropertyExpression {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::PROPERTY_EXPRESSION
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(PropertyExpression(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
#[derive(Clone, Debug)]
pub struct ProcedureName(SyntaxNode);
impl AstNode for ProcedureName {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::PROCEDURE_NAME
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(ProcedureName(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl ProcedureName {
pub fn namespace(&self) -> Option<Namespace> {
let names: Vec<_> = self
.0
.children()
.filter(|n| n.kind() == SyntaxKind::SYMBOLIC_NAME)
.collect();
if names.len() > 1 {
names.first().cloned().map(|n| Namespace(n.clone()))
} else {
None
}
}
pub fn symbolic_names(&self) -> impl Iterator<Item = super::top_level::SymbolicName> {
self.0
.children()
.filter_map(super::top_level::SymbolicName::cast)
}
}
#[derive(Clone, Debug)]
pub struct ImplicitProcedureInvocation(SyntaxNode);
impl AstNode for ImplicitProcedureInvocation {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::IMPLICIT_PROCEDURE_INVOCATION
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(ImplicitProcedureInvocation(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl ImplicitProcedureInvocation {
pub fn procedure_name(&self) -> Option<ProcedureName> {
child(&self.0)
}
}
#[derive(Clone, Debug)]
pub struct ExplicitProcedureInvocation(SyntaxNode);
impl AstNode for ExplicitProcedureInvocation {
fn can_cast(kind: SyntaxKind) -> bool {
kind == SyntaxKind::EXPLICIT_PROCEDURE_INVOCATION
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(ExplicitProcedureInvocation(syntax))
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode {
&self.0
}
}
impl ExplicitProcedureInvocation {
pub fn procedure_name(&self) -> Option<ProcedureName> {
child(&self.0)
}
pub fn arguments(&self) -> impl Iterator<Item = Expression> {
self.0
.children()
.filter(|n| n.kind() != SyntaxKind::PROCEDURE_NAME && n.kind() != SyntaxKind::NAMESPACE)
.filter_map(Expression::cast)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::parser;
use crate::syntax::ast::traits::AstNode;
use assert2::check;
fn find_return(
source: &super::super::top_level::SourceFile,
) -> super::super::clauses::ReturnClause {
for clause in source.statements().next().unwrap().clauses() {
if let super::super::clauses::Clause::Return(r) = clause {
return r;
}
}
panic!("no return clause found");
}
#[test]
fn test_binary_expr_add() {
let parse = parser::parse("RETURN 1 + 2");
let source = super::super::top_level::SourceFile::cast(parse.tree.clone()).unwrap();
let ret = find_return(&source);
let proj = ret.projection_body().unwrap();
let item = proj.items().next().unwrap();
let expr = item.expr().unwrap();
let bin = match expr {
Expression::BinaryExpr(b) => b,
other => panic!("expected BinaryExpr, got {:?}", other.syntax().kind()),
};
check!(bin.op_kind() == Some(BinOp::Add));
}
#[test]
fn test_binary_expr_mul_precedence() {
let parse = parser::parse("RETURN 1 + 2 * 3");
let source = super::super::top_level::SourceFile::cast(parse.tree.clone()).unwrap();
let ret = find_return(&source);
let proj = ret.projection_body().unwrap();
let item = proj.items().next().unwrap();
let expr = item.expr().unwrap();
let add = match expr {
Expression::BinaryExpr(b) => b,
_ => panic!("expected BinaryExpr at top"),
};
check!(add.op_kind() == Some(BinOp::Add));
let rhs = add.rhs().unwrap();
let mul = match rhs {
Expression::BinaryExpr(b) => b,
_ => panic!("expected BinaryExpr on rhs"),
};
check!(mul.op_kind() == Some(BinOp::Mul));
}
#[test]
fn test_unary_expr_not() {
let parse = parser::parse("RETURN NOT true");
let source = super::super::top_level::SourceFile::cast(parse.tree).unwrap();
let ret = find_return(&source);
let proj = ret.projection_body().unwrap();
let item = proj.items().next().unwrap();
let expr = item.expr().unwrap();
let unary = match expr {
Expression::UnaryExpr(u) => u,
_ => panic!("expected UnaryExpr"),
};
check!(unary.op() == Some(UnOp::Not));
}
#[test]
fn test_expression_can_cast() {
use crate::syntax::{CypherLang, SyntaxNode};
use rowan::{GreenNodeBuilder, Language};
let mut builder = GreenNodeBuilder::new();
builder.start_node(CypherLang::kind_to_raw(SyntaxKind::SOURCE_FILE));
builder.finish_node();
let green = builder.finish();
let node: SyntaxNode = rowan::SyntaxNode::new_root(green);
check!(Expression::can_cast(node.kind()) == false);
check!(BinaryExpr::can_cast(SyntaxKind::OR_EXPR) == true);
check!(BinaryExpr::can_cast(SyntaxKind::ATOM) == false);
check!(UnaryExpr::can_cast(SyntaxKind::NOT_EXPR) == true);
check!(Atom::can_cast(SyntaxKind::VARIABLE) == true);
}
}