Cargo Format
Run `cargo fmt` and ignore generated files
This commit is contained in:
@@ -1,16 +1,18 @@
|
||||
pub mod walk;
|
||||
pub mod visit;
|
||||
pub mod walk;
|
||||
|
||||
use crate::{
|
||||
SyntaxNodeRef, TextUnit, TextRange,
|
||||
text_utils::{contains_offset_nonstrict, is_subrange},
|
||||
SyntaxNodeRef, TextRange, TextUnit,
|
||||
};
|
||||
|
||||
pub fn find_leaf_at_offset(node: SyntaxNodeRef, offset: TextUnit) -> LeafAtOffset {
|
||||
let range = node.range();
|
||||
assert!(
|
||||
contains_offset_nonstrict(range, offset),
|
||||
"Bad offset: range {:?} offset {:?}", range, offset
|
||||
"Bad offset: range {:?} offset {:?}",
|
||||
range,
|
||||
offset
|
||||
);
|
||||
if range.is_empty() {
|
||||
return LeafAtOffset::None;
|
||||
@@ -20,20 +22,23 @@ pub fn find_leaf_at_offset(node: SyntaxNodeRef, offset: TextUnit) -> LeafAtOffse
|
||||
return LeafAtOffset::Single(node);
|
||||
}
|
||||
|
||||
let mut children = node.children()
|
||||
.filter(|child| {
|
||||
let child_range = child.range();
|
||||
!child_range.is_empty() && contains_offset_nonstrict(child_range, offset)
|
||||
});
|
||||
let mut children = node.children().filter(|child| {
|
||||
let child_range = child.range();
|
||||
!child_range.is_empty() && contains_offset_nonstrict(child_range, offset)
|
||||
});
|
||||
|
||||
let left = children.next().unwrap();
|
||||
let right = children.next();
|
||||
assert!(children.next().is_none());
|
||||
return if let Some(right) = right {
|
||||
match (find_leaf_at_offset(left, offset), find_leaf_at_offset(right, offset)) {
|
||||
(LeafAtOffset::Single(left), LeafAtOffset::Single(right)) =>
|
||||
LeafAtOffset::Between(left, right),
|
||||
_ => unreachable!()
|
||||
match (
|
||||
find_leaf_at_offset(left, offset),
|
||||
find_leaf_at_offset(right, offset),
|
||||
) {
|
||||
(LeafAtOffset::Single(left), LeafAtOffset::Single(right)) => {
|
||||
LeafAtOffset::Between(left, right)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
} else {
|
||||
find_leaf_at_offset(left, offset)
|
||||
@@ -44,7 +49,7 @@ pub fn find_leaf_at_offset(node: SyntaxNodeRef, offset: TextUnit) -> LeafAtOffse
|
||||
pub enum LeafAtOffset<'a> {
|
||||
None,
|
||||
Single(SyntaxNodeRef<'a>),
|
||||
Between(SyntaxNodeRef<'a>, SyntaxNodeRef<'a>)
|
||||
Between(SyntaxNodeRef<'a>, SyntaxNodeRef<'a>),
|
||||
}
|
||||
|
||||
impl<'a> LeafAtOffset<'a> {
|
||||
@@ -52,7 +57,7 @@ impl<'a> LeafAtOffset<'a> {
|
||||
match self {
|
||||
LeafAtOffset::None => None,
|
||||
LeafAtOffset::Single(node) => Some(node),
|
||||
LeafAtOffset::Between(_, right) => Some(right)
|
||||
LeafAtOffset::Between(_, right) => Some(right),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +65,7 @@ impl<'a> LeafAtOffset<'a> {
|
||||
match self {
|
||||
LeafAtOffset::None => None,
|
||||
LeafAtOffset::Single(node) => Some(node),
|
||||
LeafAtOffset::Between(left, _) => Some(left)
|
||||
LeafAtOffset::Between(left, _) => Some(left),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -71,8 +76,14 @@ impl<'f> Iterator for LeafAtOffset<'f> {
|
||||
fn next(&mut self) -> Option<SyntaxNodeRef<'f>> {
|
||||
match *self {
|
||||
LeafAtOffset::None => None,
|
||||
LeafAtOffset::Single(node) => { *self = LeafAtOffset::None; Some(node) }
|
||||
LeafAtOffset::Between(left, right) => { *self = LeafAtOffset::Single(right); Some(left) }
|
||||
LeafAtOffset::Single(node) => {
|
||||
*self = LeafAtOffset::None;
|
||||
Some(node)
|
||||
}
|
||||
LeafAtOffset::Between(left, right) => {
|
||||
*self = LeafAtOffset::Single(right);
|
||||
Some(left)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,14 +92,15 @@ pub fn find_covering_node(root: SyntaxNodeRef, range: TextRange) -> SyntaxNodeRe
|
||||
assert!(
|
||||
is_subrange(root.range(), range),
|
||||
"node range: {:?}, target range: {:?}",
|
||||
root.range(), range,
|
||||
root.range(),
|
||||
range,
|
||||
);
|
||||
let (left, right) = match (
|
||||
find_leaf_at_offset(root, range.start()).right_biased(),
|
||||
find_leaf_at_offset(root, range.end()).left_biased()
|
||||
find_leaf_at_offset(root, range.end()).left_biased(),
|
||||
) {
|
||||
(Some(l), Some(r)) => (l, r),
|
||||
_ => return root
|
||||
_ => return root,
|
||||
};
|
||||
|
||||
common_ancestor(left, right)
|
||||
@@ -103,7 +115,7 @@ fn common_ancestor<'a>(n1: SyntaxNodeRef<'a>, n2: SyntaxNodeRef<'a>) -> SyntaxNo
|
||||
panic!("Can't find common ancestor of {:?} and {:?}", n1, n2)
|
||||
}
|
||||
|
||||
pub fn generate<T>(seed: Option<T>, step: impl Fn(&T) -> Option<T>) -> impl Iterator<Item=T> {
|
||||
pub fn generate<T>(seed: Option<T>, step: impl Fn(&T) -> Option<T>) -> impl Iterator<Item = T> {
|
||||
::itertools::unfold(seed, move |slot| {
|
||||
slot.take().map(|curr| {
|
||||
*slot = step(&curr);
|
||||
|
||||
@@ -1,23 +1,31 @@
|
||||
use crate::{AstNode, SyntaxNodeRef};
|
||||
|
||||
use std::marker::PhantomData;
|
||||
use crate::{SyntaxNodeRef, AstNode};
|
||||
|
||||
|
||||
pub fn visitor<'a, T>() -> impl Visitor<'a, Output=T> {
|
||||
pub fn visitor<'a, T>() -> impl Visitor<'a, Output = T> {
|
||||
EmptyVisitor { ph: PhantomData }
|
||||
}
|
||||
|
||||
pub fn visitor_ctx<'a, T, C>(ctx: C) -> impl VisitorCtx<'a, Output=T, Ctx=C> {
|
||||
EmptyVisitorCtx { ph: PhantomData, ctx }
|
||||
pub fn visitor_ctx<'a, T, C>(ctx: C) -> impl VisitorCtx<'a, Output = T, Ctx = C> {
|
||||
EmptyVisitorCtx {
|
||||
ph: PhantomData,
|
||||
ctx,
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Visitor<'a>: Sized {
|
||||
type Output;
|
||||
fn accept(self, node: SyntaxNodeRef<'a>) -> Option<Self::Output>;
|
||||
fn visit<N, F>(self, f: F) -> Vis<Self, N, F>
|
||||
where N: AstNode<'a>,
|
||||
F: FnOnce(N) -> Self::Output,
|
||||
where
|
||||
N: AstNode<'a>,
|
||||
F: FnOnce(N) -> Self::Output,
|
||||
{
|
||||
Vis { inner: self, f, ph: PhantomData }
|
||||
Vis {
|
||||
inner: self,
|
||||
f,
|
||||
ph: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,16 +34,21 @@ pub trait VisitorCtx<'a>: Sized {
|
||||
type Ctx;
|
||||
fn accept(self, node: SyntaxNodeRef<'a>) -> Result<Self::Output, Self::Ctx>;
|
||||
fn visit<N, F>(self, f: F) -> VisCtx<Self, N, F>
|
||||
where N: AstNode<'a>,
|
||||
F: FnOnce(N, Self::Ctx) -> Self::Output,
|
||||
where
|
||||
N: AstNode<'a>,
|
||||
F: FnOnce(N, Self::Ctx) -> Self::Output,
|
||||
{
|
||||
VisCtx { inner: self, f, ph: PhantomData }
|
||||
VisCtx {
|
||||
inner: self,
|
||||
f,
|
||||
ph: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct EmptyVisitor<T> {
|
||||
ph: PhantomData<fn() -> T>
|
||||
ph: PhantomData<fn() -> T>,
|
||||
}
|
||||
|
||||
impl<'a, T> Visitor<'a> for EmptyVisitor<T> {
|
||||
@@ -69,10 +82,10 @@ pub struct Vis<V, N, F> {
|
||||
}
|
||||
|
||||
impl<'a, V, N, F> Visitor<'a> for Vis<V, N, F>
|
||||
where
|
||||
V: Visitor<'a>,
|
||||
N: AstNode<'a>,
|
||||
F: FnOnce(N) -> <V as Visitor<'a>>::Output,
|
||||
where
|
||||
V: Visitor<'a>,
|
||||
N: AstNode<'a>,
|
||||
F: FnOnce(N) -> <V as Visitor<'a>>::Output,
|
||||
{
|
||||
type Output = <V as Visitor<'a>>::Output;
|
||||
|
||||
@@ -90,21 +103,19 @@ pub struct VisCtx<V, N, F> {
|
||||
}
|
||||
|
||||
impl<'a, V, N, F> VisitorCtx<'a> for VisCtx<V, N, F>
|
||||
where
|
||||
V: VisitorCtx<'a>,
|
||||
N: AstNode<'a>,
|
||||
F: FnOnce(N, <V as VisitorCtx<'a>>::Ctx) -> <V as VisitorCtx<'a>>::Output,
|
||||
where
|
||||
V: VisitorCtx<'a>,
|
||||
N: AstNode<'a>,
|
||||
F: FnOnce(N, <V as VisitorCtx<'a>>::Ctx) -> <V as VisitorCtx<'a>>::Output,
|
||||
{
|
||||
type Output = <V as VisitorCtx<'a>>::Output;
|
||||
type Ctx = <V as VisitorCtx<'a>>::Ctx;
|
||||
|
||||
fn accept(self, node: SyntaxNodeRef<'a>) -> Result<Self::Output, Self::Ctx> {
|
||||
let VisCtx { inner, f, .. } = self;
|
||||
inner.accept(node).or_else(|ctx|
|
||||
match N::cast(node) {
|
||||
None => Err(ctx),
|
||||
Some(node) => Ok(f(node, ctx))
|
||||
}
|
||||
)
|
||||
inner.accept(node).or_else(|ctx| match N::cast(node) {
|
||||
None => Err(ctx),
|
||||
Some(node) => Ok(f(node, ctx)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
use crate::{
|
||||
SyntaxNodeRef,
|
||||
algo::generate,
|
||||
};
|
||||
|
||||
use crate::{algo::generate, SyntaxNodeRef};
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum WalkEvent<'a> {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// This file is automatically generated based on the file `./generated.rs.tera` when `cargo gen-kinds` is run
|
||||
// Do not edit manually
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
|
||||
use crate::{
|
||||
ast,
|
||||
SyntaxNodeRef, AstNode,
|
||||
|
||||
@@ -3,6 +3,8 @@ the below applies to the result of this template
|
||||
#}// This file is automatically generated based on the file `./generated.rs.tera` when `cargo gen-kinds` is run
|
||||
// Do not edit manually
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
|
||||
use crate::{
|
||||
ast,
|
||||
SyntaxNodeRef, AstNode,
|
||||
|
||||
@@ -4,15 +4,18 @@ use std::marker::PhantomData;
|
||||
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::{
|
||||
SmolStr, SyntaxNodeRef, SyntaxKind::*,
|
||||
yellow::{RefRoot, SyntaxNodeChildren},
|
||||
};
|
||||
pub use self::generated::*;
|
||||
use crate::{
|
||||
yellow::{RefRoot, SyntaxNodeChildren},
|
||||
SmolStr,
|
||||
SyntaxKind::*,
|
||||
SyntaxNodeRef,
|
||||
};
|
||||
|
||||
pub trait AstNode<'a>: Clone + Copy + 'a {
|
||||
fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self>
|
||||
where Self: Sized;
|
||||
where
|
||||
Self: Sized;
|
||||
fn syntax(self) -> SyntaxNodeRef<'a>;
|
||||
}
|
||||
|
||||
@@ -64,9 +67,7 @@ pub trait AttrsOwner<'a>: AstNode<'a> {
|
||||
|
||||
impl<'a> FnDef<'a> {
|
||||
pub fn has_atom_attr(&self, atom: &str) -> bool {
|
||||
self.attrs()
|
||||
.filter_map(|x| x.as_atom())
|
||||
.any(|x| x == atom)
|
||||
self.attrs().filter_map(|x| x.as_atom()).any(|x| x == atom)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +136,7 @@ pub enum CommentFlavor {
|
||||
Line,
|
||||
Doc,
|
||||
ModuleDoc,
|
||||
Multiline
|
||||
Multiline,
|
||||
}
|
||||
|
||||
impl CommentFlavor {
|
||||
@@ -145,7 +146,7 @@ impl CommentFlavor {
|
||||
Line => "//",
|
||||
Doc => "///",
|
||||
ModuleDoc => "//!",
|
||||
Multiline => "/*"
|
||||
Multiline => "/*",
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -166,16 +167,14 @@ impl<'a> Whitespace<'a> {
|
||||
|
||||
impl<'a> Name<'a> {
|
||||
pub fn text(&self) -> SmolStr {
|
||||
let ident = self.syntax().first_child()
|
||||
.unwrap();
|
||||
let ident = self.syntax().first_child().unwrap();
|
||||
ident.leaf_text().unwrap().clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> NameRef<'a> {
|
||||
pub fn text(&self) -> SmolStr {
|
||||
let ident = self.syntax().first_child()
|
||||
.unwrap();
|
||||
let ident = self.syntax().first_child().unwrap();
|
||||
ident.leaf_text().unwrap().clone()
|
||||
}
|
||||
}
|
||||
@@ -241,7 +240,6 @@ fn children<'a, P: AstNode<'a>, C: AstNode<'a>>(parent: P) -> AstChildren<'a, C>
|
||||
AstChildren::new(parent.syntax())
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AstChildren<'a, N> {
|
||||
inner: SyntaxNodeChildren<RefRoot<'a>>,
|
||||
|
||||
@@ -13,9 +13,18 @@ use super::*;
|
||||
// let _ = b"e";
|
||||
// let _ = br"f";
|
||||
// }
|
||||
pub(crate) const LITERAL_FIRST: TokenSet =
|
||||
token_set![TRUE_KW, FALSE_KW, INT_NUMBER, FLOAT_NUMBER, BYTE, CHAR,
|
||||
STRING, RAW_STRING, BYTE_STRING, RAW_BYTE_STRING];
|
||||
pub(crate) const LITERAL_FIRST: TokenSet = token_set![
|
||||
TRUE_KW,
|
||||
FALSE_KW,
|
||||
INT_NUMBER,
|
||||
FLOAT_NUMBER,
|
||||
BYTE,
|
||||
CHAR,
|
||||
STRING,
|
||||
RAW_STRING,
|
||||
BYTE_STRING,
|
||||
RAW_BYTE_STRING
|
||||
];
|
||||
|
||||
pub(crate) fn literal(p: &mut Parser) -> Option<CompletedMarker> {
|
||||
if !p.at_ts(LITERAL_FIRST) {
|
||||
@@ -26,15 +35,31 @@ pub(crate) fn literal(p: &mut Parser) -> Option<CompletedMarker> {
|
||||
Some(m.complete(p, LITERAL))
|
||||
}
|
||||
|
||||
pub(super) const ATOM_EXPR_FIRST: TokenSet =
|
||||
token_set_union![
|
||||
LITERAL_FIRST,
|
||||
token_set![L_CURLY, L_PAREN, L_BRACK, PIPE, MOVE_KW, IF_KW, WHILE_KW, MATCH_KW, UNSAFE_KW,
|
||||
RETURN_KW, IDENT, SELF_KW, SUPER_KW, CRATE_KW, COLONCOLON, BREAK_KW, CONTINUE_KW, LIFETIME ],
|
||||
];
|
||||
pub(super) const ATOM_EXPR_FIRST: TokenSet = token_set_union![
|
||||
LITERAL_FIRST,
|
||||
token_set![
|
||||
L_CURLY,
|
||||
L_PAREN,
|
||||
L_BRACK,
|
||||
PIPE,
|
||||
MOVE_KW,
|
||||
IF_KW,
|
||||
WHILE_KW,
|
||||
MATCH_KW,
|
||||
UNSAFE_KW,
|
||||
RETURN_KW,
|
||||
IDENT,
|
||||
SELF_KW,
|
||||
SUPER_KW,
|
||||
CRATE_KW,
|
||||
COLONCOLON,
|
||||
BREAK_KW,
|
||||
CONTINUE_KW,
|
||||
LIFETIME
|
||||
],
|
||||
];
|
||||
|
||||
const EXPR_RECOVERY_SET: TokenSet =
|
||||
token_set![LET_KW];
|
||||
const EXPR_RECOVERY_SET: TokenSet = token_set![LET_KW];
|
||||
|
||||
pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<CompletedMarker> {
|
||||
match literal(p) {
|
||||
@@ -80,7 +105,7 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<CompletedMark
|
||||
let m = p.start();
|
||||
p.bump();
|
||||
block_expr(p, Some(m))
|
||||
},
|
||||
}
|
||||
L_CURLY => block_expr(p, None),
|
||||
RETURN_KW => return_expr(p),
|
||||
CONTINUE_KW => continue_expr(p),
|
||||
@@ -119,7 +144,14 @@ fn tuple_expr(p: &mut Parser) -> CompletedMarker {
|
||||
}
|
||||
}
|
||||
p.expect(R_PAREN);
|
||||
m.complete(p, if saw_expr && !saw_comma { PAREN_EXPR } else { TUPLE_EXPR })
|
||||
m.complete(
|
||||
p,
|
||||
if saw_expr && !saw_comma {
|
||||
PAREN_EXPR
|
||||
} else {
|
||||
TUPLE_EXPR
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// test array_expr
|
||||
|
||||
@@ -1,23 +1,32 @@
|
||||
mod atom;
|
||||
|
||||
use super::*;
|
||||
pub(super) use self::atom::{literal, LITERAL_FIRST};
|
||||
pub(crate) use self::atom::match_arm_list;
|
||||
pub(super) use self::atom::{literal, LITERAL_FIRST};
|
||||
use super::*;
|
||||
|
||||
const EXPR_FIRST: TokenSet = LHS_FIRST;
|
||||
|
||||
pub(super) fn expr(p: &mut Parser) -> BlockLike {
|
||||
let r = Restrictions { forbid_structs: false, prefer_stmt: false };
|
||||
let r = Restrictions {
|
||||
forbid_structs: false,
|
||||
prefer_stmt: false,
|
||||
};
|
||||
expr_bp(p, r, 1)
|
||||
}
|
||||
|
||||
pub(super) fn expr_stmt(p: &mut Parser) -> BlockLike {
|
||||
let r = Restrictions { forbid_structs: false, prefer_stmt: true };
|
||||
let r = Restrictions {
|
||||
forbid_structs: false,
|
||||
prefer_stmt: true,
|
||||
};
|
||||
expr_bp(p, r, 1)
|
||||
}
|
||||
|
||||
fn expr_no_struct(p: &mut Parser) {
|
||||
let r = Restrictions { forbid_structs: true, prefer_stmt: false };
|
||||
let r = Restrictions {
|
||||
forbid_structs: true,
|
||||
prefer_stmt: false,
|
||||
};
|
||||
expr_bp(p, r, 1);
|
||||
}
|
||||
|
||||
@@ -107,10 +116,8 @@ enum Op {
|
||||
fn current_op(p: &Parser) -> (u8, Op) {
|
||||
if let Some(t) = p.next3() {
|
||||
match t {
|
||||
(L_ANGLE, L_ANGLE, EQ) =>
|
||||
return (1, Op::Composite(SHLEQ, 3)),
|
||||
(R_ANGLE, R_ANGLE, EQ) =>
|
||||
return (1, Op::Composite(SHREQ, 3)),
|
||||
(L_ANGLE, L_ANGLE, EQ) => return (1, Op::Composite(SHLEQ, 3)),
|
||||
(R_ANGLE, R_ANGLE, EQ) => return (1, Op::Composite(SHREQ, 3)),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
@@ -201,11 +208,10 @@ fn is_block(kind: SyntaxKind) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
const LHS_FIRST: TokenSet =
|
||||
token_set_union![
|
||||
token_set![AMP, STAR, EXCL, DOTDOT, MINUS],
|
||||
atom::ATOM_EXPR_FIRST,
|
||||
];
|
||||
const LHS_FIRST: TokenSet = token_set_union![
|
||||
token_set![AMP, STAR, EXCL, DOTDOT, MINUS],
|
||||
atom::ATOM_EXPR_FIRST,
|
||||
];
|
||||
|
||||
fn lhs(p: &mut Parser, r: Restrictions) -> Option<CompletedMarker> {
|
||||
let m;
|
||||
@@ -265,11 +271,13 @@ fn postfix_expr(p: &mut Parser, r: Restrictions, mut lhs: CompletedMarker) -> Co
|
||||
// }
|
||||
L_PAREN if allow_calls => call_expr(p, lhs),
|
||||
L_BRACK if allow_calls => index_expr(p, lhs),
|
||||
DOT if p.nth(1) == IDENT => if p.nth(2) == L_PAREN || p.nth(2) == COLONCOLON {
|
||||
method_call_expr(p, lhs)
|
||||
} else {
|
||||
field_expr(p, lhs)
|
||||
},
|
||||
DOT if p.nth(1) == IDENT => {
|
||||
if p.nth(2) == L_PAREN || p.nth(2) == COLONCOLON {
|
||||
method_call_expr(p, lhs)
|
||||
} else {
|
||||
field_expr(p, lhs)
|
||||
}
|
||||
}
|
||||
DOT if p.nth(1) == INT_NUMBER => field_expr(p, lhs),
|
||||
// test postfix_range
|
||||
// fn foo() { let x = 1..; }
|
||||
@@ -318,10 +326,7 @@ fn index_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
|
||||
// y.bar::<T>(1, 2,);
|
||||
// }
|
||||
fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
|
||||
assert!(
|
||||
p.at(DOT) && p.nth(1) == IDENT
|
||||
&& (p.nth(2) == L_PAREN || p.nth(2) == COLONCOLON)
|
||||
);
|
||||
assert!(p.at(DOT) && p.nth(1) == IDENT && (p.nth(2) == L_PAREN || p.nth(2) == COLONCOLON));
|
||||
let m = lhs.precede(p);
|
||||
p.bump();
|
||||
name_ref(p);
|
||||
@@ -410,7 +415,7 @@ fn path_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker {
|
||||
items::macro_call_after_excl(p);
|
||||
m.complete(p, MACRO_CALL)
|
||||
}
|
||||
_ => m.complete(p, PATH_EXPR)
|
||||
_ => m.complete(p, PATH_EXPR),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
|
||||
mod consts;
|
||||
mod nominal;
|
||||
mod traits;
|
||||
mod use_item;
|
||||
|
||||
use super::*;
|
||||
pub(crate) use self::{
|
||||
expressions::{named_field_list, match_arm_list},
|
||||
expressions::{match_arm_list, named_field_list},
|
||||
nominal::{enum_variant_list, named_field_def_list},
|
||||
traits::{trait_item_list, impl_item_list},
|
||||
traits::{impl_item_list, trait_item_list},
|
||||
use_item::use_tree_list,
|
||||
};
|
||||
use super::*;
|
||||
|
||||
// test mod_contents
|
||||
// fn foo() {}
|
||||
@@ -26,12 +25,14 @@ pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) {
|
||||
}
|
||||
|
||||
pub(super) enum ItemFlavor {
|
||||
Mod, Trait
|
||||
Mod,
|
||||
Trait,
|
||||
}
|
||||
|
||||
const ITEM_RECOVERY_SET: TokenSet =
|
||||
token_set![FN_KW, STRUCT_KW, ENUM_KW, IMPL_KW, TRAIT_KW, CONST_KW, STATIC_KW, LET_KW,
|
||||
MOD_KW, PUB_KW, CRATE_KW];
|
||||
const ITEM_RECOVERY_SET: TokenSet = token_set![
|
||||
FN_KW, STRUCT_KW, ENUM_KW, IMPL_KW, TRAIT_KW, CONST_KW, STATIC_KW, LET_KW, MOD_KW, PUB_KW,
|
||||
CRATE_KW
|
||||
];
|
||||
|
||||
pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool, flavor: ItemFlavor) {
|
||||
let m = p.start();
|
||||
@@ -153,10 +154,12 @@ pub(super) fn maybe_item(p: &mut Parser, flavor: ItemFlavor) -> MaybeItem {
|
||||
traits::impl_item(p);
|
||||
IMPL_ITEM
|
||||
}
|
||||
_ => return if has_mods {
|
||||
MaybeItem::Modifiers
|
||||
} else {
|
||||
MaybeItem::None
|
||||
_ => {
|
||||
return if has_mods {
|
||||
MaybeItem::Modifiers
|
||||
} else {
|
||||
MaybeItem::None
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -194,7 +197,7 @@ fn items_without_modifiers(p: &mut Parser) -> Option<SyntaxKind> {
|
||||
if p.at(SEMI) {
|
||||
p.err_and_bump(
|
||||
"expected item, found `;`\n\
|
||||
consider removing this semicolon"
|
||||
consider removing this semicolon",
|
||||
);
|
||||
}
|
||||
STRUCT_DEF
|
||||
@@ -227,7 +230,9 @@ fn items_without_modifiers(p: &mut Parser) -> Option<SyntaxKind> {
|
||||
}
|
||||
// test extern_block
|
||||
// extern {}
|
||||
EXTERN_KW if la == L_CURLY || ((la == STRING || la == RAW_STRING) && p.nth(2) == L_CURLY) => {
|
||||
EXTERN_KW
|
||||
if la == L_CURLY || ((la == STRING || la == RAW_STRING) && p.nth(2) == L_CURLY) =>
|
||||
{
|
||||
abi(p);
|
||||
extern_item_list(p);
|
||||
EXTERN_BLOCK
|
||||
@@ -267,10 +272,8 @@ fn fn_def(p: &mut Parser, flavor: ItemFlavor) {
|
||||
|
||||
if p.at(L_PAREN) {
|
||||
match flavor {
|
||||
ItemFlavor::Mod =>
|
||||
params::param_list(p),
|
||||
ItemFlavor::Trait =>
|
||||
params::param_list_opt_patterns(p),
|
||||
ItemFlavor::Mod => params::param_list(p),
|
||||
ItemFlavor::Trait => params::param_list_opt_patterns(p),
|
||||
}
|
||||
} else {
|
||||
p.error("expected function arguments");
|
||||
@@ -361,7 +364,7 @@ pub(super) fn macro_call_after_excl(p: &mut Parser) -> BlockLike {
|
||||
_ => {
|
||||
p.error("expected `{`, `[`, `(`");
|
||||
BlockLike::NotBlock
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
flavor
|
||||
@@ -385,9 +388,9 @@ pub(crate) fn token_tree(p: &mut Parser) {
|
||||
return;
|
||||
}
|
||||
R_PAREN | R_BRACK => p.err_and_bump("unmatched brace"),
|
||||
_ => p.bump()
|
||||
_ => p.bump(),
|
||||
}
|
||||
};
|
||||
}
|
||||
p.expect(closing_paren_kind);
|
||||
m.complete(p, TOKEN_TREE);
|
||||
}
|
||||
|
||||
@@ -128,4 +128,3 @@ pub(crate) fn impl_type(p: &mut Parser) {
|
||||
}
|
||||
types::type_(p);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,28 +31,18 @@ mod type_args;
|
||||
mod type_params;
|
||||
mod types;
|
||||
|
||||
use crate::{
|
||||
token_set::TokenSet,
|
||||
parser_api::{Marker, CompletedMarker, Parser},
|
||||
SyntaxKind::{self, *},
|
||||
};
|
||||
pub(crate) use self::{
|
||||
expressions::{
|
||||
block,
|
||||
},
|
||||
expressions::block,
|
||||
items::{
|
||||
enum_variant_list,
|
||||
extern_item_list,
|
||||
impl_item_list,
|
||||
match_arm_list,
|
||||
mod_item_list,
|
||||
named_field_def_list,
|
||||
named_field_list,
|
||||
token_tree,
|
||||
trait_item_list,
|
||||
use_tree_list,
|
||||
enum_variant_list, extern_item_list, impl_item_list, match_arm_list, mod_item_list,
|
||||
named_field_def_list, named_field_list, token_tree, trait_item_list, use_tree_list,
|
||||
},
|
||||
};
|
||||
use crate::{
|
||||
parser_api::{CompletedMarker, Marker, Parser},
|
||||
token_set::TokenSet,
|
||||
SyntaxKind::{self, *},
|
||||
};
|
||||
|
||||
pub(crate) fn root(p: &mut Parser) {
|
||||
let m = p.start();
|
||||
@@ -61,7 +51,6 @@ pub(crate) fn root(p: &mut Parser) {
|
||||
m.complete(p, ROOT);
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
enum BlockLike {
|
||||
Block,
|
||||
@@ -69,7 +58,9 @@ enum BlockLike {
|
||||
}
|
||||
|
||||
impl BlockLike {
|
||||
fn is_block(self) -> bool { self == BlockLike::Block }
|
||||
fn is_block(self) -> bool {
|
||||
self == BlockLike::Block
|
||||
}
|
||||
}
|
||||
|
||||
fn opt_visibility(p: &mut Parser) {
|
||||
|
||||
@@ -61,12 +61,8 @@ fn list_(p: &mut Parser, flavor: Flavor) {
|
||||
m.complete(p, PARAM_LIST);
|
||||
}
|
||||
|
||||
|
||||
const VALUE_PARAMETER_FIRST: TokenSet =
|
||||
token_set_union![
|
||||
patterns::PATTERN_FIRST,
|
||||
types::TYPE_FIRST,
|
||||
];
|
||||
token_set_union![patterns::PATTERN_FIRST, types::TYPE_FIRST,];
|
||||
|
||||
fn value_parameter(p: &mut Parser, flavor: Flavor) {
|
||||
let m = p.start();
|
||||
@@ -76,7 +72,7 @@ fn value_parameter(p: &mut Parser, flavor: Flavor) {
|
||||
if p.at(COLON) || flavor.type_required() {
|
||||
types::ascription(p)
|
||||
}
|
||||
},
|
||||
}
|
||||
// test value_parameters_no_patterns
|
||||
// type F = Box<Fn(a: i32, &b: &i32, &mut c: &i32, ())>;
|
||||
Flavor::OptionalPattern => {
|
||||
@@ -86,13 +82,14 @@ fn value_parameter(p: &mut Parser, flavor: Flavor) {
|
||||
let la3 = p.nth(3);
|
||||
if la0 == IDENT && la1 == COLON
|
||||
|| la0 == AMP && la1 == IDENT && la2 == COLON
|
||||
|| la0 == AMP && la1 == MUT_KW && la2 == IDENT && la3 == COLON {
|
||||
|| la0 == AMP && la1 == MUT_KW && la2 == IDENT && la3 == COLON
|
||||
{
|
||||
patterns::pattern(p);
|
||||
types::ascription(p);
|
||||
} else {
|
||||
types::type_(p);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
m.complete(p, PARAM);
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ fn opt_path_type_args(p: &mut Parser, mode: Mode) {
|
||||
} else {
|
||||
type_args::opt_type_arg_list(p, false)
|
||||
}
|
||||
},
|
||||
}
|
||||
Mode::Expr => type_args::opt_type_arg_list(p, true),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
use super::*;
|
||||
|
||||
pub(super) const PATTERN_FIRST: TokenSet =
|
||||
token_set_union![
|
||||
token_set![REF_KW, MUT_KW, L_PAREN, L_BRACK, AMP, UNDERSCORE],
|
||||
expressions::LITERAL_FIRST,
|
||||
paths::PATH_FIRST,
|
||||
];
|
||||
pub(super) const PATTERN_FIRST: TokenSet = token_set_union![
|
||||
token_set![REF_KW, MUT_KW, L_PAREN, L_BRACK, AMP, UNDERSCORE],
|
||||
expressions::LITERAL_FIRST,
|
||||
paths::PATH_FIRST,
|
||||
];
|
||||
|
||||
pub(super) fn pattern(p: &mut Parser) {
|
||||
pattern_r(p, PAT_RECOVERY_SET)
|
||||
@@ -29,12 +28,13 @@ pub(super) fn pattern_r(p: &mut Parser, recovery_set: TokenSet) {
|
||||
const PAT_RECOVERY_SET: TokenSet =
|
||||
token_set![LET_KW, IF_KW, WHILE_KW, LOOP_KW, MATCH_KW, R_PAREN, COMMA];
|
||||
|
||||
|
||||
fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> {
|
||||
let la0 = p.nth(0);
|
||||
let la1 = p.nth(1);
|
||||
if la0 == REF_KW || la0 == MUT_KW
|
||||
|| (la0 == IDENT && !(la1 == COLONCOLON || la1 == L_PAREN || la1 == L_CURLY)) {
|
||||
if la0 == REF_KW
|
||||
|| la0 == MUT_KW
|
||||
|| (la0 == IDENT && !(la1 == COLONCOLON || la1 == L_PAREN || la1 == L_CURLY))
|
||||
{
|
||||
return Some(bind_pat(p, true));
|
||||
}
|
||||
if paths::is_path_start(p) {
|
||||
@@ -87,7 +87,7 @@ fn path_pat(p: &mut Parser) -> CompletedMarker {
|
||||
field_pat_list(p);
|
||||
STRUCT_PAT
|
||||
}
|
||||
_ => PATH_PAT
|
||||
_ => PATH_PAT,
|
||||
};
|
||||
m.complete(p, kind)
|
||||
}
|
||||
@@ -195,7 +195,7 @@ fn pat_list(p: &mut Parser, ket: SyntaxKind) {
|
||||
break;
|
||||
}
|
||||
pattern(p)
|
||||
},
|
||||
}
|
||||
}
|
||||
if !p.at(ket) {
|
||||
p.expect(COMMA);
|
||||
|
||||
@@ -72,12 +72,8 @@ pub(super) fn bounds_without_colon(p: &mut Parser) {
|
||||
p.eat(QUESTION);
|
||||
match p.current() {
|
||||
LIFETIME => p.bump(),
|
||||
FOR_KW => {
|
||||
types::for_type(p)
|
||||
}
|
||||
_ if paths::is_path_start(p) => {
|
||||
types::path_type(p)
|
||||
}
|
||||
FOR_KW => types::for_type(p),
|
||||
_ if paths::is_path_start(p) => types::path_type(p),
|
||||
_ => break,
|
||||
}
|
||||
if has_paren {
|
||||
@@ -104,7 +100,7 @@ pub(super) fn opt_where_clause(p: &mut Parser) {
|
||||
p.bump();
|
||||
loop {
|
||||
if !(paths::is_path_start(p) || p.current() == LIFETIME) {
|
||||
break
|
||||
break;
|
||||
}
|
||||
where_predicate(p);
|
||||
if p.current() != L_CURLY && p.current() != SEMI {
|
||||
@@ -130,7 +126,6 @@ fn where_predicate(p: &mut Parser) {
|
||||
} else {
|
||||
p.error("expected colon")
|
||||
}
|
||||
|
||||
}
|
||||
m.complete(p, WHERE_PRED);
|
||||
}
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
use super::*;
|
||||
|
||||
pub(super) const TYPE_FIRST: TokenSet =
|
||||
token_set_union![
|
||||
token_set![
|
||||
L_PAREN, EXCL, STAR, L_BRACK, AMP, UNDERSCORE, FN_KW, UNSAFE_KW, EXTERN_KW, FOR_KW, IMPL_KW, DYN_KW, L_ANGLE,
|
||||
],
|
||||
paths::PATH_FIRST,
|
||||
];
|
||||
pub(super) const TYPE_FIRST: TokenSet = token_set_union![
|
||||
token_set![
|
||||
L_PAREN, EXCL, STAR, L_BRACK, AMP, UNDERSCORE, FN_KW, UNSAFE_KW, EXTERN_KW, FOR_KW,
|
||||
IMPL_KW, DYN_KW, L_ANGLE,
|
||||
],
|
||||
paths::PATH_FIRST,
|
||||
];
|
||||
|
||||
const TYPE_RECOVERY_SET: TokenSet =
|
||||
token_set![R_PAREN, COMMA];
|
||||
const TYPE_RECOVERY_SET: TokenSet = token_set![R_PAREN, COMMA];
|
||||
|
||||
pub(super) fn type_(p: &mut Parser) {
|
||||
match p.current() {
|
||||
@@ -200,7 +199,6 @@ pub(super) fn for_type(p: &mut Parser) {
|
||||
FN_KW | UNSAFE_KW | EXTERN_KW => fn_pointer_type(p),
|
||||
_ if paths::is_path_start(p) => path_type_(p, false),
|
||||
_ => p.error("expected a path"),
|
||||
|
||||
}
|
||||
m.complete(p, FOR_TYPE);
|
||||
}
|
||||
|
||||
@@ -58,12 +58,16 @@ fn next_token_inner(c: char, ptr: &mut Ptr) -> SyntaxKind {
|
||||
}
|
||||
|
||||
match c {
|
||||
'#' => if scan_shebang(ptr) {
|
||||
return SHEBANG;
|
||||
},
|
||||
'/' => if let Some(kind) = scan_comment(ptr) {
|
||||
return kind;
|
||||
},
|
||||
'#' => {
|
||||
if scan_shebang(ptr) {
|
||||
return SHEBANG;
|
||||
}
|
||||
}
|
||||
'/' => {
|
||||
if let Some(kind) = scan_comment(ptr) {
|
||||
return kind;
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
|
||||
@@ -134,10 +134,10 @@ mod tests {
|
||||
#[test]
|
||||
fn test_nth_is_p() {
|
||||
let ptr = Ptr::new("test");
|
||||
assert!(ptr.nth_is_p(0,|c| c == 't'));
|
||||
assert!(!ptr.nth_is_p(1,|c| c == 't'));
|
||||
assert!(ptr.nth_is_p(3,|c| c == 't'));
|
||||
assert!(!ptr.nth_is_p(150,|c| c == 't'));
|
||||
assert!(ptr.nth_is_p(0, |c| c == 't'));
|
||||
assert!(!ptr.nth_is_p(1, |c| c == 't'));
|
||||
assert!(ptr.nth_is_p(3, |c| c == 't'));
|
||||
assert!(!ptr.nth_is_p(150, |c| c == 't'));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -71,7 +71,7 @@ pub(crate) fn scan_string(ptr: &mut Ptr) {
|
||||
}
|
||||
_ => {
|
||||
ptr.bump();
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -90,7 +90,7 @@ pub(crate) fn scan_raw_string(ptr: &mut Ptr) {
|
||||
while let Some(c) = ptr.bump() {
|
||||
if c == '"' {
|
||||
let mut hashes_left = hashes;
|
||||
while ptr.at('#') && hashes_left > 0{
|
||||
while ptr.at('#') && hashes_left > 0 {
|
||||
hashes_left -= 1;
|
||||
ptr.bump();
|
||||
}
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
#![allow(missing_docs)]
|
||||
//#![warn(unreachable_pub)] // rust-lang/rust#47816
|
||||
|
||||
extern crate itertools;
|
||||
extern crate unicode_xid;
|
||||
extern crate drop_bomb;
|
||||
extern crate itertools;
|
||||
extern crate parking_lot;
|
||||
extern crate rowan;
|
||||
extern crate unicode_xid;
|
||||
|
||||
#[cfg(test)]
|
||||
#[macro_use]
|
||||
@@ -35,33 +35,31 @@ pub mod ast;
|
||||
mod lexer;
|
||||
#[macro_use]
|
||||
mod token_set;
|
||||
mod parser_api;
|
||||
mod grammar;
|
||||
mod parser_api;
|
||||
mod parser_impl;
|
||||
mod reparsing;
|
||||
|
||||
mod syntax_kinds;
|
||||
mod yellow;
|
||||
pub mod text_utils;
|
||||
/// Utilities for simple uses of the parser.
|
||||
pub mod utils;
|
||||
pub mod text_utils;
|
||||
mod yellow;
|
||||
|
||||
pub use crate::{
|
||||
rowan::{SmolStr, TextRange, TextUnit},
|
||||
ast::AstNode,
|
||||
lexer::{tokenize, Token},
|
||||
syntax_kinds::SyntaxKind,
|
||||
yellow::{SyntaxNode, SyntaxNodeRef, OwnedRoot, RefRoot, TreeRoot, SyntaxError, Direction},
|
||||
reparsing::AtomEdit,
|
||||
rowan::{SmolStr, TextRange, TextUnit},
|
||||
syntax_kinds::SyntaxKind,
|
||||
yellow::{Direction, OwnedRoot, RefRoot, SyntaxError, SyntaxNode, SyntaxNodeRef, TreeRoot},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
yellow::{GreenNode},
|
||||
};
|
||||
use crate::yellow::GreenNode;
|
||||
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||
pub struct File {
|
||||
root: SyntaxNode
|
||||
root: SyntaxNode,
|
||||
}
|
||||
|
||||
impl File {
|
||||
@@ -74,21 +72,21 @@ impl File {
|
||||
}
|
||||
pub fn parse(text: &str) -> File {
|
||||
let tokens = tokenize(&text);
|
||||
let (green, errors) = parser_impl::parse_with(
|
||||
yellow::GreenBuilder::new(),
|
||||
text, &tokens, grammar::root,
|
||||
);
|
||||
let (green, errors) =
|
||||
parser_impl::parse_with(yellow::GreenBuilder::new(), text, &tokens, grammar::root);
|
||||
File::new(green, errors)
|
||||
}
|
||||
pub fn reparse(&self, edit: &AtomEdit) -> File {
|
||||
self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit))
|
||||
self.incremental_reparse(edit)
|
||||
.unwrap_or_else(|| self.full_reparse(edit))
|
||||
}
|
||||
pub fn incremental_reparse(&self, edit: &AtomEdit) -> Option<File> {
|
||||
reparsing::incremental_reparse(self.syntax(), edit, self.errors())
|
||||
.map(|(green_node, errors)| File::new(green_node, errors))
|
||||
}
|
||||
fn full_reparse(&self, edit: &AtomEdit) -> File {
|
||||
let text = text_utils::replace_range(self.syntax().text().to_string(), edit.delete, &edit.insert);
|
||||
let text =
|
||||
text_utils::replace_range(self.syntax().text().to_string(), edit.delete, &edit.insert);
|
||||
File::parse(&text)
|
||||
}
|
||||
pub fn ast(&self) -> ast::Root {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use crate::{
|
||||
token_set::TokenSet,
|
||||
parser_impl::ParserImpl,
|
||||
SyntaxKind::{self, ERROR},
|
||||
drop_bomb::DropBomb,
|
||||
parser_impl::ParserImpl,
|
||||
token_set::TokenSet,
|
||||
SyntaxKind::{self, ERROR},
|
||||
};
|
||||
|
||||
/// `Parser` struct provides the low-level API for
|
||||
@@ -116,9 +116,7 @@ impl<'t> Parser<'t> {
|
||||
|
||||
/// Create an error node and consume the next token.
|
||||
pub(crate) fn err_recover(&mut self, message: &str, recovery: TokenSet) {
|
||||
if self.at(SyntaxKind::L_CURLY)
|
||||
|| self.at(SyntaxKind::R_CURLY)
|
||||
|| self.at_ts(recovery) {
|
||||
if self.at(SyntaxKind::L_CURLY) || self.at(SyntaxKind::R_CURLY) || self.at_ts(recovery) {
|
||||
self.error(message);
|
||||
} else {
|
||||
let m = self.start();
|
||||
|
||||
@@ -7,14 +7,14 @@
|
||||
//! tree builder: the parser produces a stream of events like
|
||||
//! `start node`, `finish node`, and `FileBuilder` converts
|
||||
//! this stream to a real tree.
|
||||
use std::mem;
|
||||
use crate::{
|
||||
TextUnit, TextRange, SmolStr,
|
||||
lexer::Token,
|
||||
parser_impl::Sink,
|
||||
SmolStr,
|
||||
SyntaxKind::{self, *},
|
||||
TextRange, TextUnit,
|
||||
};
|
||||
|
||||
use std::mem;
|
||||
|
||||
/// `Parser` produces a flat list of `Event`s.
|
||||
/// They are converted to a tree-structure in
|
||||
@@ -89,20 +89,28 @@ pub(super) struct EventProcessor<'a, S: Sink> {
|
||||
}
|
||||
|
||||
impl<'a, S: Sink> EventProcessor<'a, S> {
|
||||
pub(super) fn new(sink: S, text: &'a str, tokens: &'a[Token], events: &'a mut [Event]) -> EventProcessor<'a, S> {
|
||||
pub(super) fn new(
|
||||
sink: S,
|
||||
text: &'a str,
|
||||
tokens: &'a [Token],
|
||||
events: &'a mut [Event],
|
||||
) -> EventProcessor<'a, S> {
|
||||
EventProcessor {
|
||||
sink,
|
||||
text_pos: 0.into(),
|
||||
text,
|
||||
token_pos: 0,
|
||||
tokens,
|
||||
events
|
||||
events,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn process(mut self) -> S {
|
||||
fn tombstone() -> Event {
|
||||
Event::Start { kind: TOMBSTONE, forward_parent: None }
|
||||
Event::Start {
|
||||
kind: TOMBSTONE,
|
||||
forward_parent: None,
|
||||
}
|
||||
}
|
||||
let mut forward_parents = Vec::new();
|
||||
|
||||
@@ -112,7 +120,10 @@ impl<'a, S: Sink> EventProcessor<'a, S> {
|
||||
kind: TOMBSTONE, ..
|
||||
} => (),
|
||||
|
||||
Event::Start { kind, forward_parent } => {
|
||||
Event::Start {
|
||||
kind,
|
||||
forward_parent,
|
||||
} => {
|
||||
forward_parents.push(kind);
|
||||
let mut idx = i;
|
||||
let mut fp = forward_parent;
|
||||
@@ -125,7 +136,7 @@ impl<'a, S: Sink> EventProcessor<'a, S> {
|
||||
} => {
|
||||
forward_parents.push(kind);
|
||||
forward_parent
|
||||
},
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
}
|
||||
@@ -136,7 +147,7 @@ impl<'a, S: Sink> EventProcessor<'a, S> {
|
||||
Event::Finish => {
|
||||
let last = i == self.events.len() - 1;
|
||||
self.finish(last);
|
||||
},
|
||||
}
|
||||
Event::Token { kind, n_raw_tokens } => {
|
||||
self.eat_ws();
|
||||
let n_raw_tokens = n_raw_tokens as usize;
|
||||
@@ -162,19 +173,16 @@ impl<'a, S: Sink> EventProcessor<'a, S> {
|
||||
.take_while(|it| it.kind.is_trivia())
|
||||
.count();
|
||||
let leading_trivias = &self.tokens[self.token_pos..self.token_pos + n_trivias];
|
||||
let mut trivia_end = self.text_pos + leading_trivias
|
||||
.iter()
|
||||
.map(|it| it.len)
|
||||
.sum::<TextUnit>();
|
||||
let mut trivia_end =
|
||||
self.text_pos + leading_trivias.iter().map(|it| it.len).sum::<TextUnit>();
|
||||
|
||||
let n_attached_trivias = {
|
||||
let leading_trivias = leading_trivias.iter().rev()
|
||||
.map(|it| {
|
||||
let next_end = trivia_end - it.len;
|
||||
let range = TextRange::from_to(next_end, trivia_end);
|
||||
trivia_end = next_end;
|
||||
(it.kind, &self.text[range])
|
||||
});
|
||||
let leading_trivias = leading_trivias.iter().rev().map(|it| {
|
||||
let next_end = trivia_end - it.len;
|
||||
let range = TextRange::from_to(next_end, trivia_end);
|
||||
trivia_end = next_end;
|
||||
(it.kind, &self.text[range])
|
||||
});
|
||||
n_attached_trivias(kind, leading_trivias)
|
||||
};
|
||||
self.eat_n_trivias(n_trivias - n_attached_trivias);
|
||||
@@ -215,7 +223,10 @@ impl<'a, S: Sink> EventProcessor<'a, S> {
|
||||
}
|
||||
}
|
||||
|
||||
fn n_attached_trivias<'a>(kind: SyntaxKind, trivias: impl Iterator<Item=(SyntaxKind, &'a str)>) -> usize {
|
||||
fn n_attached_trivias<'a>(
|
||||
kind: SyntaxKind,
|
||||
trivias: impl Iterator<Item = (SyntaxKind, &'a str)>,
|
||||
) -> usize {
|
||||
match kind {
|
||||
STRUCT_DEF | ENUM_DEF | FN_DEF | TRAIT_DEF | MODULE => {
|
||||
let mut res = 0;
|
||||
@@ -236,5 +247,4 @@ fn n_attached_trivias<'a>(kind: SyntaxKind, trivias: impl Iterator<Item=(SyntaxK
|
||||
}
|
||||
_ => 0,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,13 +4,13 @@ mod input;
|
||||
use std::cell::Cell;
|
||||
|
||||
use crate::{
|
||||
TextUnit, SmolStr,
|
||||
lexer::Token,
|
||||
parser_api::Parser,
|
||||
parser_impl::{
|
||||
event::{EventProcessor, Event},
|
||||
event::{Event, EventProcessor},
|
||||
input::{InputPosition, ParserInput},
|
||||
},
|
||||
SmolStr, TextUnit,
|
||||
};
|
||||
|
||||
use crate::SyntaxKind::{self, EOF, TOMBSTONE};
|
||||
@@ -86,7 +86,9 @@ impl<'t> ParserImpl<'t> {
|
||||
let c2 = self.inp.kind(self.pos + 1);
|
||||
let c3 = self.inp.kind(self.pos + 2);
|
||||
if self.inp.start(self.pos + 1) == self.inp.start(self.pos) + self.inp.len(self.pos)
|
||||
&& self.inp.start(self.pos + 2) == self.inp.start(self.pos + 1) + self.inp.len(self.pos + 1){
|
||||
&& self.inp.start(self.pos + 2)
|
||||
== self.inp.start(self.pos + 1) + self.inp.len(self.pos + 1)
|
||||
{
|
||||
Some((c1, c2, c3))
|
||||
} else {
|
||||
None
|
||||
@@ -138,10 +140,7 @@ impl<'t> ParserImpl<'t> {
|
||||
|
||||
fn do_bump(&mut self, kind: SyntaxKind, n_raw_tokens: u8) {
|
||||
self.pos += u32::from(n_raw_tokens);
|
||||
self.event(Event::Token {
|
||||
kind,
|
||||
n_raw_tokens,
|
||||
});
|
||||
self.event(Event::Token { kind, n_raw_tokens });
|
||||
}
|
||||
|
||||
pub(super) fn error(&mut self, msg: String) {
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
use crate::algo;
|
||||
use crate::grammar;
|
||||
use crate::lexer::{tokenize, Token};
|
||||
use crate::yellow::{self, GreenNode, SyntaxNodeRef, SyntaxError};
|
||||
use crate::parser_impl;
|
||||
use crate::parser_api::Parser;
|
||||
use crate::{
|
||||
TextUnit, TextRange,
|
||||
SyntaxKind::*,
|
||||
};
|
||||
use crate::parser_impl;
|
||||
use crate::text_utils::replace_range;
|
||||
use crate::yellow::{self, GreenNode, SyntaxError, SyntaxNodeRef};
|
||||
use crate::{SyntaxKind::*, TextRange, TextUnit};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AtomEdit {
|
||||
@@ -18,7 +15,10 @@ pub struct AtomEdit {
|
||||
|
||||
impl AtomEdit {
|
||||
pub fn replace(range: TextRange, replace_with: String) -> AtomEdit {
|
||||
AtomEdit { delete: range, insert: replace_with }
|
||||
AtomEdit {
|
||||
delete: range,
|
||||
insert: replace_with,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delete(range: TextRange) -> AtomEdit {
|
||||
@@ -48,12 +48,7 @@ fn reparse_leaf<'node>(
|
||||
) -> Option<(SyntaxNodeRef<'node>, GreenNode, Vec<SyntaxError>)> {
|
||||
let node = algo::find_covering_node(node, edit.delete);
|
||||
match node.kind() {
|
||||
| WHITESPACE
|
||||
| COMMENT
|
||||
| DOC_COMMENT
|
||||
| IDENT
|
||||
| STRING
|
||||
| RAW_STRING => {
|
||||
WHITESPACE | COMMENT | DOC_COMMENT | IDENT | STRING | RAW_STRING => {
|
||||
let text = get_text_after_edit(node, &edit);
|
||||
let tokens = tokenize(&text);
|
||||
let token = match tokens[..] {
|
||||
@@ -84,10 +79,7 @@ fn reparse_block<'node>(
|
||||
return None;
|
||||
}
|
||||
let (green, new_errors) =
|
||||
parser_impl::parse_with(
|
||||
yellow::GreenBuilder::new(),
|
||||
&text, &tokens, reparser,
|
||||
);
|
||||
parser_impl::parse_with(yellow::GreenBuilder::new(), &text, &tokens, reparser);
|
||||
Some((node, green, new_errors))
|
||||
}
|
||||
|
||||
@@ -101,9 +93,7 @@ fn get_text_after_edit(node: SyntaxNodeRef, edit: &AtomEdit) -> String {
|
||||
|
||||
fn is_contextual_kw(text: &str) -> bool {
|
||||
match text {
|
||||
| "auto"
|
||||
| "default"
|
||||
| "union" => true,
|
||||
"auto" | "default" | "union" => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@@ -113,7 +103,8 @@ fn find_reparsable_node<'node>(
|
||||
range: TextRange,
|
||||
) -> Option<(SyntaxNodeRef<'node>, fn(&mut Parser))> {
|
||||
let node = algo::find_covering_node(node, range);
|
||||
return node.ancestors()
|
||||
return node
|
||||
.ancestors()
|
||||
.filter_map(|node| reparser(node).map(|r| (node, r)))
|
||||
.next();
|
||||
|
||||
@@ -145,17 +136,20 @@ fn find_reparsable_node<'node>(
|
||||
fn is_balanced(tokens: &[Token]) -> bool {
|
||||
if tokens.len() == 0
|
||||
|| tokens.first().unwrap().kind != L_CURLY
|
||||
|| tokens.last().unwrap().kind != R_CURLY {
|
||||
|| tokens.last().unwrap().kind != R_CURLY
|
||||
{
|
||||
return false;
|
||||
}
|
||||
let mut balance = 0usize;
|
||||
for t in tokens.iter() {
|
||||
match t.kind {
|
||||
L_CURLY => balance += 1,
|
||||
R_CURLY => balance = match balance.checked_sub(1) {
|
||||
Some(b) => b,
|
||||
None => return false,
|
||||
},
|
||||
R_CURLY => {
|
||||
balance = match balance.checked_sub(1) {
|
||||
Some(b) => b,
|
||||
None => return false,
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
@@ -191,24 +185,14 @@ fn merge_errors(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{
|
||||
super::{
|
||||
File,
|
||||
test_utils::extract_range,
|
||||
text_utils::replace_range,
|
||||
utils::dump_tree,
|
||||
},
|
||||
reparse_leaf, reparse_block, AtomEdit, GreenNode, SyntaxError, SyntaxNodeRef,
|
||||
super::{test_utils::extract_range, text_utils::replace_range, utils::dump_tree, File},
|
||||
reparse_block, reparse_leaf, AtomEdit, GreenNode, SyntaxError, SyntaxNodeRef,
|
||||
};
|
||||
|
||||
fn do_check<F>(
|
||||
before: &str,
|
||||
replace_with: &str,
|
||||
reparser: F,
|
||||
) where
|
||||
for<'a> F: Fn(
|
||||
SyntaxNodeRef<'a>,
|
||||
&AtomEdit,
|
||||
) -> Option<(SyntaxNodeRef<'a>, GreenNode, Vec<SyntaxError>)>
|
||||
fn do_check<F>(before: &str, replace_with: &str, reparser: F)
|
||||
where
|
||||
for<'a> F: Fn(SyntaxNodeRef<'a>, &AtomEdit)
|
||||
-> Option<(SyntaxNodeRef<'a>, GreenNode, Vec<SyntaxError>)>,
|
||||
{
|
||||
let (range, before) = extract_range(before);
|
||||
let after = replace_range(before.clone(), range, replace_with);
|
||||
@@ -216,7 +200,10 @@ mod tests {
|
||||
let fully_reparsed = File::parse(&after);
|
||||
let incrementally_reparsed = {
|
||||
let f = File::parse(&before);
|
||||
let edit = AtomEdit { delete: range, insert: replace_with.to_string() };
|
||||
let edit = AtomEdit {
|
||||
delete: range,
|
||||
insert: replace_with.to_string(),
|
||||
};
|
||||
let (node, green, new_errors) =
|
||||
reparser(f.syntax(), &edit).expect("cannot incrementally reparse");
|
||||
let green_root = node.replace_with(green);
|
||||
@@ -232,113 +219,183 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn reparse_block_tests() {
|
||||
let do_check = |before, replace_to|
|
||||
do_check(before, replace_to, reparse_block);
|
||||
let do_check = |before, replace_to| do_check(before, replace_to, reparse_block);
|
||||
|
||||
do_check(r"
|
||||
do_check(
|
||||
r"
|
||||
fn foo() {
|
||||
let x = foo + <|>bar<|>
|
||||
}
|
||||
", "baz");
|
||||
do_check(r"
|
||||
",
|
||||
"baz",
|
||||
);
|
||||
do_check(
|
||||
r"
|
||||
fn foo() {
|
||||
let x = foo<|> + bar<|>
|
||||
}
|
||||
", "baz");
|
||||
do_check(r"
|
||||
",
|
||||
"baz",
|
||||
);
|
||||
do_check(
|
||||
r"
|
||||
struct Foo {
|
||||
f: foo<|><|>
|
||||
}
|
||||
", ",\n g: (),");
|
||||
do_check(r"
|
||||
",
|
||||
",\n g: (),",
|
||||
);
|
||||
do_check(
|
||||
r"
|
||||
fn foo {
|
||||
let;
|
||||
1 + 1;
|
||||
<|>92<|>;
|
||||
}
|
||||
", "62");
|
||||
do_check(r"
|
||||
",
|
||||
"62",
|
||||
);
|
||||
do_check(
|
||||
r"
|
||||
mod foo {
|
||||
fn <|><|>
|
||||
}
|
||||
", "bar");
|
||||
do_check(r"
|
||||
",
|
||||
"bar",
|
||||
);
|
||||
do_check(
|
||||
r"
|
||||
trait Foo {
|
||||
type <|>Foo<|>;
|
||||
}
|
||||
", "Output");
|
||||
do_check(r"
|
||||
",
|
||||
"Output",
|
||||
);
|
||||
do_check(
|
||||
r"
|
||||
impl IntoIterator<Item=i32> for Foo {
|
||||
f<|><|>
|
||||
}
|
||||
", "n next(");
|
||||
do_check(r"
|
||||
",
|
||||
"n next(",
|
||||
);
|
||||
do_check(
|
||||
r"
|
||||
use a::b::{foo,<|>,bar<|>};
|
||||
", "baz");
|
||||
do_check(r"
|
||||
",
|
||||
"baz",
|
||||
);
|
||||
do_check(
|
||||
r"
|
||||
pub enum A {
|
||||
Foo<|><|>
|
||||
}
|
||||
", "\nBar;\n");
|
||||
do_check(r"
|
||||
",
|
||||
"\nBar;\n",
|
||||
);
|
||||
do_check(
|
||||
r"
|
||||
foo!{a, b<|><|> d}
|
||||
", ", c[3]");
|
||||
do_check(r"
|
||||
",
|
||||
", c[3]",
|
||||
);
|
||||
do_check(
|
||||
r"
|
||||
fn foo() {
|
||||
vec![<|><|>]
|
||||
}
|
||||
", "123");
|
||||
do_check(r"
|
||||
",
|
||||
"123",
|
||||
);
|
||||
do_check(
|
||||
r"
|
||||
extern {
|
||||
fn<|>;<|>
|
||||
}
|
||||
", " exit(code: c_int)");
|
||||
",
|
||||
" exit(code: c_int)",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reparse_leaf_tests() {
|
||||
let do_check = |before, replace_to|
|
||||
do_check(before, replace_to, reparse_leaf);
|
||||
let do_check = |before, replace_to| do_check(before, replace_to, reparse_leaf);
|
||||
|
||||
do_check(r"<|><|>
|
||||
do_check(
|
||||
r"<|><|>
|
||||
fn foo() -> i32 { 1 }
|
||||
", "\n\n\n \n");
|
||||
do_check(r"
|
||||
",
|
||||
"\n\n\n \n",
|
||||
);
|
||||
do_check(
|
||||
r"
|
||||
fn foo() -> <|><|> {}
|
||||
", " \n");
|
||||
do_check(r"
|
||||
",
|
||||
" \n",
|
||||
);
|
||||
do_check(
|
||||
r"
|
||||
fn <|>foo<|>() -> i32 { 1 }
|
||||
", "bar");
|
||||
do_check(r"
|
||||
",
|
||||
"bar",
|
||||
);
|
||||
do_check(
|
||||
r"
|
||||
fn foo<|><|>foo() { }
|
||||
", "bar");
|
||||
do_check(r"
|
||||
",
|
||||
"bar",
|
||||
);
|
||||
do_check(
|
||||
r"
|
||||
fn foo /* <|><|> */ () {}
|
||||
", "some comment");
|
||||
do_check(r"
|
||||
",
|
||||
"some comment",
|
||||
);
|
||||
do_check(
|
||||
r"
|
||||
fn baz <|><|> () {}
|
||||
", " \t\t\n\n");
|
||||
do_check(r"
|
||||
",
|
||||
" \t\t\n\n",
|
||||
);
|
||||
do_check(
|
||||
r"
|
||||
fn baz <|><|> () {}
|
||||
", " \t\t\n\n");
|
||||
do_check(r"
|
||||
",
|
||||
" \t\t\n\n",
|
||||
);
|
||||
do_check(
|
||||
r"
|
||||
/// foo <|><|>omment
|
||||
mod { }
|
||||
", "c");
|
||||
do_check(r#"
|
||||
",
|
||||
"c",
|
||||
);
|
||||
do_check(
|
||||
r#"
|
||||
fn -> &str { "Hello<|><|>" }
|
||||
"#, ", world");
|
||||
do_check(r#"
|
||||
"#,
|
||||
", world",
|
||||
);
|
||||
do_check(
|
||||
r#"
|
||||
fn -> &str { // "Hello<|><|>"
|
||||
"#, ", world");
|
||||
do_check(r##"
|
||||
"#,
|
||||
", world",
|
||||
);
|
||||
do_check(
|
||||
r##"
|
||||
fn -> &str { r#"Hello<|><|>"#
|
||||
"##, ", world");
|
||||
do_check(r"
|
||||
"##,
|
||||
", world",
|
||||
);
|
||||
do_check(
|
||||
r"
|
||||
#[derive(<|>Copy<|>)]
|
||||
enum Foo {
|
||||
|
||||
}
|
||||
", "Clone");
|
||||
",
|
||||
"Clone",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
mod generated;
|
||||
|
||||
use std::fmt;
|
||||
use crate::SyntaxKind::*;
|
||||
use std::fmt;
|
||||
|
||||
pub use self::generated::SyntaxKind;
|
||||
|
||||
|
||||
@@ -23,4 +23,4 @@ pub fn replace_range(mut text: String, range: TextRange, replace_with: &str) ->
|
||||
let end = u32::from(range.end()) as usize;
|
||||
text.replace_range(start..end, replace_with);
|
||||
text
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use std::fmt::Write;
|
||||
use crate::{
|
||||
algo::walk::{walk, WalkEvent},
|
||||
SyntaxKind, File, SyntaxNodeRef
|
||||
File, SyntaxKind, SyntaxNodeRef,
|
||||
};
|
||||
use std::fmt::Write;
|
||||
|
||||
/// Parse a file and create a string representation of the resulting parse tree.
|
||||
pub fn dump_tree(syntax: SyntaxNodeRef) -> String {
|
||||
@@ -58,9 +58,7 @@ pub(crate) fn validate_block_structure(root: SyntaxNodeRef) {
|
||||
let mut stack = Vec::new();
|
||||
for node in root.descendants() {
|
||||
match node.kind() {
|
||||
SyntaxKind::L_CURLY => {
|
||||
stack.push(node)
|
||||
}
|
||||
SyntaxKind::L_CURLY => stack.push(node),
|
||||
SyntaxKind::R_CURLY => {
|
||||
if let Some(pair) = stack.pop() {
|
||||
assert_eq!(
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
use rowan::GreenNodeBuilder;
|
||||
use crate::{
|
||||
TextUnit, SmolStr,
|
||||
parser_impl::Sink,
|
||||
yellow::{GreenNode, SyntaxError, RaTypes},
|
||||
SyntaxKind,
|
||||
yellow::{GreenNode, RaTypes, SyntaxError},
|
||||
SmolStr, SyntaxKind, TextUnit,
|
||||
};
|
||||
use rowan::GreenNodeBuilder;
|
||||
|
||||
pub(crate) struct GreenBuilder {
|
||||
errors: Vec<SyntaxError>,
|
||||
@@ -36,7 +35,10 @@ impl Sink for GreenBuilder {
|
||||
}
|
||||
|
||||
fn error(&mut self, message: String, offset: TextUnit) {
|
||||
let error = SyntaxError { msg: message, offset };
|
||||
let error = SyntaxError {
|
||||
msg: message,
|
||||
offset,
|
||||
};
|
||||
self.errors.push(error)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
mod builder;
|
||||
mod syntax_text;
|
||||
|
||||
use self::syntax_text::SyntaxText;
|
||||
use crate::{SmolStr, SyntaxKind, TextRange, TextUnit};
|
||||
use rowan::Types;
|
||||
use std::{
|
||||
fmt,
|
||||
hash::{Hash, Hasher},
|
||||
};
|
||||
use rowan::Types;
|
||||
use crate::{SyntaxKind, TextUnit, TextRange, SmolStr};
|
||||
use self::syntax_text::SyntaxText;
|
||||
|
||||
pub use rowan::{TreeRoot};
|
||||
pub(crate) use self::builder::GreenBuilder;
|
||||
pub use rowan::TreeRoot;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum RaTypes {}
|
||||
@@ -31,9 +31,7 @@ pub struct SyntaxError {
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct SyntaxNode<R: TreeRoot<RaTypes> = OwnedRoot>(
|
||||
::rowan::SyntaxNode<RaTypes, R>,
|
||||
);
|
||||
pub struct SyntaxNode<R: TreeRoot<RaTypes> = OwnedRoot>(::rowan::SyntaxNode<RaTypes, R>);
|
||||
pub type SyntaxNodeRef<'a> = SyntaxNode<RefRoot<'a>>;
|
||||
|
||||
impl<R1, R2> PartialEq<SyntaxNode<R1>> for SyntaxNode<R2>
|
||||
@@ -69,16 +67,16 @@ impl<'a> SyntaxNodeRef<'a> {
|
||||
pub fn leaf_text(self) -> Option<&'a SmolStr> {
|
||||
self.0.leaf_text()
|
||||
}
|
||||
pub fn ancestors(self) -> impl Iterator<Item=SyntaxNodeRef<'a>> {
|
||||
pub fn ancestors(self) -> impl Iterator<Item = SyntaxNodeRef<'a>> {
|
||||
crate::algo::generate(Some(self), |&node| node.parent())
|
||||
}
|
||||
pub fn descendants(self) -> impl Iterator<Item=SyntaxNodeRef<'a>> {
|
||||
pub fn descendants(self) -> impl Iterator<Item = SyntaxNodeRef<'a>> {
|
||||
crate::algo::walk::walk(self).filter_map(|event| match event {
|
||||
crate::algo::walk::WalkEvent::Enter(node) => Some(node),
|
||||
crate::algo::walk::WalkEvent::Exit(_) => None,
|
||||
})
|
||||
}
|
||||
pub fn siblings(self, direction: Direction) -> impl Iterator<Item=SyntaxNodeRef<'a>> {
|
||||
pub fn siblings(self, direction: Direction) -> impl Iterator<Item = SyntaxNodeRef<'a>> {
|
||||
crate::algo::generate(Some(self), move |&node| match direction {
|
||||
Direction::Next => node.next_sibling(),
|
||||
Direction::Prev => node.prev_sibling(),
|
||||
@@ -142,9 +140,7 @@ impl<R: TreeRoot<RaTypes>> fmt::Debug for SyntaxNode<R> {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SyntaxNodeChildren<R: TreeRoot<RaTypes>>(
|
||||
::rowan::SyntaxNodeChildren<RaTypes, R>
|
||||
);
|
||||
pub struct SyntaxNodeChildren<R: TreeRoot<RaTypes>>(::rowan::SyntaxNodeChildren<RaTypes, R>);
|
||||
|
||||
impl<R: TreeRoot<RaTypes>> Iterator for SyntaxNodeChildren<R> {
|
||||
type Item = SyntaxNode<R>;
|
||||
@@ -154,7 +150,6 @@ impl<R: TreeRoot<RaTypes>> Iterator for SyntaxNodeChildren<R> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn has_short_text(kind: SyntaxKind) -> bool {
|
||||
use crate::SyntaxKind::*;
|
||||
match kind {
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
use std::{
|
||||
fmt, ops,
|
||||
};
|
||||
use std::{fmt, ops};
|
||||
|
||||
use crate::{
|
||||
text_utils::{contains_offset_nonstrict, intersect},
|
||||
SyntaxNodeRef, TextRange, TextUnit,
|
||||
text_utils::{intersect, contains_offset_nonstrict},
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -17,19 +15,17 @@ impl<'a> SyntaxText<'a> {
|
||||
pub(crate) fn new(node: SyntaxNodeRef<'a>) -> SyntaxText<'a> {
|
||||
SyntaxText {
|
||||
node,
|
||||
range: node.range()
|
||||
range: node.range(),
|
||||
}
|
||||
}
|
||||
pub fn chunks(&self) -> impl Iterator<Item=&'a str> {
|
||||
pub fn chunks(&self) -> impl Iterator<Item = &'a str> {
|
||||
let range = self.range;
|
||||
self.node
|
||||
.descendants()
|
||||
.filter_map(move |node| {
|
||||
let text = node.leaf_text()?;
|
||||
let range = intersect(range, node.range())?;
|
||||
let range = range - node.range().start();
|
||||
Some(&text[range])
|
||||
})
|
||||
self.node.descendants().filter_map(move |node| {
|
||||
let text = node.leaf_text()?;
|
||||
let range = intersect(range, node.range())?;
|
||||
let range = range - node.range().start();
|
||||
Some(&text[range])
|
||||
})
|
||||
}
|
||||
pub fn push_to(&self, buf: &mut String) {
|
||||
self.chunks().for_each(|it| buf.push_str(it));
|
||||
@@ -55,11 +51,13 @@ impl<'a> SyntaxText<'a> {
|
||||
self.range.len()
|
||||
}
|
||||
pub fn slice(&self, range: impl SyntaxTextSlice) -> SyntaxText<'a> {
|
||||
let range = range.restrict(self.range)
|
||||
.unwrap_or_else(|| {
|
||||
panic!("invalid slice, range: {:?}, slice: {:?}", self.range, range)
|
||||
});
|
||||
SyntaxText { node: self.node, range }
|
||||
let range = range.restrict(self.range).unwrap_or_else(|| {
|
||||
panic!("invalid slice, range: {:?}, slice: {:?}", self.range, range)
|
||||
});
|
||||
SyntaxText {
|
||||
node: self.node,
|
||||
range,
|
||||
}
|
||||
}
|
||||
pub fn char_at(&self, offset: TextUnit) -> Option<char> {
|
||||
let mut start: TextUnit = 0.into();
|
||||
|
||||
Reference in New Issue
Block a user