refine item parsing

This commit is contained in:
Aleksey Kladov 2018-08-04 13:17:24 +03:00
parent 7264c3294b
commit e919db3731
24 changed files with 334 additions and 215 deletions

View file

@ -229,18 +229,27 @@ fn block_expr(p: &mut Parser) -> CompletedMarker {
while !p.at(EOF) && !p.at(R_CURLY) { while !p.at(EOF) && !p.at(R_CURLY) {
match p.current() { match p.current() {
LET_KW => let_stmt(p), LET_KW => let_stmt(p),
c => { _ => {
// test block_items // test block_items
// fn a() { fn b() {} } // fn a() { fn b() {} }
if items::ITEM_FIRST.contains(c) { let m = p.start();
items::item(p) match items::maybe_item(p) {
} else { items::MaybeItem::Item(kind) => {
let expr_stmt = p.start(); m.complete(p, kind);
expressions::expr(p); }
if p.eat(SEMI) { items::MaybeItem::Modifiers => {
expr_stmt.complete(p, EXPR_STMT); m.abandon(p);
} else { p.error("expected an item");
expr_stmt.abandon(p); }
// test pub_expr
// fn foo() { pub 92; } //FIXME
items::MaybeItem::None => {
expressions::expr(p);
if p.eat(SEMI) {
m.complete(p, EXPR_STMT);
} else {
m.abandon(p);
}
} }
} }
} }

View file

@ -8,174 +8,137 @@ mod use_item;
pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) { pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) {
attributes::inner_attributes(p); attributes::inner_attributes(p);
while !p.at(EOF) && !(stop_on_r_curly && p.at(R_CURLY)) { while !p.at(EOF) && !(stop_on_r_curly && p.at(R_CURLY)) {
item(p); item(p, stop_on_r_curly)
}
}
pub(super) fn item(p: &mut Parser, stop_on_r_curly: bool) {
let m = p.start();
match maybe_item(p) {
MaybeItem::Item(kind) => {
m.complete(p, kind);
}
MaybeItem::None => {
m.abandon(p);
if p.at(L_CURLY) {
error_block(p, "expected an item");
} else if !p.at(EOF) && !(stop_on_r_curly && p.at(R_CURLY)) {
p.err_and_bump("expected an item");
} else {
p.error("expected an item");
}
}
MaybeItem::Modifiers => {
p.error("expected fn, trait or impl");
m.complete(p, ERROR);
}
} }
} }
pub(super) const ITEM_FIRST: TokenSet = pub(super) const ITEM_FIRST: TokenSet =
token_set![EXTERN_KW, MOD_KW, USE_KW, STRUCT_KW, ENUM_KW, FN_KW, PUB_KW, POUND]; token_set![EXTERN_KW, MOD_KW, USE_KW, STRUCT_KW, ENUM_KW, FN_KW, PUB_KW, POUND];
pub(super) fn item(p: &mut Parser) { pub(super) enum MaybeItem {
let item = p.start(); None,
Item(SyntaxKind),
Modifiers,
}
pub(super) fn maybe_item(p: &mut Parser) -> MaybeItem {
attributes::outer_attributes(p); attributes::outer_attributes(p);
visibility(p); visibility(p);
let la = p.nth(1); if let Some(kind) = items_without_modifiers(p) {
let item_kind = match p.current() { return MaybeItem::Item(kind);
USE_KW => { }
use_item::use_item(p);
USE_ITEM let mut has_mods = false;
// modifiers
has_mods |= p.eat(CONST_KW);
// test unsafe_block_in_mod
// fn foo(){} unsafe { } fn bar(){}
if p.at(UNSAFE_KW) && p.nth(1) != L_CURLY {
p.eat(UNSAFE_KW);
has_mods = true;
}
if p.at(EXTERN_KW) {
has_mods = true;
abi(p);
}
if p.at(IDENT) && p.at_contextual_kw("auto") && p.nth(1) == TRAIT_KW {
p.bump_remap(AUTO_KW);
has_mods = true;
}
if p.at(IDENT) && p.at_contextual_kw("default") && p.nth(1) == IMPL_KW {
p.bump_remap(DEFAULT_KW);
has_mods = true;
}
// items
let kind = match p.current() {
// test extern_fn
// extern fn foo() {}
// test const_fn
// const fn foo() {}
// test const_unsafe_fn
// const unsafe fn foo() {}
// test unsafe_extern_fn
// unsafe extern "C" fn foo() {}
// test unsafe_fn
// unsafe fn foo() {}
FN_KW => {
fn_item(p);
FN_ITEM
} }
// test unsafe_trait
// unsafe trait T {}
// test auto_trait
// auto trait T {}
// test unsafe_auto_trait
// unsafe auto trait T {}
TRAIT_KW => {
traits::trait_item(p);
TRAIT_ITEM
}
// test unsafe_impl
// unsafe impl Foo {}
// test default_impl
// default impl Foo {}
// test unsafe_default_impl
// unsafe default impl Foo {}
IMPL_KW => {
traits::impl_item(p);
IMPL_ITEM
}
_ => return if has_mods {
MaybeItem::Modifiers
} else {
MaybeItem::None
}
};
MaybeItem::Item(kind)
}
fn items_without_modifiers(p: &mut Parser) -> Option<SyntaxKind> {
let la = p.nth(1);
let kind = match p.current() {
// test extern_crate // test extern_crate
// extern crate foo; // extern crate foo;
EXTERN_KW if la == CRATE_KW => { EXTERN_KW if la == CRATE_KW => {
extern_crate_item(p); extern_crate_item(p);
EXTERN_CRATE_ITEM EXTERN_CRATE_ITEM
} }
EXTERN_KW => {
abi(p);
match p.current() {
// test extern_fn
// extern fn foo() {}
FN_KW => {
fn_item(p);
FN_ITEM
}
// test extern_block
// extern {}
L_CURLY => {
extern_block(p);
EXTERN_BLOCK_EXPR
}
// test extern_struct
// extern struct Foo;
_ => {
item.abandon(p);
p.error("expected `fn` or `{`");
return;
}
}
}
STATIC_KW => {
consts::static_item(p);
STATIC_ITEM
}
CONST_KW => match p.nth(1) {
// test const_fn
// const fn foo() {}
FN_KW => {
p.bump();
fn_item(p);
FN_ITEM
}
// test const_unsafe_fn
// const unsafe fn foo() {}
UNSAFE_KW if p.nth(2) == FN_KW => {
p.bump();
p.bump();
fn_item(p);
FN_ITEM
}
_ => {
consts::const_item(p);
CONST_ITEM
}
},
UNSAFE_KW => {
p.bump();
let la = p.nth(1);
match p.current() {
// test unsafe_trait
// unsafe trait T {}
TRAIT_KW => {
traits::trait_item(p);
TRAIT_ITEM
}
// test unsafe_auto_trait
// unsafe auto trait T {}
IDENT if p.at_contextual_kw("auto") && la == TRAIT_KW => {
p.bump_remap(AUTO_KW);
traits::trait_item(p);
TRAIT_ITEM
}
// test unsafe_impl
// unsafe impl Foo {}
IMPL_KW => {
traits::impl_item(p);
IMPL_ITEM
}
// test unsafe_default_impl
// unsafe default impl Foo {}
IDENT if p.at_contextual_kw("default") && la == IMPL_KW => {
p.bump_remap(DEFAULT_KW);
traits::impl_item(p);
IMPL_ITEM
}
// test unsafe_extern_fn
// unsafe extern "C" fn foo() {}
EXTERN_KW => {
abi(p);
if !p.at(FN_KW) {
item.abandon(p);
p.error("expected function");
return;
}
fn_item(p);
FN_ITEM
}
// test unsafe_fn
// unsafe fn foo() {}
FN_KW => {
fn_item(p);
FN_ITEM
}
t => {
item.abandon(p);
let message = "expected `trait`, `impl` or `fn`";
// test unsafe_block_in_mod
// fn foo(){} unsafe { } fn bar(){}
if t == L_CURLY {
error_block(p, message);
} else {
p.error(message);
}
return;
}
}
}
TRAIT_KW => {
traits::trait_item(p);
TRAIT_ITEM
}
// test auto_trait
// auto trait T {}
IDENT if p.at_contextual_kw("auto") && la == TRAIT_KW => {
p.bump_remap(AUTO_KW);
traits::trait_item(p);
TRAIT_ITEM
}
IMPL_KW => {
traits::impl_item(p);
IMPL_ITEM
}
// test default_impl
// default impl Foo {}
IDENT if p.at_contextual_kw("default") && la == IMPL_KW => {
p.bump_remap(DEFAULT_KW);
traits::impl_item(p);
IMPL_ITEM
}
FN_KW => {
fn_item(p);
FN_ITEM
}
TYPE_KW => { TYPE_KW => {
type_item(p); type_item(p);
TYPE_ITEM TYPE_ITEM
@ -186,31 +149,40 @@ pub(super) fn item(p: &mut Parser) {
} }
STRUCT_KW => { STRUCT_KW => {
structs::struct_item(p); structs::struct_item(p);
if p.at(SEMI) {
p.err_and_bump(
"expected item, found `;`\n\
consider removing this semicolon"
);
}
STRUCT_ITEM STRUCT_ITEM
} }
ENUM_KW => { ENUM_KW => {
structs::enum_item(p); structs::enum_item(p);
ENUM_ITEM ENUM_ITEM
} }
L_CURLY => { USE_KW => {
item.abandon(p); use_item::use_item(p);
error_block(p, "expected item"); USE_ITEM
return;
} }
err_token => { CONST_KW if (la == IDENT || la == MUT_KW) => {
item.abandon(p); consts::const_item(p);
let message = if err_token == SEMI { CONST_ITEM
//TODO: if the item is incomplete, this message is misleading
"expected item, found `;`\n\
consider removing this semicolon"
} else {
"expected item"
};
p.err_and_bump(message);
return;
} }
STATIC_KW => {
consts::static_item(p);
STATIC_ITEM
}
// test extern_block
// extern {}
EXTERN_KW if la == L_CURLY || ((la == STRING || la == RAW_STRING) && p.nth(2) == L_CURLY) => {
abi(p);
extern_block(p);
EXTERN_BLOCK_EXPR
}
_ => return None,
}; };
item.complete(p, item_kind); Some(kind)
} }
fn extern_crate_item(p: &mut Parser) { fn extern_crate_item(p: &mut Parser) {

View file

@ -45,7 +45,7 @@ pub(super) fn impl_item(p: &mut Parser) {
// fn bar(&self) {} // fn bar(&self) {}
// } // }
while !p.at(EOF) && !p.at(R_CURLY) { while !p.at(EOF) && !p.at(R_CURLY) {
item(p); item(p, true);
} }
p.expect(R_CURLY); p.expect(R_CURLY);
} }

View file

@ -1,9 +1,9 @@
FILE@[0; 21) FILE@[0; 21)
ERROR@[0; 3) ERROR@[0; 3)
IF_KW@[0; 2) IF_KW@[0; 2)
err: `expected item` err: `expected an item`
WHITESPACE@[2; 3) WHITESPACE@[2; 3)
err: `expected item` err: `expected an item`
ERROR@[3; 10) ERROR@[3; 10)
MATCH_KW@[3; 8) MATCH_KW@[3; 8)
WHITESPACE@[8; 10) WHITESPACE@[8; 10)

View file

@ -1,6 +1,6 @@
FILE@[0; 42) FILE@[0; 42)
SHEBANG@[0; 20) SHEBANG@[0; 20)
err: `expected item` err: `expected an item`
ERROR@[20; 42) ERROR@[20; 42)
WHITESPACE@[20; 21) WHITESPACE@[20; 21)
SHEBANG@[21; 41) SHEBANG@[21; 41)

View file

@ -1,5 +1,5 @@
FILE@[0; 40) FILE@[0; 40)
STRUCT_ITEM@[0; 39) STRUCT_ITEM@[0; 40)
STRUCT_KW@[0; 6) STRUCT_KW@[0; 6)
NAME@[6; 9) NAME@[6; 9)
WHITESPACE@[6; 7) WHITESPACE@[6; 7)
@ -34,5 +34,5 @@ FILE@[0; 40)
R_CURLY@[38; 39) R_CURLY@[38; 39)
err: `expected item, found `;` err: `expected item, found `;`
consider removing this semicolon` consider removing this semicolon`
ERROR@[39; 40) ERROR@[39; 40)
SEMI@[39; 40) SEMI@[39; 40)

View file

@ -11,11 +11,10 @@ FILE@[0; 12)
COLONCOLON@[7; 9) COLONCOLON@[7; 9)
err: `expected identifier` err: `expected identifier`
err: `expected SEMI` err: `expected SEMI`
err: `expected item` err: `expected an item`
PATH_SEGMENT@[9; 9) PATH_SEGMENT@[9; 9)
ERROR@[9; 11) ERROR@[9; 11)
INT_NUMBER@[9; 11) "92" INT_NUMBER@[9; 11) "92"
err: `expected item, found `;` err: `expected an item`
consider removing this semicolon`
ERROR@[11; 12) ERROR@[11; 12)
SEMI@[11; 12) SEMI@[11; 12)

View file

@ -1,7 +1,7 @@
FILE@[0; 31) FILE@[0; 31)
ERROR@[0; 3) ERROR@[0; 3)
R_CURLY@[0; 1) R_CURLY@[0; 1)
err: `expected item` err: `expected an item`
WHITESPACE@[1; 3) WHITESPACE@[1; 3)
STRUCT_ITEM@[3; 14) STRUCT_ITEM@[3; 14)
STRUCT_KW@[3; 9) STRUCT_KW@[3; 9)
@ -10,7 +10,7 @@ FILE@[0; 31)
IDENT@[10; 11) "S" IDENT@[10; 11) "S"
SEMI@[11; 12) SEMI@[11; 12)
WHITESPACE@[12; 14) WHITESPACE@[12; 14)
err: `expected item` err: `expected an item`
ERROR@[14; 17) ERROR@[14; 17)
R_CURLY@[14; 15) R_CURLY@[14; 15)
WHITESPACE@[15; 17) WHITESPACE@[15; 17)
@ -26,7 +26,7 @@ FILE@[0; 31)
L_CURLY@[25; 26) L_CURLY@[25; 26)
R_CURLY@[26; 27) R_CURLY@[26; 27)
WHITESPACE@[27; 29) WHITESPACE@[27; 29)
err: `expected item` err: `expected an item`
ERROR@[29; 31) ERROR@[29; 31)
R_CURLY@[29; 30) R_CURLY@[29; 30)
WHITESPACE@[30; 31) WHITESPACE@[30; 31)

View file

@ -13,17 +13,17 @@ FILE@[0; 95)
WHITESPACE@[10; 11) WHITESPACE@[10; 11)
R_CURLY@[11; 12) R_CURLY@[11; 12)
WHITESPACE@[12; 14) WHITESPACE@[12; 14)
err: `expected item` err: `expected an item`
ERROR@[14; 17) ERROR@[14; 17)
IDENT@[14; 17) "bar" IDENT@[14; 17) "bar"
err: `expected item` err: `expected an item`
ERROR@[17; 18) ERROR@[17; 18)
L_PAREN@[17; 18) L_PAREN@[17; 18)
err: `expected item` err: `expected an item`
ERROR@[18; 20) ERROR@[18; 20)
R_PAREN@[18; 19) R_PAREN@[18; 19)
WHITESPACE@[19; 20) WHITESPACE@[19; 20)
err: `expected item` err: `expected an item`
ERROR@[20; 82) ERROR@[20; 82)
L_CURLY@[20; 21) L_CURLY@[20; 21)
WHITESPACE@[21; 26) WHITESPACE@[21; 26)

View file

@ -13,18 +13,18 @@ FILE@[0; 43)
err: `expected COMMA` err: `expected COMMA`
err: `expected R_ANGLE` err: `expected R_ANGLE`
err: `expected `;`, `{`, or `(`` err: `expected `;`, `{`, or `(``
err: `expected item` err: `expected an item`
ERROR@[12; 14) ERROR@[12; 14)
PLUS@[12; 13) PLUS@[12; 13)
WHITESPACE@[13; 14) WHITESPACE@[13; 14)
err: `expected item` err: `expected an item`
ERROR@[14; 15) ERROR@[14; 15)
INT_NUMBER@[14; 15) "2" INT_NUMBER@[14; 15) "2"
err: `expected item` err: `expected an item`
ERROR@[15; 17) ERROR@[15; 17)
R_ANGLE@[15; 16) R_ANGLE@[15; 16)
WHITESPACE@[16; 17) WHITESPACE@[16; 17)
err: `expected item` err: `expected an item`
ERROR@[17; 33) ERROR@[17; 33)
L_CURLY@[17; 18) L_CURLY@[17; 18)
WHITESPACE@[18; 23) WHITESPACE@[18; 23)

View file

@ -1,8 +1,9 @@
FILE@[0; 19) FILE@[0; 19)
ABI@[0; 7) ERROR@[0; 7)
EXTERN_KW@[0; 6) ABI@[0; 7)
WHITESPACE@[6; 7) EXTERN_KW@[0; 6)
err: `expected `fn` or `{`` WHITESPACE@[6; 7)
err: `expected fn, trait or impl`
STRUCT_ITEM@[7; 19) STRUCT_ITEM@[7; 19)
STRUCT_KW@[7; 13) STRUCT_KW@[7; 13)
NAME@[13; 17) NAME@[13; 17)

View file

@ -11,10 +11,12 @@ FILE@[0; 33)
L_CURLY@[8; 9) L_CURLY@[8; 9)
R_CURLY@[9; 10) R_CURLY@[9; 10)
WHITESPACE@[10; 11) WHITESPACE@[10; 11)
UNSAFE_KW@[11; 17) err: `expected an item`
err: `expected `trait`, `impl` or `fn`` ERROR@[11; 18)
ERROR@[17; 22) UNSAFE_KW@[11; 17)
WHITESPACE@[17; 18) WHITESPACE@[17; 18)
err: `expected an item`
ERROR@[18; 22)
L_CURLY@[18; 19) L_CURLY@[18; 19)
WHITESPACE@[19; 20) WHITESPACE@[19; 20)
R_CURLY@[20; 21) R_CURLY@[20; 21)

View file

@ -15,14 +15,13 @@ FILE@[0; 18)
WHITESPACE@[12; 13) WHITESPACE@[12; 13)
err: `expected `;` or `]`` err: `expected `;` or `]``
err: `expected SEMI` err: `expected SEMI`
err: `expected item` err: `expected an item`
ERROR@[13; 15) ERROR@[13; 15)
INT_NUMBER@[13; 15) "92" INT_NUMBER@[13; 15) "92"
err: `expected item` err: `expected an item`
ERROR@[15; 16) ERROR@[15; 16)
R_BRACK@[15; 16) R_BRACK@[15; 16)
err: `expected item, found `;` err: `expected an item`
consider removing this semicolon`
ERROR@[16; 18) ERROR@[16; 18)
SEMI@[16; 17) SEMI@[16; 17)
WHITESPACE@[17; 18) WHITESPACE@[17; 18)

View file

@ -11,14 +11,13 @@ FILE@[0; 20)
err: `expected `fn`` err: `expected `fn``
err: `expected SEMI` err: `expected SEMI`
WHITESPACE@[15; 16) WHITESPACE@[15; 16)
err: `expected item` err: `expected an item`
ERROR@[16; 17) ERROR@[16; 17)
L_PAREN@[16; 17) L_PAREN@[16; 17)
err: `expected item` err: `expected an item`
ERROR@[17; 18) ERROR@[17; 18)
R_PAREN@[17; 18) R_PAREN@[17; 18)
err: `expected item, found `;` err: `expected an item`
consider removing this semicolon`
ERROR@[18; 20) ERROR@[18; 20)
SEMI@[18; 19) SEMI@[18; 19)
WHITESPACE@[19; 20) WHITESPACE@[19; 20)

View file

@ -0,0 +1 @@
fn foo() { pub 92; } //FIXME

View file

@ -0,0 +1,25 @@
FILE@[0; 29)
FN_ITEM@[0; 29)
FN_KW@[0; 2)
NAME@[2; 6)
WHITESPACE@[2; 3)
IDENT@[3; 6) "foo"
PARAM_LIST@[6; 9)
L_PAREN@[6; 7)
R_PAREN@[7; 8)
WHITESPACE@[8; 9)
BLOCK_EXPR@[9; 29)
L_CURLY@[9; 10)
EXPR_STMT@[10; 19)
VISIBILITY@[10; 15)
WHITESPACE@[10; 11)
PUB_KW@[11; 14)
WHITESPACE@[14; 15)
LITERAL@[15; 17)
INT_NUMBER@[15; 17) "92"
SEMI@[17; 18)
WHITESPACE@[18; 19)
R_CURLY@[19; 20)
WHITESPACE@[20; 21)
COMMENT@[21; 28)
WHITESPACE@[28; 29)

View file

@ -0,0 +1,3 @@
fn main() {
extern fn f() {}
}

View file

@ -0,0 +1,31 @@
FILE@[0; 35)
FN_ITEM@[0; 35)
FN_KW@[0; 2)
NAME@[2; 7)
WHITESPACE@[2; 3)
IDENT@[3; 7) "main"
PARAM_LIST@[7; 10)
L_PAREN@[7; 8)
R_PAREN@[8; 9)
WHITESPACE@[9; 10)
BLOCK_EXPR@[10; 35)
L_CURLY@[10; 11)
FN_ITEM@[11; 33)
ABI@[11; 23)
WHITESPACE@[11; 16)
EXTERN_KW@[16; 22)
WHITESPACE@[22; 23)
FN_KW@[23; 25)
NAME@[25; 27)
WHITESPACE@[25; 26)
IDENT@[26; 27) "f"
PARAM_LIST@[27; 30)
L_PAREN@[27; 28)
R_PAREN@[28; 29)
WHITESPACE@[29; 30)
BLOCK_EXPR@[30; 33)
L_CURLY@[30; 31)
R_CURLY@[31; 32)
WHITESPACE@[32; 33)
R_CURLY@[33; 34)
WHITESPACE@[34; 35)

View file

@ -0,0 +1,3 @@
fn main() {
const fn f() {}
}

View file

@ -0,0 +1,30 @@
FILE@[0; 34)
FN_ITEM@[0; 34)
FN_KW@[0; 2)
NAME@[2; 7)
WHITESPACE@[2; 3)
IDENT@[3; 7) "main"
PARAM_LIST@[7; 10)
L_PAREN@[7; 8)
R_PAREN@[8; 9)
WHITESPACE@[9; 10)
BLOCK_EXPR@[10; 34)
L_CURLY@[10; 11)
FN_ITEM@[11; 32)
WHITESPACE@[11; 16)
CONST_KW@[16; 21)
WHITESPACE@[21; 22)
FN_KW@[22; 24)
NAME@[24; 26)
WHITESPACE@[24; 25)
IDENT@[25; 26) "f"
PARAM_LIST@[26; 29)
L_PAREN@[26; 27)
R_PAREN@[27; 28)
WHITESPACE@[28; 29)
BLOCK_EXPR@[29; 32)
L_CURLY@[29; 30)
R_CURLY@[30; 31)
WHITESPACE@[31; 32)
R_CURLY@[32; 33)
WHITESPACE@[33; 34)

View file

@ -0,0 +1,4 @@
fn main() {
unsafe fn f() {}
unsafe { 92 }
}

View file

@ -0,0 +1,40 @@
FILE@[0; 53)
FN_ITEM@[0; 53)
FN_KW@[0; 2)
NAME@[2; 7)
WHITESPACE@[2; 3)
IDENT@[3; 7) "main"
PARAM_LIST@[7; 10)
L_PAREN@[7; 8)
R_PAREN@[8; 9)
WHITESPACE@[9; 10)
BLOCK_EXPR@[10; 53)
L_CURLY@[10; 11)
FN_ITEM@[11; 37)
WHITESPACE@[11; 16)
UNSAFE_KW@[16; 22)
WHITESPACE@[22; 23)
FN_KW@[23; 25)
NAME@[25; 27)
WHITESPACE@[25; 26)
IDENT@[26; 27) "f"
PARAM_LIST@[27; 30)
L_PAREN@[27; 28)
R_PAREN@[28; 29)
WHITESPACE@[29; 30)
BLOCK_EXPR@[30; 37)
L_CURLY@[30; 31)
R_CURLY@[31; 32)
WHITESPACE@[32; 37)
BLOCK_EXPR@[37; 51)
UNSAFE_KW@[37; 43)
WHITESPACE@[43; 44)
L_CURLY@[44; 45)
LITERAL@[45; 49)
WHITESPACE@[45; 46)
INT_NUMBER@[46; 48) "92"
WHITESPACE@[48; 49)
R_CURLY@[49; 50)
WHITESPACE@[50; 51)
R_CURLY@[51; 52)
WHITESPACE@[52; 53)

View file

@ -90,6 +90,7 @@ fn print_difference(expected: &str, actual: &str, path: &Path) {
return; return;
} }
let changeset = Changeset::new(actual, expected, "\n"); let changeset = Changeset::new(actual, expected, "\n");
println!("Expected:\n{}\n\nActual:\n{}\n", expected, actual);
print!("{}", changeset); print!("{}", changeset);
println!("file: {}\n", path.display()); println!("file: {}\n", path.display());
panic!("Comparison failed") panic!("Comparison failed")