This commit is contained in:
Aleksey Kladov 2018-08-16 12:51:40 +03:00
parent 1193c5f829
commit 7094291573
18 changed files with 260 additions and 276 deletions

View file

@ -26,9 +26,8 @@ use std::{
use libsyntax2::{
TextUnit,
ast::{self, AstNode},
algo::{find_leaf_at_offset, ancestors},
};
use libeditor::{LineIndex, FileSymbol};
use libeditor::{LineIndex, FileSymbol, find_node};
use self::symbol_index::FileSymbols;
pub use self::symbol_index::Query;
@ -123,13 +122,7 @@ impl World {
let file = self.file_syntax(id)?;
let syntax = file.syntax();
let syntax = syntax.as_ref();
let name_ref =
find_leaf_at_offset(syntax, offset)
.left_biased()
.into_iter()
.flat_map(|node| ancestors(node))
.flat_map(ast::NameRef::cast)
.next();
let name_ref = find_node::<ast::NameRef<_>>(syntax, offset);
let name = match name_ref {
None => return Ok(vec![]),
Some(name_ref) => name_ref.text(),

View file

@ -66,7 +66,7 @@ fn find_non_trivia_leaf(syntax: SyntaxNodeRef, offset: TextUnit) -> Option<Synta
.find(|leaf| !leaf.kind().is_trivia())
}
fn find_node<'a, N: AstNode<&'a SyntaxRoot>>(syntax: SyntaxNodeRef<'a>, offset: TextUnit) -> Option<N> {
pub fn find_node<'a, N: AstNode<&'a SyntaxRoot>>(syntax: SyntaxNodeRef<'a>, offset: TextUnit) -> Option<N> {
let leaf = find_non_trivia_leaf(syntax, offset)?;
ancestors(leaf)
.filter_map(N::cast)

View file

@ -21,7 +21,10 @@ pub use self::{
extend_selection::extend_selection,
symbols::{StructureNode, file_structure, FileSymbol, file_symbols},
edit::{EditBuilder, Edit, AtomEdit},
code_actions::{flip_comma, add_derive, ActionResult, CursorPosition},
code_actions::{
ActionResult, CursorPosition, find_node,
flip_comma, add_derive,
},
};
#[derive(Debug)]
@ -59,9 +62,7 @@ pub fn matching_brace(file: &ast::File, offset: TextUnit) -> Option<TextUnit> {
L_PAREN, R_PAREN,
L_ANGLE, R_ANGLE,
];
let syntax = file.syntax();
let syntax = syntax.as_ref();
let (brace_node, brace_idx) = find_leaf_at_offset(syntax, offset)
let (brace_node, brace_idx) = find_leaf_at_offset(file.syntax_ref(), offset)
.filter_map(|node| {
let idx = BRACES.iter().position(|&brace| brace == node.kind())?;
Some((node, idx))
@ -75,9 +76,8 @@ pub fn matching_brace(file: &ast::File, offset: TextUnit) -> Option<TextUnit> {
}
pub fn highlight(file: &ast::File) -> Vec<HighlightedRange> {
let syntax = file.syntax();
let mut res = Vec::new();
for node in walk::preorder(syntax.as_ref()) {
for node in walk::preorder(file.syntax_ref()) {
let tag = match node.kind() {
ERROR => "error",
COMMENT | DOC_COMMENT => "comment",
@ -99,10 +99,9 @@ pub fn highlight(file: &ast::File) -> Vec<HighlightedRange> {
}
pub fn diagnostics(file: &ast::File) -> Vec<Diagnostic> {
let syntax = file.syntax();
let mut res = Vec::new();
for node in walk::preorder(syntax.as_ref()) {
for node in walk::preorder(file.syntax_ref()) {
if node.kind() == ERROR {
res.push(Diagnostic {
range: node.range(),

View file

@ -26,8 +26,7 @@ pub struct FileSymbol {
}
pub fn file_symbols(file: &ast::File) -> Vec<FileSymbol> {
let syntax = file.syntax();
preorder(syntax.as_ref())
preorder(file.syntax_ref())
.filter_map(to_symbol)
.collect()
}
@ -57,9 +56,8 @@ fn to_symbol(node: SyntaxNodeRef) -> Option<FileSymbol> {
pub fn file_structure(file: &ast::File) -> Vec<StructureNode> {
let mut res = Vec::new();
let mut stack = Vec::new();
let syntax = file.syntax();
for event in walk(syntax.as_ref()) {
for event in walk(file.syntax_ref()) {
match event {
WalkEvent::Enter(node) => {
match structure_node(node) {

View file

@ -23,6 +23,31 @@ impl<R: TreeRoot> AstNode<R> for ArrayType<R> {
impl<R: TreeRoot> ArrayType<R> {}
// Attr
#[derive(Debug, Clone, Copy)]
pub struct Attr<R: TreeRoot = Arc<SyntaxRoot>> {
syntax: SyntaxNode<R>,
}
impl<R: TreeRoot> AstNode<R> for Attr<R> {
fn cast(syntax: SyntaxNode<R>) -> Option<Self> {
match syntax.kind() {
ATTR => Some(Attr { syntax }),
_ => None,
}
}
fn syntax(&self) -> &SyntaxNode<R> { &self.syntax }
}
impl<R: TreeRoot> Attr<R> {
pub fn value(&self) -> Option<TokenTree<R>> {
self.syntax()
.children()
.filter_map(TokenTree::cast)
.next()
}
}
// ConstDef
#[derive(Debug, Clone, Copy)]
pub struct ConstDef<R: TreeRoot = Arc<SyntaxRoot>> {
@ -40,6 +65,7 @@ impl<R: TreeRoot> AstNode<R> for ConstDef<R> {
}
impl<R: TreeRoot> ast::NameOwner<R> for ConstDef<R> {}
impl<R: TreeRoot> ast::AttrsOwner<R> for ConstDef<R> {}
impl<R: TreeRoot> ConstDef<R> {}
// DynTraitType
@ -77,6 +103,7 @@ impl<R: TreeRoot> AstNode<R> for EnumDef<R> {
}
impl<R: TreeRoot> ast::NameOwner<R> for EnumDef<R> {}
impl<R: TreeRoot> ast::AttrsOwner<R> for EnumDef<R> {}
impl<R: TreeRoot> EnumDef<R> {}
// File
@ -120,6 +147,7 @@ impl<R: TreeRoot> AstNode<R> for FnDef<R> {
}
impl<R: TreeRoot> ast::NameOwner<R> for FnDef<R> {}
impl<R: TreeRoot> ast::AttrsOwner<R> for FnDef<R> {}
impl<R: TreeRoot> FnDef<R> {}
// FnPointerType
@ -211,6 +239,7 @@ impl<R: TreeRoot> AstNode<R> for Module<R> {
}
impl<R: TreeRoot> ast::NameOwner<R> for Module<R> {}
impl<R: TreeRoot> ast::AttrsOwner<R> for Module<R> {}
impl<R: TreeRoot> Module<R> {}
// Name
@ -266,6 +295,7 @@ impl<R: TreeRoot> AstNode<R> for NamedField<R> {
}
impl<R: TreeRoot> ast::NameOwner<R> for NamedField<R> {}
impl<R: TreeRoot> ast::AttrsOwner<R> for NamedField<R> {}
impl<R: TreeRoot> NamedField<R> {}
// NeverType
@ -436,6 +466,7 @@ impl<R: TreeRoot> AstNode<R> for StaticDef<R> {
}
impl<R: TreeRoot> ast::NameOwner<R> for StaticDef<R> {}
impl<R: TreeRoot> ast::AttrsOwner<R> for StaticDef<R> {}
impl<R: TreeRoot> StaticDef<R> {}
// StructDef
@ -455,6 +486,7 @@ impl<R: TreeRoot> AstNode<R> for StructDef<R> {
}
impl<R: TreeRoot> ast::NameOwner<R> for StructDef<R> {}
impl<R: TreeRoot> ast::AttrsOwner<R> for StructDef<R> {}
impl<R: TreeRoot> StructDef<R> {
pub fn fields<'a>(&'a self) -> impl Iterator<Item = NamedField<R>> + 'a {
self.syntax()
@ -463,6 +495,24 @@ impl<R: TreeRoot> StructDef<R> {
}
}
// TokenTree
#[derive(Debug, Clone, Copy)]
pub struct TokenTree<R: TreeRoot = Arc<SyntaxRoot>> {
syntax: SyntaxNode<R>,
}
impl<R: TreeRoot> AstNode<R> for TokenTree<R> {
fn cast(syntax: SyntaxNode<R>) -> Option<Self> {
match syntax.kind() {
TOKEN_TREE => Some(TokenTree { syntax }),
_ => None,
}
}
fn syntax(&self) -> &SyntaxNode<R> { &self.syntax }
}
impl<R: TreeRoot> TokenTree<R> {}
// TraitDef
#[derive(Debug, Clone, Copy)]
pub struct TraitDef<R: TreeRoot = Arc<SyntaxRoot>> {
@ -480,6 +530,7 @@ impl<R: TreeRoot> AstNode<R> for TraitDef<R> {
}
impl<R: TreeRoot> ast::NameOwner<R> for TraitDef<R> {}
impl<R: TreeRoot> ast::AttrsOwner<R> for TraitDef<R> {}
impl<R: TreeRoot> TraitDef<R> {}
// TupleType
@ -517,6 +568,7 @@ impl<R: TreeRoot> AstNode<R> for TypeDef<R> {
}
impl<R: TreeRoot> ast::NameOwner<R> for TypeDef<R> {}
impl<R: TreeRoot> ast::AttrsOwner<R> for TypeDef<R> {}
impl<R: TreeRoot> TypeDef<R> {}
// TypeRef

View file

@ -2,10 +2,11 @@ mod generated;
use std::sync::Arc;
use itertools::Itertools;
use smol_str::SmolStr;
use {
SyntaxNode, SyntaxRoot, TreeRoot, SyntaxError,
SyntaxNode, SyntaxNodeRef, SyntaxRoot, TreeRoot, SyntaxError,
SyntaxKind::*,
};
pub use self::generated::*;
@ -14,6 +15,9 @@ pub trait AstNode<R: TreeRoot> {
fn cast(syntax: SyntaxNode<R>) -> Option<Self>
where Self: Sized;
fn syntax(&self) -> &SyntaxNode<R>;
fn syntax_ref<'a>(&'a self) -> SyntaxNodeRef<'a> where R: 'a {
self.syntax().as_ref()
}
}
pub trait NameOwner<R: TreeRoot>: AstNode<R> {
@ -25,6 +29,14 @@ pub trait NameOwner<R: TreeRoot>: AstNode<R> {
}
}
pub trait AttrsOwner<R: TreeRoot>: AstNode<R> {
fn attrs<'a>(&'a self) -> Box<Iterator<Item=Attr<R>> + 'a> where R: 'a {
let it = self.syntax().children()
.filter_map(Attr::cast);
Box::new(it)
}
}
impl File<Arc<SyntaxRoot>> {
pub fn parse(text: &str) -> Self {
File::cast(::parse(text)).unwrap()
@ -39,31 +51,20 @@ impl<R: TreeRoot> File<R> {
impl<R: TreeRoot> FnDef<R> {
pub fn has_atom_attr(&self, atom: &str) -> bool {
self.syntax()
.children()
.filter(|node| node.kind() == ATTR)
.any(|attr| {
let mut metas = attr.children().filter(|node| node.kind() == META_ITEM);
let meta = match metas.next() {
None => return false,
Some(meta) => {
if metas.next().is_some() {
return false;
}
meta
}
};
let mut children = meta.children();
match children.next() {
None => false,
Some(child) => {
if children.next().is_some() {
return false;
}
child.kind() == IDENT && child.text() == atom
}
}
})
self.attrs()
.filter_map(|x| x.value())
.filter_map(|x| as_atom(x))
.any(|x| x == atom)
}
}
fn as_atom<R: TreeRoot>(tt: TokenTree<R>) -> Option<SmolStr> {
let syntax = tt.syntax_ref();
let (_bra, attr, _ket) = syntax.children().collect_tuple()?;
if attr.kind() == IDENT {
Some(attr.leaf_text().unwrap())
} else {
None
}
}

View file

@ -221,24 +221,26 @@ Grammar(
["functions", "FnDef"]
]
),
"FnDef": ( traits: ["NameOwner"] ),
"FnDef": ( traits: ["NameOwner", "AttrsOwner"] ),
"StructDef": (
traits: ["NameOwner"],
traits: ["NameOwner", "AttrsOwner"],
collections: [
["fields", "NamedField"]
]
),
"NamedField": ( traits: ["NameOwner"] ),
"EnumDef": ( traits: ["NameOwner"] ),
"TraitDef": ( traits: ["NameOwner"] ),
"Module": ( traits: ["NameOwner"] ),
"ConstDef": ( traits: ["NameOwner"] ),
"StaticDef": ( traits: ["NameOwner"] ),
"TypeDef": ( traits: ["NameOwner"] ),
"NamedField": ( traits: ["NameOwner", "AttrsOwner"] ),
"EnumDef": ( traits: ["NameOwner", "AttrsOwner"] ),
"TraitDef": ( traits: ["NameOwner", "AttrsOwner"] ),
"Module": ( traits: ["NameOwner", "AttrsOwner"] ),
"ConstDef": ( traits: ["NameOwner", "AttrsOwner"] ),
"StaticDef": ( traits: ["NameOwner", "AttrsOwner"] ),
"TypeDef": ( traits: ["NameOwner", "AttrsOwner"] ),
"ImplItem": (),
"Name": (),
"NameRef": (),
"Attr": ( options: [ ["value", "TokenTree"] ] ),
"TokenTree": (),
"ParenType": (),
"TupleType": (),

View file

@ -22,58 +22,10 @@ fn attribute(p: &mut Parser, inner: bool) {
p.bump();
}
if p.expect(L_BRACK) {
meta_item(p);
p.expect(R_BRACK);
if p.at(L_BRACK) {
items::token_tree(p);
} else {
p.error("expected `[`");
}
attr.complete(p, ATTR);
}
fn meta_item(p: &mut Parser) {
if p.at(IDENT) {
let meta_item = p.start();
p.bump();
match p.current() {
EQ => {
p.bump();
if expressions::literal(p).is_none() {
p.error("expected literal");
}
}
L_PAREN => meta_item_arg_list(p),
_ => (),
}
meta_item.complete(p, META_ITEM);
} else {
p.error("expected attribute value");
}
}
fn meta_item_arg_list(p: &mut Parser) {
assert!(p.at(L_PAREN));
p.bump();
loop {
match p.current() {
EOF | R_PAREN => break,
IDENT => meta_item(p),
c => if expressions::literal(p).is_none() {
let message = "expected attribute";
if items::ITEM_FIRST.contains(c) {
p.error(message);
return;
}
let err = p.start();
p.error(message);
p.bump();
err.complete(p, ERROR);
continue;
},
}
if !p.at(R_PAREN) {
p.expect(COMMA);
}
}
p.expect(R_PAREN);
}

View file

@ -55,9 +55,6 @@ pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool, flavor: ItemF
}
}
pub(super) const ITEM_FIRST: TokenSet =
token_set![EXTERN_KW, MOD_KW, USE_KW, STRUCT_KW, ENUM_KW, FN_KW, PUB_KW, POUND];
pub(super) enum MaybeItem {
None,
Item(SyntaxKind),
@ -322,13 +319,14 @@ pub(super) fn macro_call_after_excl(p: &mut Parser) -> BlockLike {
flavor
}
fn token_tree(p: &mut Parser) {
pub(super) fn token_tree(p: &mut Parser) {
let closing_paren_kind = match p.current() {
L_CURLY => R_CURLY,
L_PAREN => R_PAREN,
L_BRACK => R_BRACK,
_ => unreachable!(),
};
let m = p.start();
p.bump();
while !p.at(EOF) && !p.at(closing_paren_kind) {
match p.current() {
@ -338,4 +336,5 @@ fn token_tree(p: &mut Parser) {
}
};
p.expect(closing_paren_kind);
m.complete(p, TOKEN_TREE);
}

View file

@ -2,25 +2,20 @@ FILE@[0; 54)
FN_DEF@[0; 31)
ATTR@[0; 18)
POUND@[0; 1)
L_BRACK@[1; 2)
META_ITEM@[2; 17)
TOKEN_TREE@[1; 18)
L_BRACK@[1; 2)
IDENT@[2; 5) "foo"
L_PAREN@[5; 6)
META_ITEM@[6; 9)
TOKEN_TREE@[5; 17)
L_PAREN@[5; 6)
IDENT@[6; 9) "foo"
COMMA@[9; 10)
WHITESPACE@[10; 11)
err: `expected attribute`
ERROR@[11; 12)
COMMA@[9; 10)
WHITESPACE@[10; 11)
PLUS@[11; 12)
err: `expected attribute`
ERROR@[12; 13)
COMMA@[12; 13)
WHITESPACE@[13; 14)
LITERAL@[14; 16)
WHITESPACE@[13; 14)
INT_NUMBER@[14; 16) "92"
R_PAREN@[16; 17)
R_BRACK@[17; 18)
R_PAREN@[16; 17)
R_BRACK@[17; 18)
WHITESPACE@[18; 19)
FN_KW@[19; 21)
WHITESPACE@[21; 22)
@ -35,26 +30,26 @@ FILE@[0; 54)
WHITESPACE@[29; 30)
R_CURLY@[30; 31)
WHITESPACE@[31; 34)
FN_DEF@[34; 53)
ATTR@[34; 40)
POUND@[34; 35)
ATTR@[34; 53)
POUND@[34; 35)
TOKEN_TREE@[35; 53)
L_BRACK@[35; 36)
META_ITEM@[36; 40)
IDENT@[36; 39) "foo"
IDENT@[36; 39) "foo"
TOKEN_TREE@[39; 53)
L_PAREN@[39; 40)
err: `expected attribute`
err: `expected R_BRACK`
WHITESPACE@[40; 41)
FN_KW@[41; 43)
WHITESPACE@[43; 44)
NAME@[44; 47)
IDENT@[44; 47) "foo"
PARAM_LIST@[47; 49)
L_PAREN@[47; 48)
R_PAREN@[48; 49)
WHITESPACE@[49; 50)
BLOCK_EXPR@[50; 53)
L_CURLY@[50; 51)
WHITESPACE@[51; 52)
R_CURLY@[52; 53)
WHITESPACE@[40; 41)
FN_KW@[41; 43)
WHITESPACE@[43; 44)
IDENT@[44; 47) "foo"
TOKEN_TREE@[47; 49)
L_PAREN@[47; 48)
R_PAREN@[48; 49)
WHITESPACE@[49; 50)
TOKEN_TREE@[50; 53)
L_CURLY@[50; 51)
WHITESPACE@[51; 52)
R_CURLY@[52; 53)
err: `expected R_PAREN`
err: `expected R_BRACK`
err: `expected an item`
WHITESPACE@[53; 54)

View file

@ -19,9 +19,10 @@ FILE@[0; 95)
NAME_REF@[14; 17)
IDENT@[14; 17) "bar"
err: `expected EXCL`
L_PAREN@[17; 18)
R_PAREN@[18; 19)
err: `expected SEMI`
TOKEN_TREE@[17; 19)
L_PAREN@[17; 18)
R_PAREN@[18; 19)
err: `expected SEMI`
WHITESPACE@[19; 20)
err: `expected an item`
ERROR@[20; 80)

View file

@ -86,8 +86,9 @@ FILE@[0; 91)
NAME_REF@[78; 84)
IDENT@[78; 84) "format"
EXCL@[84; 85)
L_PAREN@[85; 86)
R_PAREN@[86; 87)
TOKEN_TREE@[85; 87)
L_PAREN@[85; 86)
R_PAREN@[86; 87)
SEMI@[87; 88)
WHITESPACE@[88; 89)
R_CURLY@[89; 90)

View file

@ -21,8 +21,9 @@ FILE@[0; 70)
WHITESPACE@[24; 25)
IDENT@[25; 28) "foo"
WHITESPACE@[28; 29)
L_CURLY@[29; 30)
R_CURLY@[30; 31)
TOKEN_TREE@[29; 31)
L_CURLY@[29; 30)
R_CURLY@[30; 31)
WHITESPACE@[31; 32)
MACRO_CALL@[32; 44)
PATH@[32; 40)
@ -35,8 +36,9 @@ FILE@[0; 70)
NAME_REF@[37; 40)
IDENT@[37; 40) "bar"
EXCL@[40; 41)
L_PAREN@[41; 42)
R_PAREN@[42; 43)
TOKEN_TREE@[41; 43)
L_PAREN@[41; 42)
R_PAREN@[42; 43)
SEMI@[43; 44)
WHITESPACE@[44; 45)
MACRO_CALL@[45; 59)
@ -50,8 +52,9 @@ FILE@[0; 70)
IDENT@[52; 55) "baz"
EXCL@[55; 56)
WHITESPACE@[56; 57)
L_CURLY@[57; 58)
R_CURLY@[58; 59)
TOKEN_TREE@[57; 59)
L_CURLY@[57; 58)
R_CURLY@[58; 59)
WHITESPACE@[59; 60)
STRUCT_DEF@[60; 69)
STRUCT_KW@[60; 66)

View file

@ -2,175 +2,163 @@ FILE@[0; 236)
ATTR@[0; 8)
POUND@[0; 1)
EXCL@[1; 2)
L_BRACK@[2; 3)
META_ITEM@[3; 7)
TOKEN_TREE@[2; 8)
L_BRACK@[2; 3)
IDENT@[3; 7) "attr"
R_BRACK@[7; 8)
R_BRACK@[7; 8)
WHITESPACE@[8; 9)
ATTR@[9; 23)
POUND@[9; 10)
EXCL@[10; 11)
L_BRACK@[11; 12)
META_ITEM@[12; 22)
TOKEN_TREE@[11; 23)
L_BRACK@[11; 12)
IDENT@[12; 16) "attr"
L_PAREN@[16; 17)
LITERAL@[17; 21)
TOKEN_TREE@[16; 22)
L_PAREN@[16; 17)
TRUE_KW@[17; 21)
R_PAREN@[21; 22)
R_BRACK@[22; 23)
R_PAREN@[21; 22)
R_BRACK@[22; 23)
WHITESPACE@[23; 24)
ATTR@[24; 39)
POUND@[24; 25)
EXCL@[25; 26)
L_BRACK@[26; 27)
META_ITEM@[27; 38)
TOKEN_TREE@[26; 39)
L_BRACK@[26; 27)
IDENT@[27; 31) "attr"
L_PAREN@[31; 32)
META_ITEM@[32; 37)
TOKEN_TREE@[31; 38)
L_PAREN@[31; 32)
IDENT@[32; 37) "ident"
R_PAREN@[37; 38)
R_BRACK@[38; 39)
R_PAREN@[37; 38)
R_BRACK@[38; 39)
WHITESPACE@[39; 40)
ATTR@[40; 116)
POUND@[40; 41)
EXCL@[41; 42)
L_BRACK@[42; 43)
META_ITEM@[43; 115)
TOKEN_TREE@[42; 116)
L_BRACK@[42; 43)
IDENT@[43; 47) "attr"
L_PAREN@[47; 48)
META_ITEM@[48; 53)
TOKEN_TREE@[47; 115)
L_PAREN@[47; 48)
IDENT@[48; 53) "ident"
COMMA@[53; 54)
WHITESPACE@[54; 55)
LITERAL@[55; 58)
COMMA@[53; 54)
WHITESPACE@[54; 55)
INT_NUMBER@[55; 58) "100"
COMMA@[58; 59)
WHITESPACE@[59; 60)
LITERAL@[60; 64)
COMMA@[58; 59)
WHITESPACE@[59; 60)
TRUE_KW@[60; 64)
COMMA@[64; 65)
WHITESPACE@[65; 66)
LITERAL@[66; 72)
COMMA@[64; 65)
WHITESPACE@[65; 66)
STRING@[66; 72)
COMMA@[72; 73)
WHITESPACE@[73; 74)
META_ITEM@[74; 85)
COMMA@[72; 73)
WHITESPACE@[73; 74)
IDENT@[74; 79) "ident"
WHITESPACE@[79; 80)
EQ@[80; 81)
WHITESPACE@[81; 82)
LITERAL@[82; 85)
INT_NUMBER@[82; 85) "100"
COMMA@[85; 86)
WHITESPACE@[86; 87)
META_ITEM@[87; 102)
INT_NUMBER@[82; 85) "100"
COMMA@[85; 86)
WHITESPACE@[86; 87)
IDENT@[87; 92) "ident"
WHITESPACE@[92; 93)
EQ@[93; 94)
WHITESPACE@[94; 95)
LITERAL@[95; 102)
STRING@[95; 102)
COMMA@[102; 103)
WHITESPACE@[103; 104)
META_ITEM@[104; 114)
STRING@[95; 102)
COMMA@[102; 103)
WHITESPACE@[103; 104)
IDENT@[104; 109) "ident"
L_PAREN@[109; 110)
LITERAL@[110; 113)
TOKEN_TREE@[109; 114)
L_PAREN@[109; 110)
INT_NUMBER@[110; 113) "100"
R_PAREN@[113; 114)
R_PAREN@[114; 115)
R_BRACK@[115; 116)
R_PAREN@[113; 114)
R_PAREN@[114; 115)
R_BRACK@[115; 116)
WHITESPACE@[116; 117)
ATTR@[117; 130)
POUND@[117; 118)
EXCL@[118; 119)
L_BRACK@[119; 120)
META_ITEM@[120; 129)
TOKEN_TREE@[119; 130)
L_BRACK@[119; 120)
IDENT@[120; 124) "attr"
L_PAREN@[124; 125)
LITERAL@[125; 128)
TOKEN_TREE@[124; 129)
L_PAREN@[124; 125)
INT_NUMBER@[125; 128) "100"
R_PAREN@[128; 129)
R_BRACK@[129; 130)
R_PAREN@[128; 129)
R_BRACK@[129; 130)
WHITESPACE@[130; 131)
ATTR@[131; 155)
POUND@[131; 132)
EXCL@[132; 133)
L_BRACK@[133; 134)
META_ITEM@[134; 154)
TOKEN_TREE@[133; 155)
L_BRACK@[133; 134)
IDENT@[134; 138) "attr"
L_PAREN@[138; 139)
META_ITEM@[139; 153)
TOKEN_TREE@[138; 154)
L_PAREN@[138; 139)
IDENT@[139; 146) "enabled"
WHITESPACE@[146; 147)
EQ@[147; 148)
WHITESPACE@[148; 149)
LITERAL@[149; 153)
TRUE_KW@[149; 153)
R_PAREN@[153; 154)
R_BRACK@[154; 155)
TRUE_KW@[149; 153)
R_PAREN@[153; 154)
R_BRACK@[154; 155)
WHITESPACE@[155; 156)
ATTR@[156; 173)
POUND@[156; 157)
EXCL@[157; 158)
L_BRACK@[158; 159)
META_ITEM@[159; 172)
TOKEN_TREE@[158; 173)
L_BRACK@[158; 159)
IDENT@[159; 166) "enabled"
L_PAREN@[166; 167)
LITERAL@[167; 171)
TOKEN_TREE@[166; 172)
L_PAREN@[166; 167)
TRUE_KW@[167; 171)
R_PAREN@[171; 172)
R_BRACK@[172; 173)
R_PAREN@[171; 172)
R_BRACK@[172; 173)
WHITESPACE@[173; 174)
ATTR@[174; 191)
POUND@[174; 175)
EXCL@[175; 176)
L_BRACK@[176; 177)
META_ITEM@[177; 190)
TOKEN_TREE@[176; 191)
L_BRACK@[176; 177)
IDENT@[177; 181) "attr"
L_PAREN@[181; 182)
LITERAL@[182; 189)
TOKEN_TREE@[181; 190)
L_PAREN@[181; 182)
STRING@[182; 189)
R_PAREN@[189; 190)
R_BRACK@[190; 191)
R_PAREN@[189; 190)
R_BRACK@[190; 191)
WHITESPACE@[191; 192)
ATTR@[192; 214)
POUND@[192; 193)
EXCL@[193; 194)
L_BRACK@[194; 195)
META_ITEM@[195; 213)
TOKEN_TREE@[194; 214)
L_BRACK@[194; 195)
IDENT@[195; 199) "repr"
L_PAREN@[199; 200)
META_ITEM@[200; 201)
TOKEN_TREE@[199; 213)
L_PAREN@[199; 200)
IDENT@[200; 201) "C"
COMMA@[201; 202)
WHITESPACE@[202; 203)
META_ITEM@[203; 212)
COMMA@[201; 202)
WHITESPACE@[202; 203)
IDENT@[203; 208) "align"
WHITESPACE@[208; 209)
EQ@[209; 210)
WHITESPACE@[210; 211)
LITERAL@[211; 212)
INT_NUMBER@[211; 212) "4"
R_PAREN@[212; 213)
R_BRACK@[213; 214)
INT_NUMBER@[211; 212) "4"
R_PAREN@[212; 213)
R_BRACK@[213; 214)
WHITESPACE@[214; 215)
ATTR@[215; 236)
POUND@[215; 216)
EXCL@[216; 217)
L_BRACK@[217; 218)
META_ITEM@[218; 235)
TOKEN_TREE@[217; 236)
L_BRACK@[217; 218)
IDENT@[218; 222) "repr"
L_PAREN@[222; 223)
META_ITEM@[223; 224)
TOKEN_TREE@[222; 235)
L_PAREN@[222; 223)
IDENT@[223; 224) "C"
COMMA@[224; 225)
WHITESPACE@[225; 226)
META_ITEM@[226; 234)
COMMA@[224; 225)
WHITESPACE@[225; 226)
IDENT@[226; 231) "align"
L_PAREN@[231; 232)
LITERAL@[232; 233)
TOKEN_TREE@[231; 234)
L_PAREN@[231; 232)
INT_NUMBER@[232; 233) "4"
R_PAREN@[233; 234)
R_PAREN@[234; 235)
R_BRACK@[235; 236)
R_PAREN@[233; 234)
R_PAREN@[234; 235)
R_BRACK@[235; 236)

View file

@ -60,10 +60,10 @@ FILE@[0; 118)
ATTR@[79; 87)
POUND@[79; 80)
EXCL@[80; 81)
L_BRACK@[81; 82)
META_ITEM@[82; 86)
TOKEN_TREE@[81; 87)
L_BRACK@[81; 82)
IDENT@[82; 86) "attr"
R_BRACK@[86; 87)
R_BRACK@[86; 87)
WHITESPACE@[87; 92)
MODULE@[92; 98)
MOD_KW@[92; 95)

View file

@ -2,21 +2,21 @@ FILE@[0; 35)
FN_DEF@[0; 34)
ATTR@[0; 12)
POUND@[0; 1)
L_BRACK@[1; 2)
META_ITEM@[2; 11)
TOKEN_TREE@[1; 12)
L_BRACK@[1; 2)
IDENT@[2; 5) "cfg"
L_PAREN@[5; 6)
META_ITEM@[6; 10)
TOKEN_TREE@[5; 11)
L_PAREN@[5; 6)
IDENT@[6; 10) "test"
R_PAREN@[10; 11)
R_BRACK@[11; 12)
R_PAREN@[10; 11)
R_BRACK@[11; 12)
WHITESPACE@[12; 13)
ATTR@[13; 22)
POUND@[13; 14)
L_BRACK@[14; 15)
META_ITEM@[15; 21)
TOKEN_TREE@[14; 22)
L_BRACK@[14; 15)
IDENT@[15; 21) "ignore"
R_BRACK@[21; 22)
R_BRACK@[21; 22)
WHITESPACE@[22; 23)
FN_KW@[23; 25)
WHITESPACE@[25; 26)

View file

@ -2,15 +2,15 @@ FILE@[0; 23)
FN_DEF@[0; 22)
ATTR@[0; 10)
POUND@[0; 1)
L_BRACK@[1; 2)
META_ITEM@[2; 9)
TOKEN_TREE@[1; 10)
L_BRACK@[1; 2)
IDENT@[2; 5) "foo"
L_PAREN@[5; 6)
META_ITEM@[6; 7)
TOKEN_TREE@[5; 9)
L_PAREN@[5; 6)
IDENT@[6; 7) "a"
COMMA@[7; 8)
R_PAREN@[8; 9)
R_BRACK@[9; 10)
COMMA@[7; 8)
R_PAREN@[8; 9)
R_BRACK@[9; 10)
WHITESPACE@[10; 11)
FN_KW@[11; 13)
WHITESPACE@[13; 14)

View file

@ -70,19 +70,19 @@ fn assert_equal_text(expected: &str, actual: &str, path: &Path) {
return;
}
let dir = project_dir();
let path = path.strip_prefix(&dir).unwrap_or_else(|_| path);
let pretty_path = path.strip_prefix(&dir).unwrap_or_else(|_| path);
if expected.trim() == actual.trim() {
println!("whitespace difference, rewriting");
println!("file: {}\n", path.display());
println!("file: {}\n", pretty_path.display());
fs::write(path, actual).unwrap();
return;
}
if REWRITE {
println!("rewriting {}", path.display());
println!("rewriting {}", pretty_path.display());
fs::write(path, actual).unwrap();
return;
}
assert_eq_text!(expected, actual, "file: {}", path.display());
assert_eq_text!(expected, actual, "file: {}", pretty_path.display());
}
fn collect_tests(paths: &[&str]) -> Vec<PathBuf> {