From 2fa90e736b026ee979d9eb59178dc1f792228250 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 28 Aug 2018 11:12:42 +0300 Subject: better recovery for exprs --- crates/libsyntax2/src/ast/generated.rs | 78 ++++++++++++++++++++++- crates/libsyntax2/src/ast/mod.rs | 9 +++ crates/libsyntax2/src/grammar.ron | 10 ++- crates/libsyntax2/src/grammar/expressions/atom.rs | 5 +- crates/libsyntax2/src/parser_api.rs | 19 ++++-- 5 files changed, 113 insertions(+), 8 deletions(-) (limited to 'crates/libsyntax2/src') diff --git a/crates/libsyntax2/src/ast/generated.rs b/crates/libsyntax2/src/ast/generated.rs index f99d1274a..6181aada8 100644 --- a/crates/libsyntax2/src/ast/generated.rs +++ b/crates/libsyntax2/src/ast/generated.rs @@ -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 { + 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> + 'a { + pub fn items(self) -> impl Iterator> + '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 { + 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 { + 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> { diff --git a/crates/libsyntax2/src/ast/mod.rs b/crates/libsyntax2/src/ast/mod.rs index 2ebee6a4f..9941138a7 100644 --- a/crates/libsyntax2/src/ast/mod.rs +++ b/crates/libsyntax2/src/ast/mod.rs @@ -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> { self.blocks().nth(0) diff --git a/crates/libsyntax2/src/grammar.ron b/crates/libsyntax2/src/grammar.ron index a98e9e2fd..7217a4633 100644 --- a/crates/libsyntax2/src/grammar.ron +++ b/crates/libsyntax2/src/grammar.ron @@ -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": (), }, ) diff --git a/crates/libsyntax2/src/grammar/expressions/atom.rs b/crates/libsyntax2/src/grammar/expressions/atom.rs index ab4aa49d2..0769bb5a8 100644 --- a/crates/libsyntax2/src/grammar/expressions/atom.rs +++ b/crates/libsyntax2/src/grammar/expressions/atom.rs @@ -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 { match literal(p) { Some(m) => return Some(m), @@ -73,7 +76,7 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option continue_expr(p), BREAK_KW => break_expr(p), _ => { - p.err_and_bump("expected expression"); + p.err_recover("expected expression", EXPR_RECOVERY_SET); return None; } }; diff --git a/crates/libsyntax2/src/parser_api.rs b/crates/libsyntax2/src/parser_api.rs index 0a3b29b70..10b9b64ac 100644 --- a/crates/libsyntax2/src/parser_api.rs +++ b/crates/libsyntax2/src/parser_api.rs @@ -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); } } -- cgit v1.2.3