diff --git a/parser/src/parser.rs b/parser/src/parser.rs index ece9ec5..e1f1b56 100644 --- a/parser/src/parser.rs +++ b/parser/src/parser.rs @@ -348,7 +348,7 @@ impl> Parser { let token = self.scanner.next(); match token { None => match self.scanner.get_error() { - None => Err(ScanError::new(self.scanner.mark(), "unexpected eof")), + None => Err(ScanError::new_str(self.scanner.mark(), "unexpected eof")), Some(e) => Err(e), }, Some(tok) => Ok(tok), @@ -402,7 +402,10 @@ impl> Parser { if !self.scanner.stream_started() { let (ev, mark) = self.next_event_impl()?; if ev != Event::StreamStart { - return Err(ScanError::new(mark, "did not find expected ")); + return Err(ScanError::new_str( + mark, + "did not find expected ", + )); } recv.on_event(ev, mark); } @@ -435,7 +438,7 @@ impl> Parser { recv: &mut R, ) -> Result<(), ScanError> { if first_ev != Event::DocumentStart { - return Err(ScanError::new( + return Err(ScanError::new_str( mark, "did not find expected ", )); @@ -561,7 +564,10 @@ impl> Parser { self.skip(); Ok((Event::StreamStart, mark)) } - Token(mark, _) => Err(ScanError::new(mark, "did not find expected ")), + Token(mark, _) => Err(ScanError::new_str( + mark, + "did not find expected ", + )), } } @@ -606,17 +612,17 @@ impl> Parser { Token(mark, TokenType::VersionDirective(_, _)) => { // XXX parsing with warning according to spec //if major != 1 || minor > 2 { - // return Err(ScanError::new(tok.0, + // return Err(ScanError::new_str(tok.0, // "found incompatible YAML document")); //} if version_directive_received { - return Err(ScanError::new(*mark, "duplicate version directive")); + return Err(ScanError::new_str(*mark, "duplicate version directive")); } version_directive_received = true; } Token(mark, TokenType::TagDirective(handle, prefix)) => { if tags.contains_key(handle) { - return Err(ScanError::new(*mark, "the TAG directive must only be given at most once per handle in the same document")); + return Err(ScanError::new_str(*mark, "the TAG directive must only be given at most once per handle in the same document")); } tags.insert(handle.to_string(), prefix.to_string()); } @@ -637,7 +643,7 @@ impl> Parser { self.skip(); Ok((Event::DocumentStart, mark)) } - Token(mark, _) => Err(ScanError::new( + Token(mark, _) => Err(ScanError::new_str( mark, "did not find expected ", )), @@ -682,7 +688,7 @@ impl> Parser { if let Token(mark, TokenType::VersionDirective(..) | TokenType::TagDirective(..)) = *self.peek_token()? { - return Err(ScanError::new( + return Err(ScanError::new_str( mark, "missing explicit document end marker before directive", )); @@ -696,7 +702,7 @@ impl> Parser { fn register_anchor(&mut self, name: String, _: &Marker) -> usize { // anchors can be overridden/reused // if self.anchors.contains_key(name) { - // return Err(ScanError::new(*mark, + // return Err(ScanError::new_str(*mark, // "while parsing anchor, found duplicated anchor")); // } let new_id = self.anchor_id_count; @@ -714,7 +720,7 @@ impl> Parser { if let Token(mark, TokenType::Alias(name)) = self.fetch_token() { match self.anchors.get(&name) { None => { - return Err(ScanError::new( + return Err(ScanError::new_str( mark, "while parsing node, found unknown anchor", )) @@ -788,7 +794,7 @@ impl> Parser { self.pop_state(); Ok((Event::empty_scalar_with_anchor(anchor_id, tag), mark)) } - Token(mark, _) => Err(ScanError::new( + Token(mark, _) => Err(ScanError::new_str( mark, "while parsing a node, did not find expected node content", )), @@ -826,7 +832,7 @@ impl> Parser { self.skip(); Ok((Event::MappingEnd, mark)) } - Token(mark, _) => Err(ScanError::new( + Token(mark, _) => Err(ScanError::new_str( mark, "while parsing a block mapping, did not find expected key", )), @@ -868,7 +874,7 @@ impl> Parser { if !first { match *self.peek_token()? { Token(_, TokenType::FlowEntry) => self.skip(), - Token(mark, _) => return Err(ScanError::new( + Token(mark, _) => return Err(ScanError::new_str( mark, "while parsing a flow mapping, did not find expected ',' or '}'", )), @@ -954,7 +960,7 @@ impl> Parser { self.skip(); } Token(mark, _) if !first => { - return Err(ScanError::new( + return Err(ScanError::new_str( mark, "while parsing a flow sequence, expected ',' or ']'", )); @@ -1026,7 +1032,7 @@ impl> Parser { self.parse_node(true, false) } } - Token(mark, _) => Err(ScanError::new( + Token(mark, _) => Err(ScanError::new_str( mark, "while parsing a block collection, did not find expected '-' indicator", )), @@ -1112,7 +1118,7 @@ impl> Parser { // If the handle is of the form "!foo!", this cannot be a local handle and we need // to error. if handle.len() >= 2 && handle.starts_with('!') && handle.ends_with('!') { - Err(ScanError::new(mark, "the handle wasn't declared")) + Err(ScanError::new_str(mark, "the handle wasn't declared")) } else { Ok(Tag { handle: handle.to_string(), diff --git a/parser/src/scanner.rs b/parser/src/scanner.rs index 70512a6..33ec99b 100644 --- a/parser/src/scanner.rs +++ b/parser/src/scanner.rs @@ -88,7 +88,13 @@ pub struct ScanError { impl ScanError { /// Create a new error from a location and an error string. #[must_use] - pub fn new(loc: Marker, info: &str) -> ScanError { + pub fn new(loc: Marker, info: String) -> ScanError { + ScanError { mark: loc, info } + } + + /// Convenience alias for string slices. + #[must_use] + pub fn new_str(loc: Marker, info: &str) -> ScanError { ScanError { mark: loc, info: info.to_owned(), @@ -674,7 +680,7 @@ impl> Scanner { self.fetch_document_indicator(TokenType::DocumentEnd)?; self.skip_ws_to_eol(SkipTabs::Yes)?; if !is_breakz(self.ch()) { - return Err(ScanError::new( + return Err(ScanError::new_str( self.mark, "invalid content after document end marker", )); @@ -683,7 +689,7 @@ impl> Scanner { } if (self.mark.col as isize) < self.indent { - return Err(ScanError::new(self.mark, "invalid indentation")); + return Err(ScanError::new_str(self.mark, "invalid indentation")); } let c = self.buffer[0]; @@ -720,7 +726,7 @@ impl> Scanner { } '%' | '@' | '`' => Err(ScanError::new( self.mark, - &format!("unexpected character: `{c}'"), + format!("unexpected character: `{c}'"), )), _ => self.fetch_plain_scalar(), } @@ -738,7 +744,7 @@ impl> Scanner { self.fetch_more_tokens()?; } let Some(t) = self.tokens.pop_front() else { - return Err(ScanError::new( + return Err(ScanError::new_str( self.mark, "did not find expected next token", )); @@ -798,7 +804,7 @@ impl> Scanner { && (sk.mark.line < self.mark.line || sk.mark.index + 1024 < self.mark.index) { if sk.required { - return Err(ScanError::new(self.mark, "simple key expect ':'")); + return Err(ScanError::new_str(self.mark, "simple key expect ':'")); } sk.possible = false; } @@ -828,7 +834,7 @@ impl> Scanner { self.skip_ws_to_eol(SkipTabs::Yes)?; // If we have content on that line with a tab, return an error. if !is_breakz(self.ch()) { - return Err(ScanError::new( + return Err(ScanError::new_str( self.mark, "tabs disallowed within this context (block indentation)", )); @@ -884,7 +890,7 @@ impl> Scanner { } if need_whitespace { - Err(ScanError::new(self.mark(), "expected whitespace")) + Err(ScanError::new_str(self.mark(), "expected whitespace")) } else { Ok(()) } @@ -906,7 +912,7 @@ impl> Scanner { } // YAML comments must be preceded by whitespace. '#' if !encountered_tab && !has_yaml_ws => { - return Err(ScanError::new( + return Err(ScanError::new_str( self.mark, "comments must be separated from other tokens by whitespace", )); @@ -944,7 +950,7 @@ impl> Scanner { // had. If one was required, however, that was an error and we must propagate it. for sk in &mut self.simple_keys { if sk.required && sk.possible { - return Err(ScanError::new(self.mark, "simple key expected")); + return Err(ScanError::new_str(self.mark, "simple key expected")); } sk.possible = false; } @@ -991,7 +997,7 @@ impl> Scanner { start_mark, TokenType::TagDirective(String::new(), String::new()), ) - // return Err(ScanError::new(start_mark, + // return Err(ScanError::new_str(start_mark, // "while scanning a directive, found unknown directive name")) } }; @@ -999,7 +1005,7 @@ impl> Scanner { self.skip_ws_to_eol(SkipTabs::Yes)?; if !is_breakz(self.ch()) { - return Err(ScanError::new( + return Err(ScanError::new_str( start_mark, "while scanning a directive, did not find expected comment or line break", )); @@ -1022,7 +1028,7 @@ impl> Scanner { let major = self.scan_version_directive_number(mark)?; if self.ch() != '.' { - return Err(ScanError::new( + return Err(ScanError::new_str( *mark, "while scanning a YAML directive, did not find expected digit or '.' character", )); @@ -1043,14 +1049,14 @@ impl> Scanner { } if string.is_empty() { - return Err(ScanError::new( + return Err(ScanError::new_str( start_mark, "while scanning a directive, could not find expected directive name", )); } if !is_blank_or_breakz(self.ch()) { - return Err(ScanError::new( + return Err(ScanError::new_str( start_mark, "while scanning a directive, found unexpected non-alphabetical character", )); @@ -1064,7 +1070,7 @@ impl> Scanner { let mut length = 0usize; while let Some(digit) = self.look_ch().to_digit(10) { if length + 1 > 9 { - return Err(ScanError::new( + return Err(ScanError::new_str( *mark, "while scanning a YAML directive, found extremely long version number", )); @@ -1075,7 +1081,7 @@ impl> Scanner { } if length == 0 { - return Err(ScanError::new( + return Err(ScanError::new_str( *mark, "while scanning a YAML directive, did not find expected version number", )); @@ -1103,7 +1109,7 @@ impl> Scanner { if is_blank_or_breakz(self.ch()) { Ok(Token(*mark, TokenType::TagDirective(handle, prefix))) } else { - Err(ScanError::new( + Err(ScanError::new_str( *mark, "while scanning TAG, did not find expected whitespace or line break", )) @@ -1154,7 +1160,7 @@ impl> Scanner { // XXX: ex 7.2, an empty scalar can follow a secondary tag Ok(Token(start_mark, TokenType::Tag(handle, suffix))) } else { - Err(ScanError::new( + Err(ScanError::new_str( start_mark, "while scanning a tag, did not find expected whitespace or line break", )) @@ -1164,7 +1170,7 @@ impl> Scanner { fn scan_tag_handle(&mut self, directive: bool, mark: &Marker) -> Result { let mut string = String::new(); if self.look_ch() != '!' { - return Err(ScanError::new( + return Err(ScanError::new_str( *mark, "while scanning a tag, did not find expected '!'", )); @@ -1186,7 +1192,7 @@ impl> Scanner { // It's either the '!' tag or not really a tag handle. If it's a %TAG // directive, it's an error. If it's a tag token, it must be a part of // URI. - return Err(ScanError::new( + return Err(ScanError::new_str( *mark, "while parsing a tag directive, did not find expected '!'", )); @@ -1208,7 +1214,10 @@ impl> Scanner { self.skip_non_blank(); } else if !is_tag_char(self.ch()) { // Otherwise, check if the first global tag character is valid. - return Err(ScanError::new(*start_mark, "invalid global tag character")); + return Err(ScanError::new_str( + *start_mark, + "invalid global tag character", + )); } else if self.ch() == '%' { // If it is valid and an escape sequence, escape it. string.push(self.scan_uri_escapes(start_mark)?); @@ -1249,7 +1258,7 @@ impl> Scanner { } if self.ch() != '>' { - return Err(ScanError::new( + return Err(ScanError::new_str( *start_mark, "while scanning a verbatim tag, did not find the expected '>'", )); @@ -1288,7 +1297,7 @@ impl> Scanner { } if length == 0 { - return Err(ScanError::new( + return Err(ScanError::new_str( *mark, "while parsing a tag, did not find expected tag URI", )); @@ -1304,7 +1313,7 @@ impl> Scanner { self.lookahead(3); if !(self.ch() == '%' && is_hex(self.buffer[1]) && is_hex(self.buffer[2])) { - return Err(ScanError::new( + return Err(ScanError::new_str( *mark, "while parsing a tag, did not find URI escaped octet", )); @@ -1318,7 +1327,7 @@ impl> Scanner { _ if octet & 0xF0 == 0xE0 => 3, _ if octet & 0xF8 == 0xF0 => 4, _ => { - return Err(ScanError::new( + return Err(ScanError::new_str( *mark, "while parsing a tag, found an incorrect leading UTF-8 octet", )); @@ -1327,7 +1336,7 @@ impl> Scanner { code = octet; } else { if octet & 0xc0 != 0x80 { - return Err(ScanError::new( + return Err(ScanError::new_str( *mark, "while parsing a tag, found an incorrect trailing UTF-8 octet", )); @@ -1345,7 +1354,7 @@ impl> Scanner { match char::from_u32(code) { Some(ch) => Ok(ch), - None => Err(ScanError::new( + None => Err(ScanError::new_str( *mark, "while parsing a tag, found an invalid UTF-8 codepoint", )), @@ -1374,7 +1383,7 @@ impl> Scanner { } if string.is_empty() { - return Err(ScanError::new(start_mark, "while scanning an anchor or alias, did not find expected alphabetic or numeric character")); + return Err(ScanError::new_str(start_mark, "while scanning an anchor or alias, did not find expected alphabetic or numeric character")); } if alias { @@ -1452,7 +1461,7 @@ impl> Scanner { self.flow_level = self .flow_level .checked_add(1) - .ok_or_else(|| ScanError::new(self.mark, "recursion limit exceeded"))?; + .ok_or_else(|| ScanError::new_str(self.mark, "recursion limit exceeded"))?; Ok(()) } @@ -1471,14 +1480,14 @@ impl> Scanner { fn fetch_block_entry(&mut self) -> ScanResult { if self.flow_level > 0 { // - * only allowed in block - return Err(ScanError::new( + return Err(ScanError::new_str( self.mark, r#""-" is only valid inside a block"#, )); } // Check if we are allowed to start a new entry. if !self.simple_key_allowed { - return Err(ScanError::new( + return Err(ScanError::new_str( self.mark, "block sequence entries are not allowed in this context", )); @@ -1487,7 +1496,7 @@ impl> Scanner { // ???, fixes test G9HC. if let Some(Token(mark, TokenType::Anchor(..) | TokenType::Tag(..))) = self.tokens.back() { if self.mark.col == 0 && mark.col == 0 && self.indent > -1 { - return Err(ScanError::new(*mark, "invalid indentation for anchor")); + return Err(ScanError::new_str(*mark, "invalid indentation for anchor")); } } @@ -1500,7 +1509,7 @@ impl> Scanner { let found_tabs = self.skip_ws_to_eol(SkipTabs::Yes)?.found_tabs(); self.lookahead(2); if found_tabs && self.buffer[0] == '-' && is_blank_or_breakz(self.buffer[1]) { - return Err(ScanError::new( + return Err(ScanError::new_str( self.mark, "'-' must be followed by a valid YAML whitespace", )); @@ -1574,7 +1583,7 @@ impl> Scanner { self.skip_non_blank(); if is_digit(self.look_ch()) { if self.ch() == '0' { - return Err(ScanError::new( + return Err(ScanError::new_str( start_mark, "while scanning a block scalar, found an indentation indicator equal to 0", )); @@ -1584,7 +1593,7 @@ impl> Scanner { } } else if is_digit(self.ch()) { if self.ch() == '0' { - return Err(ScanError::new( + return Err(ScanError::new_str( start_mark, "while scanning a block scalar, found an indentation indicator equal to 0", )); @@ -1607,7 +1616,7 @@ impl> Scanner { // Check if we are at the end of the line. if !is_breakz(self.look_ch()) { - return Err(ScanError::new( + return Err(ScanError::new_str( start_mark, "while scanning a block scalar, did not find expected comment or line break", )); @@ -1619,7 +1628,7 @@ impl> Scanner { } if self.look_ch() == '\t' { - return Err(ScanError::new( + return Err(ScanError::new_str( start_mark, "a block scalar content cannot start with a tab", )); @@ -1663,7 +1672,7 @@ impl> Scanner { } if self.mark.col < indent && (self.mark.col as isize) > self.indent { - return Err(ScanError::new( + return Err(ScanError::new_str( self.mark, "wrongly indented line in block scalar", )); @@ -1891,21 +1900,21 @@ impl> Scanner { && (self.buffer[2] == '.'))) && is_blank_or_breakz(self.buffer[3]) { - return Err(ScanError::new( + return Err(ScanError::new_str( start_mark, "while scanning a quoted scalar, found unexpected document indicator", )); } if is_z(self.ch()) { - return Err(ScanError::new( + return Err(ScanError::new_str( start_mark, "while scanning a quoted scalar, found unexpected end of stream", )); } if (self.mark.col as isize) < self.indent { - return Err(ScanError::new( + return Err(ScanError::new_str( start_mark, "invalid indentation in quoted scalar", )); @@ -1931,7 +1940,7 @@ impl> Scanner { // Consume a space or a tab character. if leading_blanks { if self.ch() == '\t' && (self.mark.col as isize) < self.indent { - return Err(ScanError::new( + return Err(ScanError::new_str( self.mark, "tab cannot be used as indentation", )); @@ -1992,7 +2001,7 @@ impl> Scanner { // Inside a flow context, this is allowed. ':' if self.flow_level > 0 => {} _ => { - return Err(ScanError::new( + return Err(ScanError::new_str( self.mark, "invalid trailing content after double-quoted scalar", )); @@ -2094,7 +2103,7 @@ impl> Scanner { 'u' => code_length = 4, 'U' => code_length = 8, _ => { - return Err(ScanError::new( + return Err(ScanError::new_str( *start_mark, "while parsing a quoted scalar, found unknown escape character", )) @@ -2108,7 +2117,7 @@ impl> Scanner { let mut value = 0u32; for i in 0..code_length { if !is_hex(self.buffer[i]) { - return Err(ScanError::new( + return Err(ScanError::new_str( *start_mark, "while parsing a quoted scalar, did not find expected hexadecimal number", )); @@ -2117,7 +2126,7 @@ impl> Scanner { } let Some(ch) = char::from_u32(value) else { - return Err(ScanError::new( + return Err(ScanError::new_str( *start_mark, "while parsing a quoted scalar, found invalid Unicode character escape code", )); @@ -2150,7 +2159,7 @@ impl> Scanner { let start_mark = self.mark; if self.flow_level > 0 && (start_mark.col as isize) < indent { - return Err(ScanError::new( + return Err(ScanError::new_str( start_mark, "invalid indentation in flow construct", )); @@ -2168,7 +2177,7 @@ impl> Scanner { } if self.flow_level > 0 && self.ch() == '-' && is_flow(self.buffer[1]) { - return Err(ScanError::new( + return Err(ScanError::new_str( self.mark, "plain scalar cannot start with '-' followed by ,[]{}", )); @@ -2232,7 +2241,7 @@ impl> Scanner { // empty. Skip to the end of the line. self.skip_ws_to_eol(SkipTabs::Yes)?; if !is_breakz(self.ch()) { - return Err(ScanError::new( + return Err(ScanError::new_str( start_mark, "while scanning a plain scalar, found a tab", )); @@ -2274,7 +2283,7 @@ impl> Scanner { if self.flow_level == 0 { // Check if we are allowed to start a new key (not necessarily simple). if !self.simple_key_allowed { - return Err(ScanError::new( + return Err(ScanError::new_str( self.mark, "mapping keys are not allowed in this context", )); @@ -2301,7 +2310,7 @@ impl> Scanner { self.skip_non_blank(); self.skip_yaml_whitespace()?; if self.ch() == '\t' { - return Err(ScanError::new( + return Err(ScanError::new_str( self.mark(), "tabs disallowed in this context", )); @@ -2322,7 +2331,7 @@ impl> Scanner { && !self.skip_ws_to_eol(SkipTabs::Yes)?.has_valid_yaml_ws() && (self.ch() == '-' || is_alpha(self.ch())) { - return Err(ScanError::new( + return Err(ScanError::new_str( self.mark, "':' must be followed by a valid YAML whitespace", )); @@ -2334,7 +2343,7 @@ impl> Scanner { self.insert_token(sk.token_number - self.tokens_parsed, tok); if self.implicit_flow_mapping { if sk.mark.line < start_mark.line { - return Err(ScanError::new( + return Err(ScanError::new_str( start_mark, "illegal placement of ':' indicator", )); @@ -2364,7 +2373,7 @@ impl> Scanner { // The ':' indicator follows a complex key. if self.flow_level == 0 { if !self.simple_key_allowed { - return Err(ScanError::new( + return Err(ScanError::new_str( start_mark, "mapping values are not allowed in this context", )); @@ -2489,7 +2498,7 @@ impl> Scanner { fn remove_simple_key(&mut self) -> ScanResult { let last = self.simple_keys.last_mut().unwrap(); if last.possible && last.required { - return Err(ScanError::new(self.mark, "simple key expected")); + return Err(ScanError::new_str(self.mark, "simple key expected")); } last.possible = false;