diff --git a/crates/parser/diagnostics/diagnostic_kind.rs b/crates/parser/diagnostics/diagnostic_kind.rs index 6755d27..8b7d327 100644 --- a/crates/parser/diagnostics/diagnostic_kind.rs +++ b/crates/parser/diagnostics/diagnostic_kind.rs @@ -64,6 +64,8 @@ pub enum DiagnosticKind { InputEndedBeforeReachingClosingQuoteForAttributeValue = 1084, ExpectingEitherSemicolonOrNewLineHere = 1085, CssInvalidHexEscape = 1086, + ExpectingDirective = 1087, + ExpectingStatement = 1088, } impl DiagnosticKind { diff --git a/crates/parser/diagnostics/diagnostics_english_resources.rs b/crates/parser/diagnostics/diagnostics_english_resources.rs index 12a34b9..1200ecd 100644 --- a/crates/parser/diagnostics/diagnostics_english_resources.rs +++ b/crates/parser/diagnostics/diagnostics_english_resources.rs @@ -63,10 +63,12 @@ lazy_static! { DiagnosticKind::InputEndedBeforeReachingClosingSeqForPi.id() => "Input ended before reaching the closing '?>' for a processing instruction.".into(), DiagnosticKind::InputEndedBeforeReachingClosingSeqForXmlComment.id() => "Input ended before reaching the closing '-->' for a comment.".into(), DiagnosticKind::InputEndedBeforeReachingClosingSeqForMultiLineComment.id() => "Input ended before reaching the closing '*/' for a comment.".into(), - DiagnosticKind::InputEndedBeforeReachingClosingSlashForRegExp.id() => "Input ended before reaching the closing '/' for a regular expression.".into(), + DiagnosticKind::InputEndedBeforeReachingClosingSlashForRegExp.id() => "Input ended before reaching the closing slash for a regular expression.".into(), DiagnosticKind::InputEndedBeforeReachingClosingQuoteForAttributeValue.id() => "Input ended before reaching the closing quotation mark for an attribute value.".into(), DiagnosticKind::ExpectingEitherSemicolonOrNewLineHere.id() => "Expecting either a semicolon or a new line here.".into(), DiagnosticKind::CssInvalidHexEscape.id() => "Invalid hexadecimal escape: '\\{1}'.".into(), + DiagnosticKind::ExpectingDirective.id() => "Expecting directive before {1}".into(), + DiagnosticKind::ExpectingStatement.id() => "Expecting statement before {1}".into(), // DiagnosticKind::K.id() => ".".into(), }; } \ No newline at end of file diff --git a/crates/parser/parser/parser.rs b/crates/parser/parser/parser.rs index eaad115..7108917 100644 --- a/crates/parser/parser/parser.rs +++ b/crates/parser/parser/parser.rs @@ -56,6 +56,13 @@ impl<'input> Parser<'input> { self.compilation_unit().add_diagnostic(Diagnostic::new_syntax_error(location, kind, arguments)); } + fn patch_syntax_error(&self, original: DiagnosticKind, location: &Location, kind: DiagnosticKind, arguments: Vec) { + if self.compilation_unit().diagnostics.borrow().last().unwrap().kind == original { + self.compilation_unit().diagnostics.borrow_mut().pop(); + self.compilation_unit().add_diagnostic(Diagnostic::new_syntax_error(location, kind, arguments)); + } + } + /* fn add_warning(&self, location: &Location, kind: DiagnosticKind, arguments: Vec) { self.compilation_unit().add_diagnostic(Diagnostic::new_warning(location, kind, arguments)); @@ -2266,9 +2273,19 @@ impl<'input> Parser<'input> { // ExpressionStatement } else { self.mark_location(); + + // Store offset for patching error + let i = self.tokenizer.characters().index(); + let exp = self.parse_expression(ParserExpressionContext { allow_in: true, min_precedence: OperatorPrecedence::List, ..default() })?; + + // Patch error + if i == self.tokenizer.characters().index() { + self.patch_syntax_error(DiagnosticKind::ExpectingExpression, &self.tokenizer.cursor_location(), DiagnosticKind::ExpectingStatement, diagnostic_arguments![Token(self.token.0.clone())]); + } + let semicolon = if exp.is_invalidated() { self.next()?; true @@ -3234,7 +3251,12 @@ impl<'input> Parser<'input> { } else if self.peek(Token::Use) { self.parse_use_namespace_directive() } else { - self.parse_statement(context) + let i = self.tokenizer.characters().index(); + let r = self.parse_statement(context); + if i == self.tokenizer.characters().index() { + self.patch_syntax_error(DiagnosticKind::ExpectingStatement, &self.tokenizer.cursor_location(), DiagnosticKind::ExpectingDirective, diagnostic_arguments![Token(self.token.0.clone())]); + } + r } } @@ -5062,7 +5084,15 @@ impl<'input> Parser<'input> { while pi_characters.has_remaining() { data.push(pi_characters.next_or_zero()); } - match process_xml_pi(self.compilation_unit(), (location.first_offset() + 2 + name.len(), location.last_offset() - 2), &name) { + + // XMLPI may not have been successfully parsed, thus + // slice until where possible. + let i = location.first_offset() + 2 + name.len(); + let mut j = location.last_offset(); + j = if i < j { j - 1 } else { j }; + j = if i < j { j - 1 } else { j }; + + match process_xml_pi(self.compilation_unit(), (i, j), &name) { Ok(errors) => { for error in errors.iter() { match error { @@ -5077,9 +5107,6 @@ impl<'input> Parser<'input> { }, } } - if !errors.is_empty() { - return Err(ParserError::Common); - } }, Err(_) => { // self.add_syntax_error(&location, DiagnosticKind::InvalidXmlPi, vec![]); diff --git a/crates/parser/parser/tokenizer.rs b/crates/parser/parser/tokenizer.rs index 295f61f..efed219 100644 --- a/crates/parser/parser/tokenizer.rs +++ b/crates/parser/parser/tokenizer.rs @@ -444,7 +444,7 @@ impl<'input> Tokenizer<'input> { let ch = self.characters.peek_or_zero(); if self.characters.reached_end() { self.add_unexpected_eof_error(DiagnosticKind::InputEndedBeforeReachingClosingSlashForRegExp); - return Err(ParserError::Common); + break; } else if CharacterValidator::is_line_terminator(ch) { self.add_unexpected_error(); self.consume_line_terminator(); @@ -457,7 +457,7 @@ impl<'input> Tokenizer<'input> { self.consume_line_terminator(); } else if self.characters.reached_end() { self.add_unexpected_eof_error(DiagnosticKind::InputEndedBeforeReachingClosingSlashForRegExp); - return Err(ParserError::Common); + break; } else { body.push(ch); self.characters.next(); @@ -553,7 +553,7 @@ impl<'input> Tokenizer<'input> { self.characters.skip_in_place(); } else { self.add_unexpected_eof_error(DiagnosticKind::InputEndedBeforeReachingClosingSeqForMultiLineComment); - return Err(ParserError::Common); + break; } } @@ -881,7 +881,7 @@ impl<'input> Tokenizer<'input> { self.consume_line_terminator(); } else if !self.characters.has_remaining() { self.add_unexpected_eof_error(DiagnosticKind::InputEndedBeforeReachingClosingQuoteForString); - return Err(ParserError::Common); + break; } else { value.push(ch); self.characters.next(); @@ -901,7 +901,7 @@ impl<'input> Tokenizer<'input> { self.consume_line_terminator(); } else if !self.characters.has_remaining() { self.add_unexpected_eof_error(DiagnosticKind::InputEndedBeforeReachingClosingQuoteForString); - return Err(ParserError::Common); + break; } else { value.push(ch); self.characters.next(); @@ -931,7 +931,7 @@ impl<'input> Tokenizer<'input> { self.consume_line_terminator(); } else if !self.characters.has_remaining() { self.add_unexpected_eof_error(DiagnosticKind::InputEndedBeforeReachingClosingQuoteForString); - return Err(ParserError::Common); + break; } else { builder.push(ch); self.characters.next(); @@ -953,7 +953,7 @@ impl<'input> Tokenizer<'input> { self.consume_line_terminator(); } else if !self.characters.has_remaining() { self.add_unexpected_eof_error(DiagnosticKind::InputEndedBeforeReachingClosingQuoteForString); - return Err(ParserError::Common); + break; } else { builder.push(ch); self.characters.next(); @@ -993,7 +993,7 @@ impl<'input> Tokenizer<'input> { self.characters.next(); if !self.characters.has_remaining() { self.add_unexpected_error(); - return Err(ParserError::Common); + return Ok(Some("".into())); } if self.consume_line_terminator() { return Ok(Some("".into())); @@ -1101,6 +1101,7 @@ impl<'input> Tokenizer<'input> { self.characters.next(); if self.characters.peek_or_zero() != '>' { self.add_unexpected_error(); + /* while self.characters.has_remaining() { self.characters.next(); if self.characters.peek_or_zero() == '>' { @@ -1109,7 +1110,9 @@ impl<'input> Tokenizer<'input> { return Ok((Token::XmlSlashGt, location)); } } - return Err(ParserError::Common); + */ + let location = start.combine_with(self.cursor_location()); + return Ok((Token::XmlSlashGt, location)); } self.characters.next(); let location = start.combine_with(self.cursor_location()); @@ -1127,7 +1130,9 @@ impl<'input> Tokenizer<'input> { } if self.characters.reached_end() { self.add_unexpected_eof_error(DiagnosticKind::InputEndedBeforeReachingClosingQuoteForAttributeValue); - return Err(ParserError::Common) + let value = self.compilation_unit.text()[(start.first_offset + 1)..self.cursor_location().first_offset].to_owned(); + let location = start.combine_with(self.cursor_location()); + return Ok((Token::XmlAttributeValue(value), location)); } let value = self.compilation_unit.text()[(start.first_offset + 1)..self.cursor_location().first_offset].to_owned(); self.characters.next(); @@ -1226,7 +1231,7 @@ impl<'input> Tokenizer<'input> { self.consume_line_terminator(); } else if self.characters.reached_end() { self.add_unexpected_eof_error(DiagnosticKind::InputEndedBeforeReachingClosingSeqForXmlComment); - return Err(ParserError::Common); + break; } else { self.characters.next(); } @@ -1249,7 +1254,7 @@ impl<'input> Tokenizer<'input> { self.consume_line_terminator(); } else if self.characters.reached_end() { self.add_unexpected_eof_error(DiagnosticKind::InputEndedBeforeReachingClosingSeqForCData); - return Err(ParserError::Common); + break; } else { self.characters.next(); } @@ -1272,7 +1277,7 @@ impl<'input> Tokenizer<'input> { self.consume_line_terminator(); } else if self.characters.reached_end() { self.add_unexpected_eof_error(DiagnosticKind::InputEndedBeforeReachingClosingSeqForPi); - return Err(ParserError::Common); + break; } else { self.characters.next(); }