better recovery for exprs

This commit is contained in:
Aleksey Kladov 2018-08-28 11:12:42 +03:00
parent 13110f48e9
commit 2fa90e736b
16 changed files with 263 additions and 27 deletions

View file

@ -439,6 +439,24 @@ impl<'a> ExprStmt<'a> {
}
}
// ExternCrateItem
#[derive(Debug, Clone, Copy)]
pub struct ExternCrateItem<'a> {
syntax: SyntaxNodeRef<'a>,
}
impl<'a> AstNode<'a> for ExternCrateItem<'a> {
fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
match syntax.kind() {
EXTERN_CRATE_ITEM => Some(ExternCrateItem { syntax }),
_ => None,
}
}
fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax }
}
impl<'a> ExternCrateItem<'a> {}
// FieldExpr
#[derive(Debug, Clone, Copy)]
pub struct FieldExpr<'a> {
@ -839,11 +857,51 @@ impl<'a> AstNode<'a> for Module<'a> {
impl<'a> ast::NameOwner<'a> for Module<'a> {}
impl<'a> ast::AttrsOwner<'a> for Module<'a> {}
impl<'a> Module<'a> {
pub fn modules(self) -> impl Iterator<Item = Module<'a>> + 'a {
pub fn items(self) -> impl Iterator<Item = ModuleItem<'a>> + 'a {
super::children(self)
}
}
// ModuleItem
#[derive(Debug, Clone, Copy)]
pub enum ModuleItem<'a> {
StructDef(StructDef<'a>),
EnumDef(EnumDef<'a>),
FnDef(FnDef<'a>),
TraitDef(TraitDef<'a>),
ImplItem(ImplItem<'a>),
UseItem(UseItem<'a>),
ExternCrateItem(ExternCrateItem<'a>),
}
impl<'a> AstNode<'a> for ModuleItem<'a> {
fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
match syntax.kind() {
STRUCT_DEF => Some(ModuleItem::StructDef(StructDef { syntax })),
ENUM_DEF => Some(ModuleItem::EnumDef(EnumDef { syntax })),
FN_DEF => Some(ModuleItem::FnDef(FnDef { syntax })),
TRAIT_DEF => Some(ModuleItem::TraitDef(TraitDef { syntax })),
IMPL_ITEM => Some(ModuleItem::ImplItem(ImplItem { syntax })),
USE_ITEM => Some(ModuleItem::UseItem(UseItem { syntax })),
EXTERN_CRATE_ITEM => Some(ModuleItem::ExternCrateItem(ExternCrateItem { syntax })),
_ => None,
}
}
fn syntax(self) -> SyntaxNodeRef<'a> {
match self {
ModuleItem::StructDef(inner) => inner.syntax(),
ModuleItem::EnumDef(inner) => inner.syntax(),
ModuleItem::FnDef(inner) => inner.syntax(),
ModuleItem::TraitDef(inner) => inner.syntax(),
ModuleItem::ImplItem(inner) => inner.syntax(),
ModuleItem::UseItem(inner) => inner.syntax(),
ModuleItem::ExternCrateItem(inner) => inner.syntax(),
}
}
}
impl<'a> ModuleItem<'a> {}
// Name
#[derive(Debug, Clone, Copy)]
pub struct Name<'a> {
@ -1762,6 +1820,24 @@ impl<'a> AstNode<'a> for TypeRef<'a> {
impl<'a> TypeRef<'a> {}
// UseItem
#[derive(Debug, Clone, Copy)]
pub struct UseItem<'a> {
syntax: SyntaxNodeRef<'a>,
}
impl<'a> AstNode<'a> for UseItem<'a> {
fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
match syntax.kind() {
USE_ITEM => Some(UseItem { syntax }),
_ => None,
}
}
fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax }
}
impl<'a> UseItem<'a> {}
// WhereClause
#[derive(Debug, Clone, Copy)]
pub struct WhereClause<'a> {

View file

@ -115,6 +115,15 @@ impl<'a> Module<'a> {
}
}
impl<'a> LetStmt<'a> {
pub fn has_semi(self) -> bool {
match self.syntax().last_child() {
None => false,
Some(node) => node.kind() == SEMI,
}
}
}
impl<'a> IfExpr<'a> {
pub fn then_branch(self) -> Option<Block<'a>> {
self.blocks().nth(0)

View file

@ -273,7 +273,7 @@ Grammar(
"Module": (
traits: ["NameOwner", "AttrsOwner"],
collections: [
["modules", "Module"]
["items", "ModuleItem"]
]
),
"ConstDef": ( traits: [
@ -331,6 +331,10 @@ Grammar(
"AttrsOwner"
],
),
"ModuleItem": (
enum: ["StructDef", "EnumDef", "FnDef", "TraitDef", "ImplItem",
"UseItem", "ExternCrateItem" ]
),
"TupleExpr": (),
"ArrayExpr": (),
@ -479,6 +483,8 @@ Grammar(
),
"Param": (
options: [["pat", "Pat"]],
)
),
"UseItem": (),
"ExternCrateItem": (),
},
)

View file

@ -33,6 +33,9 @@ pub(super) const ATOM_EXPR_FIRST: TokenSet =
RETURN_KW, IDENT, SELF_KW, SUPER_KW, COLONCOLON, BREAK_KW, CONTINUE_KW, LIFETIME ],
];
const EXPR_RECOVERY_SET: TokenSet =
token_set![LET_KW];
pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<CompletedMarker> {
match literal(p) {
Some(m) => return Some(m),
@ -73,7 +76,7 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<CompletedMark
CONTINUE_KW => continue_expr(p),
BREAK_KW => break_expr(p),
_ => {
p.err_and_bump("expected expression");
p.err_recover("expected expression", EXPR_RECOVERY_SET);
return None;
}
};

View file

@ -12,6 +12,8 @@ fn mask(kind: SyntaxKind) -> u128 {
}
impl TokenSet {
const EMPTY: TokenSet = TokenSet(0);
pub fn contains(&self, kind: SyntaxKind) -> bool {
self.0 & mask(kind) != 0
}
@ -139,12 +141,21 @@ impl<'t> Parser<'t> {
/// Create an error node and consume the next token.
pub(crate) fn err_and_bump(&mut self, message: &str) {
let m = self.start();
self.error(message);
if !self.at(SyntaxKind::L_CURLY) && !self.at(SyntaxKind::R_CURLY) {
self.err_recover(message, TokenSet::EMPTY);
}
/// Create an error node and consume the next token.
pub(crate) fn err_recover(&mut self, message: &str, recovery_set: TokenSet) {
if self.at(SyntaxKind::L_CURLY)
|| self.at(SyntaxKind::R_CURLY)
|| recovery_set.contains(self.current()) {
self.error(message);
} else {
let m = self.start();
self.error(message);
self.bump();
m.complete(self, ERROR);
}
m.complete(self, ERROR);
}
}