diff --git a/src/lib.rs b/src/lib.rs index 0ea8f6a63b..1534586445 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,7 @@ mod parser; pub mod syntax_kinds; pub use text::{TextRange, TextUnit}; pub use tree::{File, Node, SyntaxKind, Token}; -pub(crate) use tree::{FileBuilder, Sink}; +pub(crate) use tree::{ErrorMsg, FileBuilder, Sink}; pub use lexer::{next_token, tokenize}; pub use parser::parse; diff --git a/src/parser/event.rs b/src/parser/event.rs index e97350c89a..90348398ee 100644 --- a/src/parser/event.rs +++ b/src/parser/event.rs @@ -1,4 +1,4 @@ -use {File, FileBuilder, Sink, SyntaxKind, TextUnit, Token}; +use {ErrorMsg, File, FileBuilder, Sink, SyntaxKind, TextUnit, Token}; use syntax_kinds::TOMBSTONE; use super::is_insignificant; @@ -140,7 +140,9 @@ pub(super) fn to_file(text: String, tokens: &[Token], events: Vec) -> Fil } builder.leaf(kind, len); } - &Event::Error { ref message } => builder.error().message(message.clone()).emit(), + &Event::Error { ref message } => builder.error(ErrorMsg { + message: message.clone(), + }), } } builder.finish() diff --git a/src/parser/grammar/attributes.rs b/src/parser/grammar/attributes.rs index 8bf04afced..92dfb99efb 100644 --- a/src/parser/grammar/attributes.rs +++ b/src/parser/grammar/attributes.rs @@ -37,7 +37,7 @@ fn meta_item(p: &mut Parser) { EQ => { p.bump(); if !expressions::literal(p) { - p.error().message("expected literal").emit(); + p.error("expected literal"); } } L_PAREN => meta_item_arg_list(p), @@ -45,7 +45,7 @@ fn meta_item(p: &mut Parser) { } meta_item.complete(p, META_ITEM); } else { - p.error().message("expected attribute value").emit() + p.error("expected attribute value"); } } @@ -60,12 +60,12 @@ fn meta_item_arg_list(p: &mut Parser) { let message = "expected attribute"; if items::ITEM_FIRST.contains(c) { - p.error().message(message).emit(); + p.error(message); return; } let err = p.start(); - p.error().message(message).emit(); + p.error(message); p.bump(); err.complete(p, ERROR); continue; diff --git a/src/parser/grammar/expressions.rs b/src/parser/grammar/expressions.rs index 8caaf35538..3704cb16fe 100644 --- a/src/parser/grammar/expressions.rs +++ b/src/parser/grammar/expressions.rs @@ -15,6 +15,6 @@ pub(super) fn literal(p: &mut Parser) -> bool { pub(super) fn expr(p: &mut Parser) { if !literal(p) { - p.error().message("expected expression").emit(); + p.error("expected expression"); } } diff --git a/src/parser/grammar/items/mod.rs b/src/parser/grammar/items/mod.rs index 37f2ab132e..b73628ec0c 100644 --- a/src/parser/grammar/items/mod.rs +++ b/src/parser/grammar/items/mod.rs @@ -51,7 +51,7 @@ fn item(p: &mut Parser) { // extern struct Foo; _ => { item.abandon(p); - p.error().message("expected `fn` or `{`").emit(); + p.error("expected `fn` or `{`"); return; } } @@ -121,7 +121,7 @@ fn item(p: &mut Parser) { abi(p); if !p.at(FN_KW) { item.abandon(p); - p.error().message("expected function").emit(); + p.error("expected function"); return; } fn_item(p); @@ -144,7 +144,7 @@ fn item(p: &mut Parser) { if t == L_CURLY { error_block(p, message); } else { - p.error().message(message).emit(); + p.error(message); } return; } @@ -234,7 +234,7 @@ fn fn_item(p: &mut Parser) { if p.at(L_PAREN) { fn_value_parameters(p); } else { - p.error().message("expected function arguments").emit(); + p.error("expected function arguments"); } if p.at(L_CURLY) { diff --git a/src/parser/grammar/items/structs.rs b/src/parser/grammar/items/structs.rs index 69d95c698f..640b940e44 100644 --- a/src/parser/grammar/items/structs.rs +++ b/src/parser/grammar/items/structs.rs @@ -19,7 +19,7 @@ pub(super) fn struct_item(p: &mut Parser) { L_CURLY => named_fields(p), _ => { //TODO: special case `(` error message - p.error().message("expected `;` or `{`").emit(); + p.error("expected `;` or `{`"); return; } } @@ -34,7 +34,7 @@ pub(super) fn struct_item(p: &mut Parser) { p.expect(SEMI); } _ => { - p.error().message("expected `;`, `{`, or `(`").emit(); + p.error("expected `;`, `{`, or `(`"); return; } } diff --git a/src/parser/grammar/items/use_item.rs b/src/parser/grammar/items/use_item.rs index 38e7b3f8a5..a3f7f0da88 100644 --- a/src/parser/grammar/items/use_item.rs +++ b/src/parser/grammar/items/use_item.rs @@ -37,7 +37,7 @@ fn use_tree(p: &mut Parser) { L_CURLY => nested_trees(p), _ => { // is this unreachable? - p.error().message("expected `{` or `*`").emit(); + p.error("expected `{` or `*`"); } } } diff --git a/src/parser/grammar/mod.rs b/src/parser/grammar/mod.rs index afce308d0c..b949583ffa 100644 --- a/src/parser/grammar/mod.rs +++ b/src/parser/grammar/mod.rs @@ -53,7 +53,7 @@ fn alias(p: &mut Parser) -> bool { fn error_block(p: &mut Parser, message: &str) { assert!(p.at(L_CURLY)); let err = p.start(); - p.error().message(message).emit(); + p.error(message); p.bump(); let mut level: u32 = 1; while level > 0 && !p.at(EOF) { @@ -74,7 +74,7 @@ impl<'p> Parser<'p> { fn err_and_bump(&mut self, message: &str) { let err = self.start(); - self.error().message(message).emit(); + self.error(message); self.bump(); err.complete(self, ERROR); } @@ -84,7 +84,7 @@ impl<'p> Parser<'p> { self.bump(); true } else { - self.error().message(format!("expected {:?}", kind)).emit(); + self.error(format!("expected {:?}", kind)); false } } diff --git a/src/parser/grammar/paths.rs b/src/parser/grammar/paths.rs index 6efac26103..a7fc90774f 100644 --- a/src/parser/grammar/paths.rs +++ b/src/parser/grammar/paths.rs @@ -43,7 +43,9 @@ fn path_segment(p: &mut Parser, first: bool) { } match p.current() { IDENT | SELF_KW | SUPER_KW => p.bump(), - _ => p.error().message("expected identifier").emit(), + _ => { + p.error("expected identifier"); + } }; segment.complete(p, PATH_SEGMENT); } diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 752d532d09..7c8e47cb6f 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -129,8 +129,8 @@ impl<'t> Parser<'t> { m } - pub(crate) fn error<'p>(&'p mut self) -> ErrorBuilder<'p, 't> { - ErrorBuilder::new(self) + pub(crate) fn error<'p, T: Into>(&'p mut self, msg: T) -> ErrorBuilder<'p, 't> { + ErrorBuilder::new(self, msg.into()) } pub(crate) fn bump(&mut self) { @@ -175,25 +175,19 @@ impl<'t> Parser<'t> { } pub(crate) struct ErrorBuilder<'p, 't: 'p> { - message: Option, + message: String, parser: &'p mut Parser<'t>, } -impl<'t, 'p> ErrorBuilder<'p, 't> { - fn new(parser: &'p mut Parser<'t>) -> Self { - ErrorBuilder { - message: None, - parser, - } - } - - pub fn message>(mut self, m: M) -> Self { - self.message = Some(m.into()); - self - } - - pub fn emit(self) { - let message = self.message.expect("Error message not set"); +impl<'p, 't: 'p> Drop for ErrorBuilder<'p, 't> { + fn drop(&mut self) { + let message = ::std::mem::replace(&mut self.message, String::new()); self.parser.event(Event::Error { message }); } } + +impl<'t, 'p> ErrorBuilder<'p, 't> { + fn new(parser: &'p mut Parser<'t>, message: String) -> Self { + ErrorBuilder { message, parser } + } +} diff --git a/src/tree/file_builder.rs b/src/tree/file_builder.rs index 47038496de..3c7e2d7cfd 100644 --- a/src/tree/file_builder.rs +++ b/src/tree/file_builder.rs @@ -14,7 +14,7 @@ pub(crate) trait Sink { fn leaf(&mut self, kind: SyntaxKind, len: TextUnit); fn start_internal(&mut self, kind: SyntaxKind); fn finish_internal(&mut self); - fn error(&mut self) -> ErrorBuilder; + fn error(&mut self, err: ErrorMsg); } #[derive(Debug)] @@ -22,7 +22,8 @@ pub(crate) struct FileBuilder { text: String, nodes: Vec, errors: Vec, - in_progress: Vec<(NodeIdx, Option)>, // (parent, last_child) + in_progress: Vec<(NodeIdx, Option)>, + // (parent, last_child) pos: TextUnit, } @@ -65,8 +66,13 @@ impl Sink for FileBuilder { } } - fn error(&mut self) -> ErrorBuilder { - ErrorBuilder::new(self) + fn error(&mut self, err: ErrorMsg) { + let &(node, after_child) = self.in_progress.last().unwrap(); + self.errors.push(SyntaxErrorData { + node, + message: err.message, + after_child, + }) } } @@ -149,32 +155,7 @@ fn grow(left: &mut TextRange, right: TextRange) { *left = TextRange::from_to(left.start(), right.end()) } -#[derive(Debug)] -pub struct ErrorBuilder<'f> { - message: Option, - builder: &'f mut FileBuilder, -} - -impl<'f> ErrorBuilder<'f> { - fn new(builder: &'f mut FileBuilder) -> Self { - ErrorBuilder { - message: None, - builder, - } - } - - pub fn message>(mut self, m: M) -> Self { - self.message = Some(m.into()); - self - } - - pub fn emit(self) { - let message = self.message.expect("Error message not set"); - let &(node, after_child) = self.builder.in_progress.last().unwrap(); - self.builder.errors.push(SyntaxErrorData { - node, - message, - after_child, - }) - } +#[derive(Default)] +pub(crate) struct ErrorMsg { + pub(crate) message: String, } diff --git a/src/tree/mod.rs b/src/tree/mod.rs index 9ed0504c7f..ebf26777be 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -4,7 +4,7 @@ use std::fmt; use std::cmp; mod file_builder; -pub(crate) use self::file_builder::{FileBuilder, Sink}; +pub(crate) use self::file_builder::{ErrorMsg, FileBuilder, Sink}; pub use syntax_kinds::SyntaxKind;