2019-04-02 10:02:23 +00:00
|
|
|
//! Various extension methods to ast Expr Nodes, which are hard to code-generate.
|
|
|
|
|
2021-07-29 20:01:24 +00:00
|
|
|
use rowan::WalkEvent;
|
|
|
|
|
2019-04-02 09:47:39 +00:00
|
|
|
use crate::{
|
2020-04-09 20:22:58 +00:00
|
|
|
ast::{self, support, AstChildren, AstNode},
|
2020-11-06 21:52:22 +00:00
|
|
|
AstToken,
|
2019-05-15 12:35:47 +00:00
|
|
|
SyntaxKind::*,
|
2019-07-04 20:05:17 +00:00
|
|
|
SyntaxToken, T,
|
2019-04-02 09:47:39 +00:00
|
|
|
};
|
|
|
|
|
2020-07-29 13:45:23 +00:00
|
|
|
impl ast::AttrsOwner for ast::Expr {}
|
|
|
|
|
2020-02-05 09:50:07 +00:00
|
|
|
impl ast::Expr {
|
|
|
|
pub fn is_block_like(&self) -> bool {
|
2021-03-21 14:33:18 +00:00
|
|
|
matches!(
|
|
|
|
self,
|
2020-02-05 09:50:07 +00:00
|
|
|
ast::Expr::IfExpr(_)
|
2021-03-21 14:33:18 +00:00
|
|
|
| ast::Expr::LoopExpr(_)
|
|
|
|
| ast::Expr::ForExpr(_)
|
|
|
|
| ast::Expr::WhileExpr(_)
|
|
|
|
| ast::Expr::BlockExpr(_)
|
|
|
|
| ast::Expr::MatchExpr(_)
|
|
|
|
| ast::Expr::EffectExpr(_)
|
|
|
|
)
|
2020-02-05 09:50:07 +00:00
|
|
|
}
|
2020-11-14 16:49:36 +00:00
|
|
|
|
|
|
|
pub fn name_ref(&self) -> Option<ast::NameRef> {
|
|
|
|
if let ast::Expr::PathExpr(expr) = self {
|
|
|
|
let path = expr.path()?;
|
|
|
|
let segment = path.segment()?;
|
|
|
|
let name_ref = segment.name_ref()?;
|
|
|
|
if path.qualifier().is_none() {
|
|
|
|
return Some(name_ref);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None
|
|
|
|
}
|
2021-07-29 20:01:24 +00:00
|
|
|
|
|
|
|
/// Preorder walk all the expression's child expressions.
|
|
|
|
pub fn walk(&self, cb: &mut dyn FnMut(ast::Expr)) {
|
|
|
|
self.preorder(&mut |ev| {
|
|
|
|
if let WalkEvent::Enter(expr) = ev {
|
|
|
|
cb(expr);
|
|
|
|
}
|
|
|
|
false
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Preorder walk all the expression's child expressions preserving events.
|
2021-08-07 20:16:15 +00:00
|
|
|
/// If the callback returns true on an [`WalkEvent::Enter`], the subtree of the expression will be skipped.
|
2021-07-29 20:01:24 +00:00
|
|
|
/// Note that the subtree may already be skipped due to the context analysis this function does.
|
|
|
|
pub fn preorder(&self, cb: &mut dyn FnMut(WalkEvent<ast::Expr>) -> bool) {
|
|
|
|
let mut preorder = self.syntax().preorder();
|
|
|
|
while let Some(event) = preorder.next() {
|
|
|
|
let node = match event {
|
|
|
|
WalkEvent::Enter(node) => node,
|
|
|
|
WalkEvent::Leave(node) => {
|
|
|
|
if let Some(expr) = ast::Expr::cast(node) {
|
|
|
|
cb(WalkEvent::Leave(expr));
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
match ast::Stmt::cast(node.clone()) {
|
|
|
|
// recursively walk the initializer, skipping potential const pat expressions
|
|
|
|
// let statements aren't usually nested too deeply so this is fine to recurse on
|
|
|
|
Some(ast::Stmt::LetStmt(l)) => {
|
|
|
|
if let Some(expr) = l.initializer() {
|
|
|
|
expr.preorder(cb);
|
|
|
|
}
|
|
|
|
preorder.skip_subtree();
|
|
|
|
}
|
|
|
|
// Don't skip subtree since we want to process the expression child next
|
|
|
|
Some(ast::Stmt::ExprStmt(_)) => (),
|
|
|
|
// skip inner items which might have their own expressions
|
|
|
|
Some(ast::Stmt::Item(_)) => preorder.skip_subtree(),
|
|
|
|
None => {
|
|
|
|
// skip const args, those expressions are a different context
|
|
|
|
if ast::GenericArg::can_cast(node.kind()) {
|
|
|
|
preorder.skip_subtree();
|
|
|
|
} else if let Some(expr) = ast::Expr::cast(node) {
|
|
|
|
let is_different_context = match &expr {
|
|
|
|
ast::Expr::EffectExpr(effect) => {
|
|
|
|
matches!(
|
|
|
|
effect.effect(),
|
|
|
|
ast::Effect::Async(_)
|
|
|
|
| ast::Effect::Try(_)
|
|
|
|
| ast::Effect::Const(_)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
ast::Expr::ClosureExpr(_) => true,
|
|
|
|
_ => false,
|
|
|
|
};
|
|
|
|
let skip = cb(WalkEvent::Enter(expr));
|
|
|
|
if skip || is_different_context {
|
|
|
|
preorder.skip_subtree();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Preorder walk all the expression's child patterns.
|
|
|
|
pub fn walk_patterns(&self, cb: &mut dyn FnMut(ast::Pat)) {
|
|
|
|
let mut preorder = self.syntax().preorder();
|
|
|
|
while let Some(event) = preorder.next() {
|
|
|
|
let node = match event {
|
|
|
|
WalkEvent::Enter(node) => node,
|
|
|
|
WalkEvent::Leave(_) => continue,
|
|
|
|
};
|
|
|
|
match ast::Stmt::cast(node.clone()) {
|
|
|
|
Some(ast::Stmt::LetStmt(l)) => {
|
|
|
|
if let Some(pat) = l.pat() {
|
|
|
|
pat.walk(cb);
|
|
|
|
}
|
|
|
|
if let Some(expr) = l.initializer() {
|
|
|
|
expr.walk_patterns(cb);
|
|
|
|
}
|
|
|
|
preorder.skip_subtree();
|
|
|
|
}
|
|
|
|
// Don't skip subtree since we want to process the expression child next
|
|
|
|
Some(ast::Stmt::ExprStmt(_)) => (),
|
|
|
|
// skip inner items which might have their own patterns
|
|
|
|
Some(ast::Stmt::Item(_)) => preorder.skip_subtree(),
|
|
|
|
None => {
|
|
|
|
// skip const args, those are a different context
|
|
|
|
if ast::GenericArg::can_cast(node.kind()) {
|
|
|
|
preorder.skip_subtree();
|
|
|
|
} else if let Some(expr) = ast::Expr::cast(node.clone()) {
|
|
|
|
let is_different_context = match &expr {
|
|
|
|
ast::Expr::EffectExpr(effect) => {
|
|
|
|
matches!(
|
|
|
|
effect.effect(),
|
|
|
|
ast::Effect::Async(_)
|
|
|
|
| ast::Effect::Try(_)
|
|
|
|
| ast::Effect::Const(_)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
ast::Expr::ClosureExpr(_) => true,
|
|
|
|
_ => false,
|
|
|
|
};
|
|
|
|
if is_different_context {
|
|
|
|
preorder.skip_subtree();
|
|
|
|
}
|
|
|
|
} else if let Some(pat) = ast::Pat::cast(node) {
|
|
|
|
preorder.skip_subtree();
|
|
|
|
pat.walk(cb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-02-05 09:50:07 +00:00
|
|
|
}
|
|
|
|
|
2019-04-02 09:47:39 +00:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
2019-07-18 16:23:05 +00:00
|
|
|
pub enum ElseBranch {
|
2019-09-02 18:23:19 +00:00
|
|
|
Block(ast::BlockExpr),
|
2019-07-18 16:23:05 +00:00
|
|
|
IfExpr(ast::IfExpr),
|
2019-04-02 09:47:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ast::IfExpr {
|
2019-09-02 18:23:19 +00:00
|
|
|
pub fn then_branch(&self) -> Option<ast::BlockExpr> {
|
2020-02-18 12:53:02 +00:00
|
|
|
self.blocks().next()
|
2019-04-02 09:47:39 +00:00
|
|
|
}
|
2021-07-31 18:00:09 +00:00
|
|
|
|
2019-04-02 09:47:39 +00:00
|
|
|
pub fn else_branch(&self) -> Option<ElseBranch> {
|
|
|
|
let res = match self.blocks().nth(1) {
|
|
|
|
Some(block) => ElseBranch::Block(block),
|
|
|
|
None => {
|
2020-04-09 20:22:58 +00:00
|
|
|
let elif: ast::IfExpr = support::child(self.syntax())?;
|
2019-04-02 09:47:39 +00:00
|
|
|
ElseBranch::IfExpr(elif)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
Some(res)
|
|
|
|
}
|
|
|
|
|
2020-04-29 11:52:55 +00:00
|
|
|
pub fn blocks(&self) -> AstChildren<ast::BlockExpr> {
|
2020-04-09 20:22:58 +00:00
|
|
|
support::children(self.syntax())
|
2019-04-02 09:47:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
|
|
|
pub enum PrefixOp {
|
|
|
|
/// The `*` operator for dereferencing
|
|
|
|
Deref,
|
|
|
|
/// The `!` operator for logical inversion
|
|
|
|
Not,
|
|
|
|
/// The `-` operator for negation
|
|
|
|
Neg,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ast::PrefixExpr {
|
|
|
|
pub fn op_kind(&self) -> Option<PrefixOp> {
|
|
|
|
match self.op_token()?.kind() {
|
2019-05-15 12:35:47 +00:00
|
|
|
T![*] => Some(PrefixOp::Deref),
|
|
|
|
T![!] => Some(PrefixOp::Not),
|
|
|
|
T![-] => Some(PrefixOp::Neg),
|
2019-04-02 09:47:39 +00:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn op_token(&self) -> Option<SyntaxToken> {
|
2019-07-19 16:05:34 +00:00
|
|
|
self.syntax().first_child_or_token()?.into_token()
|
2019-04-02 09:47:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
|
|
|
pub enum BinOp {
|
|
|
|
/// The `||` operator for boolean OR
|
|
|
|
BooleanOr,
|
|
|
|
/// The `&&` operator for boolean AND
|
|
|
|
BooleanAnd,
|
|
|
|
/// The `==` operator for equality testing
|
|
|
|
EqualityTest,
|
|
|
|
/// The `!=` operator for equality testing
|
|
|
|
NegatedEqualityTest,
|
|
|
|
/// The `<=` operator for lesser-equal testing
|
|
|
|
LesserEqualTest,
|
|
|
|
/// The `>=` operator for greater-equal testing
|
|
|
|
GreaterEqualTest,
|
|
|
|
/// The `<` operator for comparison
|
|
|
|
LesserTest,
|
|
|
|
/// The `>` operator for comparison
|
|
|
|
GreaterTest,
|
|
|
|
/// The `+` operator for addition
|
|
|
|
Addition,
|
|
|
|
/// The `*` operator for multiplication
|
|
|
|
Multiplication,
|
|
|
|
/// The `-` operator for subtraction
|
|
|
|
Subtraction,
|
|
|
|
/// The `/` operator for division
|
|
|
|
Division,
|
|
|
|
/// The `%` operator for remainder after division
|
|
|
|
Remainder,
|
|
|
|
/// The `<<` operator for left shift
|
|
|
|
LeftShift,
|
|
|
|
/// The `>>` operator for right shift
|
|
|
|
RightShift,
|
|
|
|
/// The `^` operator for bitwise XOR
|
|
|
|
BitwiseXor,
|
|
|
|
/// The `|` operator for bitwise OR
|
|
|
|
BitwiseOr,
|
|
|
|
/// The `&` operator for bitwise AND
|
|
|
|
BitwiseAnd,
|
|
|
|
/// The `=` operator for assignment
|
|
|
|
Assignment,
|
|
|
|
/// The `+=` operator for assignment after addition
|
|
|
|
AddAssign,
|
|
|
|
/// The `/=` operator for assignment after division
|
|
|
|
DivAssign,
|
|
|
|
/// The `*=` operator for assignment after multiplication
|
|
|
|
MulAssign,
|
|
|
|
/// The `%=` operator for assignment after remainders
|
|
|
|
RemAssign,
|
|
|
|
/// The `>>=` operator for assignment after shifting right
|
|
|
|
ShrAssign,
|
|
|
|
/// The `<<=` operator for assignment after shifting left
|
|
|
|
ShlAssign,
|
|
|
|
/// The `-=` operator for assignment after subtraction
|
|
|
|
SubAssign,
|
|
|
|
/// The `|=` operator for assignment after bitwise OR
|
|
|
|
BitOrAssign,
|
|
|
|
/// The `&=` operator for assignment after bitwise AND
|
|
|
|
BitAndAssign,
|
|
|
|
/// The `^=` operator for assignment after bitwise XOR
|
|
|
|
BitXorAssign,
|
|
|
|
}
|
|
|
|
|
2020-01-04 20:54:31 +00:00
|
|
|
impl BinOp {
|
2020-01-13 16:27:06 +00:00
|
|
|
pub fn is_assignment(self) -> bool {
|
2021-03-21 14:33:18 +00:00
|
|
|
matches!(
|
|
|
|
self,
|
2020-01-04 20:54:31 +00:00
|
|
|
BinOp::Assignment
|
2021-03-21 14:33:18 +00:00
|
|
|
| BinOp::AddAssign
|
|
|
|
| BinOp::DivAssign
|
|
|
|
| BinOp::MulAssign
|
|
|
|
| BinOp::RemAssign
|
|
|
|
| BinOp::ShrAssign
|
|
|
|
| BinOp::ShlAssign
|
|
|
|
| BinOp::SubAssign
|
|
|
|
| BinOp::BitOrAssign
|
|
|
|
| BinOp::BitAndAssign
|
|
|
|
| BinOp::BitXorAssign
|
|
|
|
)
|
2020-01-04 20:54:31 +00:00
|
|
|
}
|
|
|
|
}
|
2020-01-04 22:46:01 +00:00
|
|
|
|
2019-04-02 09:47:39 +00:00
|
|
|
impl ast::BinExpr {
|
2019-11-24 05:14:57 +00:00
|
|
|
pub fn op_details(&self) -> Option<(SyntaxToken, BinOp)> {
|
2019-08-17 14:14:22 +00:00
|
|
|
self.syntax().children_with_tokens().filter_map(|it| it.into_token()).find_map(|c| {
|
|
|
|
let bin_op = match c.kind() {
|
|
|
|
T![||] => BinOp::BooleanOr,
|
|
|
|
T![&&] => BinOp::BooleanAnd,
|
|
|
|
T![==] => BinOp::EqualityTest,
|
|
|
|
T![!=] => BinOp::NegatedEqualityTest,
|
|
|
|
T![<=] => BinOp::LesserEqualTest,
|
|
|
|
T![>=] => BinOp::GreaterEqualTest,
|
|
|
|
T![<] => BinOp::LesserTest,
|
|
|
|
T![>] => BinOp::GreaterTest,
|
|
|
|
T![+] => BinOp::Addition,
|
|
|
|
T![*] => BinOp::Multiplication,
|
|
|
|
T![-] => BinOp::Subtraction,
|
|
|
|
T![/] => BinOp::Division,
|
|
|
|
T![%] => BinOp::Remainder,
|
|
|
|
T![<<] => BinOp::LeftShift,
|
|
|
|
T![>>] => BinOp::RightShift,
|
|
|
|
T![^] => BinOp::BitwiseXor,
|
|
|
|
T![|] => BinOp::BitwiseOr,
|
|
|
|
T![&] => BinOp::BitwiseAnd,
|
|
|
|
T![=] => BinOp::Assignment,
|
|
|
|
T![+=] => BinOp::AddAssign,
|
|
|
|
T![/=] => BinOp::DivAssign,
|
|
|
|
T![*=] => BinOp::MulAssign,
|
|
|
|
T![%=] => BinOp::RemAssign,
|
|
|
|
T![>>=] => BinOp::ShrAssign,
|
|
|
|
T![<<=] => BinOp::ShlAssign,
|
|
|
|
T![-=] => BinOp::SubAssign,
|
|
|
|
T![|=] => BinOp::BitOrAssign,
|
|
|
|
T![&=] => BinOp::BitAndAssign,
|
|
|
|
T![^=] => BinOp::BitXorAssign,
|
|
|
|
_ => return None,
|
|
|
|
};
|
|
|
|
Some((c, bin_op))
|
2019-04-02 09:47:39 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn op_kind(&self) -> Option<BinOp> {
|
|
|
|
self.op_details().map(|t| t.1)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn op_token(&self) -> Option<SyntaxToken> {
|
|
|
|
self.op_details().map(|t| t.0)
|
|
|
|
}
|
|
|
|
|
2019-07-18 16:23:05 +00:00
|
|
|
pub fn lhs(&self) -> Option<ast::Expr> {
|
2020-04-09 20:22:58 +00:00
|
|
|
support::children(self.syntax()).next()
|
2019-04-02 09:47:39 +00:00
|
|
|
}
|
|
|
|
|
2019-07-18 16:23:05 +00:00
|
|
|
pub fn rhs(&self) -> Option<ast::Expr> {
|
2020-04-09 20:22:58 +00:00
|
|
|
support::children(self.syntax()).nth(1)
|
2019-04-02 09:47:39 +00:00
|
|
|
}
|
|
|
|
|
2019-07-18 16:23:05 +00:00
|
|
|
pub fn sub_exprs(&self) -> (Option<ast::Expr>, Option<ast::Expr>) {
|
2020-04-09 20:22:58 +00:00
|
|
|
let mut children = support::children(self.syntax());
|
2019-04-02 09:47:39 +00:00
|
|
|
let first = children.next();
|
|
|
|
let second = children.next();
|
|
|
|
(first, second)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-15 20:05:29 +00:00
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
|
|
|
pub enum RangeOp {
|
|
|
|
/// `..`
|
|
|
|
Exclusive,
|
|
|
|
/// `..=`
|
|
|
|
Inclusive,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ast::RangeExpr {
|
|
|
|
fn op_details(&self) -> Option<(usize, SyntaxToken, RangeOp)> {
|
|
|
|
self.syntax().children_with_tokens().enumerate().find_map(|(ix, child)| {
|
|
|
|
let token = child.into_token()?;
|
|
|
|
let bin_op = match token.kind() {
|
|
|
|
T![..] => RangeOp::Exclusive,
|
|
|
|
T![..=] => RangeOp::Inclusive,
|
|
|
|
_ => return None,
|
|
|
|
};
|
|
|
|
Some((ix, token, bin_op))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn op_kind(&self) -> Option<RangeOp> {
|
|
|
|
self.op_details().map(|t| t.2)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn op_token(&self) -> Option<SyntaxToken> {
|
|
|
|
self.op_details().map(|t| t.1)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn start(&self) -> Option<ast::Expr> {
|
|
|
|
let op_ix = self.op_details()?.0;
|
|
|
|
self.syntax()
|
|
|
|
.children_with_tokens()
|
|
|
|
.take(op_ix)
|
|
|
|
.find_map(|it| ast::Expr::cast(it.into_node()?))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn end(&self) -> Option<ast::Expr> {
|
|
|
|
let op_ix = self.op_details()?.0;
|
|
|
|
self.syntax()
|
|
|
|
.children_with_tokens()
|
|
|
|
.skip(op_ix + 1)
|
|
|
|
.find_map(|it| ast::Expr::cast(it.into_node()?))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-17 14:17:01 +00:00
|
|
|
impl ast::IndexExpr {
|
|
|
|
pub fn base(&self) -> Option<ast::Expr> {
|
2020-04-09 20:22:58 +00:00
|
|
|
support::children(self.syntax()).next()
|
2019-08-17 14:17:01 +00:00
|
|
|
}
|
|
|
|
pub fn index(&self) -> Option<ast::Expr> {
|
2020-04-09 20:22:58 +00:00
|
|
|
support::children(self.syntax()).nth(1)
|
2019-08-17 14:17:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-18 16:23:05 +00:00
|
|
|
pub enum ArrayExprKind {
|
|
|
|
Repeat { initializer: Option<ast::Expr>, repeat: Option<ast::Expr> },
|
|
|
|
ElementList(AstChildren<ast::Expr>),
|
2019-04-04 22:29:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ast::ArrayExpr {
|
|
|
|
pub fn kind(&self) -> ArrayExprKind {
|
|
|
|
if self.is_repeat() {
|
|
|
|
ArrayExprKind::Repeat {
|
2020-04-09 20:22:58 +00:00
|
|
|
initializer: support::children(self.syntax()).next(),
|
|
|
|
repeat: support::children(self.syntax()).nth(1),
|
2019-04-04 22:29:21 +00:00
|
|
|
}
|
|
|
|
} else {
|
2020-04-09 20:22:58 +00:00
|
|
|
ArrayExprKind::ElementList(support::children(self.syntax()))
|
2019-04-04 22:29:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_repeat(&self) -> bool {
|
2019-05-15 12:35:47 +00:00
|
|
|
self.syntax().children_with_tokens().any(|it| it.kind() == T![;])
|
2019-04-04 22:29:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-02 09:47:39 +00:00
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
2019-04-02 09:48:14 +00:00
|
|
|
pub enum LiteralKind {
|
2020-11-06 21:52:22 +00:00
|
|
|
String(ast::String),
|
|
|
|
ByteString(ast::ByteString),
|
|
|
|
IntNumber(ast::IntNumber),
|
|
|
|
FloatNumber(ast::FloatNumber),
|
2019-04-02 09:47:39 +00:00
|
|
|
Char,
|
|
|
|
Byte,
|
2020-04-01 11:47:41 +00:00
|
|
|
Bool(bool),
|
2019-04-02 09:47:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ast::Literal {
|
|
|
|
pub fn token(&self) -> SyntaxToken {
|
2019-07-20 17:04:34 +00:00
|
|
|
self.syntax()
|
2019-06-15 13:22:31 +00:00
|
|
|
.children_with_tokens()
|
2019-07-20 17:04:34 +00:00
|
|
|
.find(|e| e.kind() != ATTR && !e.kind().is_trivia())
|
|
|
|
.and_then(|e| e.into_token())
|
|
|
|
.unwrap()
|
2019-04-02 09:47:39 +00:00
|
|
|
}
|
2020-01-22 00:11:38 +00:00
|
|
|
pub fn kind(&self) -> LiteralKind {
|
|
|
|
let token = self.token();
|
2019-07-28 19:47:44 +00:00
|
|
|
|
2020-11-06 21:52:22 +00:00
|
|
|
if let Some(t) = ast::IntNumber::cast(token.clone()) {
|
|
|
|
return LiteralKind::IntNumber(t);
|
|
|
|
}
|
|
|
|
if let Some(t) = ast::FloatNumber::cast(token.clone()) {
|
|
|
|
return LiteralKind::FloatNumber(t);
|
|
|
|
}
|
|
|
|
if let Some(t) = ast::String::cast(token.clone()) {
|
|
|
|
return LiteralKind::String(t);
|
|
|
|
}
|
|
|
|
if let Some(t) = ast::ByteString::cast(token.clone()) {
|
|
|
|
return LiteralKind::ByteString(t);
|
|
|
|
}
|
|
|
|
|
2020-01-22 00:11:38 +00:00
|
|
|
match token.kind() {
|
2020-04-01 11:47:41 +00:00
|
|
|
T![true] => LiteralKind::Bool(true),
|
|
|
|
T![false] => LiteralKind::Bool(false),
|
2019-04-02 09:48:14 +00:00
|
|
|
CHAR => LiteralKind::Char,
|
|
|
|
BYTE => LiteralKind::Byte,
|
2019-04-02 09:47:39 +00:00
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-01 23:18:19 +00:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
|
|
pub enum Effect {
|
2020-04-30 20:43:06 +00:00
|
|
|
Async(SyntaxToken),
|
|
|
|
Unsafe(SyntaxToken),
|
2020-05-01 23:18:19 +00:00
|
|
|
Try(SyntaxToken),
|
2020-12-23 11:24:24 +00:00
|
|
|
Const(SyntaxToken),
|
2020-05-01 23:18:19 +00:00
|
|
|
// Very much not an effect, but we stuff it into this node anyway
|
|
|
|
Label(ast::Label),
|
2020-04-30 20:43:06 +00:00
|
|
|
}
|
|
|
|
|
2020-05-01 23:18:19 +00:00
|
|
|
impl ast::EffectExpr {
|
|
|
|
pub fn effect(&self) -> Effect {
|
2020-04-30 20:43:06 +00:00
|
|
|
if let Some(token) = self.async_token() {
|
2020-05-01 23:18:19 +00:00
|
|
|
return Effect::Async(token);
|
2020-04-30 20:43:06 +00:00
|
|
|
}
|
|
|
|
if let Some(token) = self.unsafe_token() {
|
2020-05-01 23:18:19 +00:00
|
|
|
return Effect::Unsafe(token);
|
|
|
|
}
|
|
|
|
if let Some(token) = self.try_token() {
|
|
|
|
return Effect::Try(token);
|
|
|
|
}
|
2020-12-23 11:24:24 +00:00
|
|
|
if let Some(token) = self.const_token() {
|
|
|
|
return Effect::Const(token);
|
|
|
|
}
|
2020-05-01 23:18:19 +00:00
|
|
|
if let Some(label) = self.label() {
|
|
|
|
return Effect::Label(label);
|
2020-04-30 20:43:06 +00:00
|
|
|
}
|
2020-05-01 23:18:19 +00:00
|
|
|
unreachable!("ast::EffectExpr without Effect")
|
2020-04-30 20:43:06 +00:00
|
|
|
}
|
2020-05-01 23:18:19 +00:00
|
|
|
}
|
2020-04-30 20:43:06 +00:00
|
|
|
|
2019-09-02 18:41:50 +00:00
|
|
|
impl ast::BlockExpr {
|
|
|
|
/// false if the block is an intrinsic part of the syntax and can't be
|
|
|
|
/// replaced with arbitrary expression.
|
|
|
|
///
|
|
|
|
/// ```not_rust
|
|
|
|
/// fn foo() { not_stand_alone }
|
|
|
|
/// const FOO: () = { stand_alone };
|
|
|
|
/// ```
|
|
|
|
pub fn is_standalone(&self) -> bool {
|
2020-04-30 20:41:14 +00:00
|
|
|
let parent = match self.syntax().parent() {
|
|
|
|
Some(it) => it,
|
2019-09-02 18:41:50 +00:00
|
|
|
None => return true,
|
|
|
|
};
|
2020-07-30 12:51:08 +00:00
|
|
|
!matches!(parent.kind(), FN | IF_EXPR | WHILE_EXPR | LOOP_EXPR | EFFECT_EXPR)
|
2019-09-02 18:41:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-15 13:22:31 +00:00
|
|
|
#[test]
|
|
|
|
fn test_literal_with_attr() {
|
|
|
|
let parse = ast::SourceFile::parse(r#"const _: &str = { #[attr] "Hello" };"#);
|
2019-07-18 16:23:05 +00:00
|
|
|
let lit = parse.tree().syntax().descendants().find_map(ast::Literal::cast).unwrap();
|
2019-06-15 13:22:31 +00:00
|
|
|
assert_eq!(lit.token().text(), r#""Hello""#);
|
|
|
|
}
|
|
|
|
|
2020-07-30 14:21:30 +00:00
|
|
|
impl ast::RecordExprField {
|
|
|
|
pub fn parent_record_lit(&self) -> ast::RecordExpr {
|
|
|
|
self.syntax().ancestors().find_map(ast::RecordExpr::cast).unwrap()
|
2019-04-02 09:47:39 +00:00
|
|
|
}
|
|
|
|
}
|