use itertools::Itertools;
use ra_ap_syntax::ast::Expr;
use ra_ap_syntax::{AstNode, SyntaxElement, SyntaxKind, TextRange, TextSize};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MetaValue {
expr: Expr,
elements: Vec<SyntaxElement>,
}
impl MetaValue {
pub fn parse(elems: Vec<SyntaxElement>) -> Option<Self> {
if !elems.is_empty() {
let arg_text = elems
.clone()
.into_iter()
.map(|elem| elem.to_string())
.join("");
let expr = ra_ap_syntax::hacks::parse_expr_from_str(&arg_text);
return expr.map(|exp| Self {
expr: exp,
elements: elems,
});
}
None
}
pub fn elements(&self) -> &Vec<SyntaxElement> {
&self.elements
}
pub fn as_expr_with_inaccurate_text_range(&self) -> &Expr {
&self.expr
}
pub fn kind(&self) -> SyntaxKind {
match &self.expr {
Expr::Literal(lit) => lit.token().kind(),
Expr::PathExpr(path_expr) => {
if let Some(path) = path_expr.path() {
path.syntax().kind()
} else {
path_expr.syntax().kind()
}
}
Expr::UnderscoreExpr(underscore_expr) => {
if let Some(underscore) = underscore_expr.underscore_token() {
underscore.kind()
} else {
underscore_expr.syntax().kind()
}
}
_ => self.expr.syntax().kind(),
}
}
pub fn text_range(&self) -> TextRange {
let mut start: Option<TextSize> = None;
let mut end: Option<TextSize> = None;
for token in &self.elements {
if !token.kind().is_trivia() {
if start.is_none() {
start = Some(token.text_range().start());
}
end = Some(token.text_range().end());
}
}
TextRange::new(
start.unwrap_or(
self.elements
.first()
.expect("parse method ensures that elements is never be empty")
.text_range()
.start(),
),
end.unwrap_or(
self.elements
.last()
.expect("parse method ensures that elements is never be empty")
.text_range()
.start(),
),
)
}
}
impl ToString for MetaValue {
fn to_string(&self) -> String {
self.expr.to_string()
}
}