diff --git a/cfgrammar/src/lib/header.rs b/cfgrammar/src/lib/header.rs index 4598c4638..8b2e0f266 100644 --- a/cfgrammar/src/lib/header.rs +++ b/cfgrammar/src/lib/header.rs @@ -594,10 +594,10 @@ impl TryFrom<&Value> for YaccKind { namespace, member: (yk_value, yk_value_loc), })) => { - if let Some((ns, ns_loc)) = namespace { - if ns != "yacckind" { - err_locs.push(ns_loc.clone()); - } + if let Some((ns, ns_loc)) = namespace + && ns != "yacckind" + { + err_locs.push(ns_loc.clone()); } let yacckinds = [ ("grmtools".to_string(), YaccKind::Grmtools), @@ -635,20 +635,20 @@ impl TryFrom<&Value> for YaccKind { member: (ak_str, ak_loc), }, }) => { - if let Some((yk_ns, yk_ns_loc)) = yk_namespace { - if yk_ns != "yacckind" { - err_locs.push(yk_ns_loc.clone()); - } + if let Some((yk_ns, yk_ns_loc)) = yk_namespace + && yk_ns != "yacckind" + { + err_locs.push(yk_ns_loc.clone()); } if yk_str != "original" { err_locs.push(yk_loc.clone()); } - if let Some((ak_ns, ak_ns_loc)) = ak_namespace { - if ak_ns != "yaccoriginalactionkind" { - err_locs.push(ak_ns_loc.clone()); - } + if let Some((ak_ns, ak_ns_loc)) = ak_namespace + && ak_ns != "yaccoriginalactionkind" + { + err_locs.push(ak_ns_loc.clone()); } let actionkinds = [ ("noaction", YaccOriginalActionKind::NoAction), diff --git a/cfgrammar/src/lib/yacc/ast.rs b/cfgrammar/src/lib/yacc/ast.rs index 32e96d255..b860385c0 100644 --- a/cfgrammar/src/lib/yacc/ast.rs +++ b/cfgrammar/src/lib/yacc/ast.rs @@ -370,10 +370,10 @@ impl GrammarAST { if self.tokens.contains(k) { continue; } - if let Some(ref it) = self.implicit_tokens { - if it.contains_key(k) { - continue; - } + if let Some(ref it) = self.implicit_tokens + && it.contains_key(k) + { + continue; } return Err(YaccGrammarError { kind: YaccGrammarErrorKind::UnknownEPP(k.clone()), @@ -454,10 +454,10 @@ impl GrammarAST { for sym in &prod.symbols { match sym { Symbol::Rule(name, _) => { - if seen_rules.insert(name) { - if let Some(rule) = self.rules.get(name) { - todo.extend(&rule.pidxs); - } + if seen_rules.insert(name) + && let Some(rule) = self.rules.get(name) + { + todo.extend(&rule.pidxs); } } Symbol::Token(name, _) => { diff --git a/cfgrammar/src/lib/yacc/grammar.rs b/cfgrammar/src/lib/yacc/grammar.rs index 242b59097..1a86c0754 100644 --- a/cfgrammar/src/lib/yacc/grammar.rs +++ b/cfgrammar/src/lib/yacc/grammar.rs @@ -380,7 +380,7 @@ where // Add the implicit rule: ~: "IMPLICIT_TOKEN_1" ~ | ... | "IMPLICIT_TOKEN_N" ~ | ; let implicit_prods = &mut rules_prods[usize::from(rule_map[astrulename])]; // Add a production for each implicit token - for (t, _) in ast.implicit_tokens.as_ref().unwrap().iter() { + for t in ast.implicit_tokens.as_ref().unwrap().keys() { implicit_prods.push(PIdx(prods.len().as_())); prods.push(Some(vec![Symbol::Token(token_map[t]), Symbol::Rule(ridx)])); prod_precs.push(Some(None)); diff --git a/cfgrammar/src/lib/yacc/parser.rs b/cfgrammar/src/lib/yacc/parser.rs index b3a95c715..a55b64e66 100644 --- a/cfgrammar/src/lib/yacc/parser.rs +++ b/cfgrammar/src/lib/yacc/parser.rs @@ -388,24 +388,24 @@ impl YaccParser<'_> { } continue; } - if let YaccKind::Original(_) = self.yacc_kind { - if let Some(j) = self.lookahead_is("%actiontype", i) { - i = self.parse_ws(j, false)?; - let (j, n) = self.parse_to_eol(i)?; - let span = Span::new(i, j); - if let Some((_, orig_span)) = self.global_actiontype { - add_duplicate_occurrence( - errs, - YaccGrammarErrorKind::DuplicateActiontypeDeclaration, - orig_span, - span, - ); - } else { - self.global_actiontype = Some((n, span)); - } - i = self.parse_ws(j, true)?; - continue; + if let YaccKind::Original(_) = self.yacc_kind + && let Some(j) = self.lookahead_is("%actiontype", i) + { + i = self.parse_ws(j, false)?; + let (j, n) = self.parse_to_eol(i)?; + let span = Span::new(i, j); + if let Some((_, orig_span)) = self.global_actiontype { + add_duplicate_occurrence( + errs, + YaccGrammarErrorKind::DuplicateActiontypeDeclaration, + orig_span, + span, + ); + } else { + self.global_actiontype = Some((n, span)); } + i = self.parse_ws(j, true)?; + continue; } if let Some(j) = self.lookahead_is("%start", i) { i = self.parse_ws(j, false)?; @@ -556,36 +556,36 @@ impl YaccParser<'_> { i = self.parse_ws(j, true)?; continue; } - if let YaccKind::Eco = self.yacc_kind { - if let Some(j) = self.lookahead_is("%implicit_tokens", i) { - i = self.parse_ws(j, false)?; - let num_newlines = self.num_newlines; - if self.ast.implicit_tokens.is_none() { - self.ast.implicit_tokens = Some(HashMap::new()); + if let YaccKind::Eco = self.yacc_kind + && let Some(j) = self.lookahead_is("%implicit_tokens", i) + { + i = self.parse_ws(j, false)?; + let num_newlines = self.num_newlines; + if self.ast.implicit_tokens.is_none() { + self.ast.implicit_tokens = Some(HashMap::new()); + } + while j < self.src.len() && self.num_newlines == num_newlines { + let (j, n, span, _) = self.parse_token(i)?; + if self.ast.tokens.insert(n.clone()) { + self.ast.spans.push(span); } - while j < self.src.len() && self.num_newlines == num_newlines { - let (j, n, span, _) = self.parse_token(i)?; - if self.ast.tokens.insert(n.clone()) { - self.ast.spans.push(span); + match self.ast.implicit_tokens.as_mut().unwrap().entry(n) { + Entry::Occupied(entry) => { + let orig_span = *entry.get(); + add_duplicate_occurrence( + errs, + YaccGrammarErrorKind::DuplicateImplicitTokensDeclaration, + orig_span, + span, + ); } - match self.ast.implicit_tokens.as_mut().unwrap().entry(n) { - Entry::Occupied(entry) => { - let orig_span = *entry.get(); - add_duplicate_occurrence( - errs, - YaccGrammarErrorKind::DuplicateImplicitTokensDeclaration, - orig_span, - span, - ); - } - Entry::Vacant(entry) => { - entry.insert(span); - } + Entry::Vacant(entry) => { + entry.insert(span); } - i = self.parse_ws(j, true)?; } - continue; + i = self.parse_ws(j, true)?; } + continue; } { let k; @@ -1703,7 +1703,7 @@ x" #[test] fn test_dup_precs() { #[rustfmt::skip] - let srcs = vec![ + let srcs = [ (" %left 'x' %left 'x' diff --git a/lrlex/src/lib/ctbuilder.rs b/lrlex/src/lib/ctbuilder.rs index 1820c4ff5..99cb99d8b 100644 --- a/lrlex/src/lib/ctbuilder.rs +++ b/lrlex/src/lib/ctbuilder.rs @@ -101,16 +101,16 @@ impl TryFrom<&Value> for LexerKind { namespace, member: (member, member_loc), })) => { - if let Some((ns, loc)) = namespace { - if ns.to_lowercase() != "lexerkind" { - return Err(HeaderError { - kind: HeaderErrorKind::ConversionError( - "LexerKind", - "Expected namespace `LexerKind`", - ), - locations: vec![loc.clone()], - }); - } + if let Some((ns, loc)) = namespace + && ns.to_lowercase() != "lexerkind" + { + return Err(HeaderError { + kind: HeaderErrorKind::ConversionError( + "LexerKind", + "Expected namespace `LexerKind`", + ), + locations: vec![loc.clone()], + }); } if member.to_lowercase() != "lrnonstreaminglexer" { return Err(HeaderError { @@ -473,7 +473,7 @@ where { let mut lk = GENERATED_PATHS.lock().unwrap(); if lk.contains(outp.as_path()) { - return Err(format!("Generating two lexers to the same path ('{}') is not allowed: use CTLexerBuilder::output_path (and, optionally, CTLexerBuilder::mod_name) to differentiate them.", &outp.to_str().unwrap()).into()); + return Err(format!("Generating two lexers to the same path ('{}') is not allowed: use CTLexerBuilder::output_path (and, optionally, CTLexerBuilder::mod_name) to differentiate them.", outp.to_str().unwrap()).into()); } lk.insert(outp.clone()); } @@ -572,13 +572,11 @@ where for path in glob_paths { let path = path?; - if let Some(ext) = path.extension() { - if let Some(ext) = ext.to_str() { - if ext.starts_with("grm") { + if let Some(ext) = path.extension() + && let Some(ext) = ext.to_str() + && ext.starts_with("grm") { add_error_line(&mut err_str, "test_files extensions beginning with `grm` are reserved.".into()); } - } - } let input = fs::read_to_string(&path)?; let l: LRNonStreamingLexer = closure_lexerdef.lexer(&input); @@ -648,87 +646,88 @@ where let mut has_unallowed_missing = false; let err_indent = " ".repeat(ERROR.len()); - if !self.allow_missing_terms_in_lexer { - if let Some(ref mfl) = missing_from_lexer { - if let Some(ct_parser) = &ct_parser { - let grm = ct_parser.yacc_grammar(); - let token_spans = mfl - .iter() - .map(|name| { - ct_parser - .yacc_grammar() - .token_span(*grm.tokens_map().get(name.as_str()).unwrap()) - .expect("Given token should have a span") - }) - .collect::>(); - - let yacc_diag = SpannedDiagnosticFormatter::new( - ct_parser.grammar_src(), - ct_parser.grammar_path(), - ); + if !self.allow_missing_terms_in_lexer + && let Some(ref mfl) = missing_from_lexer + { + if let Some(ct_parser) = &ct_parser { + let grm = ct_parser.yacc_grammar(); + let token_spans = mfl + .iter() + .map(|name| { + ct_parser + .yacc_grammar() + .token_span(*grm.tokens_map().get(name.as_str()).unwrap()) + .expect("Given token should have a span") + }) + .collect::>(); + + let yacc_diag = SpannedDiagnosticFormatter::new( + ct_parser.grammar_src(), + ct_parser.grammar_path(), + ); + eprintln!( + "{ERROR} these tokens are not referenced in the lexer but defined as follows" + ); + eprintln!( + "{err_indent} {}", + yacc_diag.file_location_msg("in the grammar", None) + ); + for span in token_spans { eprintln!( - "{ERROR} these tokens are not referenced in the lexer but defined as follows" - ); - eprintln!( - "{err_indent} {}", - yacc_diag.file_location_msg("in the grammar", None) - ); - for span in token_spans { - eprintln!( - "{}", - yacc_diag.underline_span_with_text( - span, - "Missing from lexer".to_string(), - '^' - ) - ); - } - eprintln!(); - } else { - eprintln!( - "{ERROR} the following tokens are used in the grammar but are not defined in the lexer:" + "{}", + yacc_diag.underline_span_with_text( + span, + "Missing from lexer".to_string(), + '^' + ) ); - for n in mfl { - eprintln!(" {}", n); - } } - has_unallowed_missing = true; + eprintln!(); + } else { + eprintln!( + "{ERROR} the following tokens are used in the grammar but are not defined in the lexer:" + ); + for n in mfl { + eprintln!(" {}", n); + } } + has_unallowed_missing = true; } - if !self.allow_missing_tokens_in_parser && self.show_warnings { - if let Some(ref mfp) = missing_from_parser { - let error_prefix = if self.warnings_are_errors { - ERROR - } else { - WARNING - }; - let err_indent = " ".repeat(error_prefix.len()); - let mut outs = Vec::new(); - outs.push(format!("{error_prefix} these tokens are not referenced in the grammar but defined as follows")); - outs.push(format!( - "{err_indent} {}", - lex_diag.file_location_msg("in the lexer", None) - )); - for (_, span) in mfp { - let error_contents = lex_diag.underline_span_with_text( - *span, - "Missing from parser".to_string(), - '^', - ); - outs.extend(error_contents.lines().map(|s| s.to_string())); - } + if !self.allow_missing_tokens_in_parser + && self.show_warnings + && let Some(ref mfp) = missing_from_parser + { + let error_prefix = if self.warnings_are_errors { + ERROR + } else { + WARNING + }; + let err_indent = " ".repeat(error_prefix.len()); + let mut outs = Vec::new(); + outs.push(format!("{error_prefix} these tokens are not referenced in the grammar but defined as follows")); + outs.push(format!( + "{err_indent} {}", + lex_diag.file_location_msg("in the lexer", None) + )); + for (_, span) in mfp { + let error_contents = lex_diag.underline_span_with_text( + *span, + "Missing from parser".to_string(), + '^', + ); + outs.extend(error_contents.lines().map(|s| s.to_string())); + } - for s in outs { - if !self.warnings_are_errors && std::env::var("OUT_DIR").is_ok() { - println!("cargo:warning={}", s) - } else { - eprintln!("{}", s); - } + for s in outs { + if !self.warnings_are_errors && std::env::var("OUT_DIR").is_ok() { + println!("cargo:warning={}", s) + } else { + eprintln!("{}", s); } - - has_unallowed_missing |= self.warnings_are_errors; } + + has_unallowed_missing |= self.warnings_are_errors; } if has_unallowed_missing { fs::remove_file(outp).ok(); @@ -894,13 +893,13 @@ where // If the file we're about to write out already exists with the same contents, then we // don't overwrite it (since that will force a recompile of the file, and relinking of the // binary etc). - if let Ok(curs) = read_to_string(outp) { - if curs == outs { - return Ok(CTLexer { - missing_from_lexer, - missing_from_parser, - }); - } + if let Ok(curs) = read_to_string(outp) + && curs == outs + { + return Ok(CTLexer { + missing_from_lexer, + missing_from_parser, + }); } let mut f = File::create(outp)?; f.write_all(outs.as_bytes())?; @@ -1410,10 +1409,10 @@ impl CTTokenMapBuilder { // If the file we're about to write out already exists with the same contents, then we // don't overwrite it (since that will force a recompile of the file, and relinking of the // binary etc). - if let Ok(curs) = read_to_string(&outp) { - if curs == outs { - return Ok(()); - } + if let Ok(curs) = read_to_string(&outp) + && curs == outs + { + return Ok(()); } let mut f = File::create(outp)?; diff --git a/lrlex/src/lib/parser.rs b/lrlex/src/lib/parser.rs index bfb5f31d3..c3236b587 100644 --- a/lrlex/src/lib/parser.rs +++ b/lrlex/src/lib/parser.rs @@ -755,7 +755,7 @@ mod test { assert_eq!(errs.len(), 1); let e = &errs[0]; if !e.kind.is_same_kind(&kind) { - panic!("expected {:?}.is_same_kind({:?})", &e.kind, &kind); + panic!("expected {:?}.is_same_kind({:?})", e.kind, kind); } assert_eq!( e.spans() diff --git a/lrlex/src/main.rs b/lrlex/src/main.rs index 827244733..93b798395 100644 --- a/lrlex/src/main.rs +++ b/lrlex/src/main.rs @@ -90,10 +90,7 @@ fn main() -> Result<(), Box> { lex_diag.file_location_msg(" parsing the `%grmtools` section", None) ); for e in es { - eprintln!( - "{}", - &indent(" ", &lex_diag.format_error(e).to_string()) - ); + eprintln!("{}", indent(" ", &lex_diag.format_error(e).to_string())); } process::exit(1); } @@ -115,10 +112,7 @@ fn main() -> Result<(), Box> { Err(errs) => { eprintln!("\n{ERROR}{}", lex_diag.file_location_msg("", None)); for e in errs { - eprintln!( - "{}", - &indent(" ", &lex_diag.format_error(e).to_string()) - ); + eprintln!("{}", indent(" ", &lex_diag.format_error(e).to_string())); } process::exit(1); } diff --git a/lrpar/examples/clone_param/src/main.rs b/lrpar/examples/clone_param/src/main.rs index 115397e6f..a44eab6e4 100644 --- a/lrpar/examples/clone_param/src/main.rs +++ b/lrpar/examples/clone_param/src/main.rs @@ -32,7 +32,7 @@ fn main() { for e in errs { println!("{}", e.pp(&lexer, ¶m_y::token_epp)); } - println!("Evaluated: {:?}", ¶m); + println!("Evaluated: {:?}", param); } _ => break, } diff --git a/lrpar/src/lib/cpctplus.rs b/lrpar/src/lib/cpctplus.rs index 7f4a999fd..1fa3d279a 100644 --- a/lrpar/src/lib/cpctplus.rs +++ b/lrpar/src/lib/cpctplus.rs @@ -539,10 +539,10 @@ fn simplify_repairs< // 2) by the number of repairs they contain let contains_avoid_insert = |rprs: &Vec>| -> bool { for r in rprs.iter() { - if let ParseRepair::Insert(tidx) = r { - if parser.grm.avoid_insert(*tidx) { - return true; - } + if let ParseRepair::Insert(tidx) = r + && parser.grm.avoid_insert(*tidx) + { + return true; } } false diff --git a/lrpar/src/lib/ctbuilder.rs b/lrpar/src/lib/ctbuilder.rs index 897cfa1ef..1ba0926c5 100644 --- a/lrpar/src/lib/ctbuilder.rs +++ b/lrpar/src/lib/ctbuilder.rs @@ -573,7 +573,7 @@ where { let mut lk = GENERATED_PATHS.lock().unwrap(); if lk.contains(outp.as_path()) { - return Err(format!("Generating two parsers to the same path ('{}') is not allowed: use CTParserBuilder::output_path (and, optionally, CTParserBuilder::mod_name) to differentiate them.", &outp.to_str().unwrap()).into()); + return Err(format!("Generating two parsers to the same path ('{}') is not allowed: use CTParserBuilder::output_path (and, optionally, CTParserBuilder::mod_name) to differentiate them.", outp.to_str().unwrap()).into()); } lk.insert(outp.clone()); } @@ -586,245 +586,245 @@ where let yacc_diag = SpannedDiagnosticFormatter::new(&inc, grmp); let parsed_header = GrmtoolsSectionParser::new(&inc, false).parse(); - if let Err(errs) = parsed_header { - let mut out = String::new(); - out.push_str(&format!( - "\n{ERROR}{}\n", - yacc_diag.file_location_msg(" parsing the `%grmtools` section", None) - )); - for e in errs { - out.push_str(&indent(" ", &yacc_diag.format_error(e).to_string())); - } - return Err(ErrorString(out))?; - } - let (parsed_header, _) = parsed_header.unwrap(); - header.merge_from(parsed_header)?; - self.yacckind = header - .get("yacckind") - .map(|HeaderValue(_, val)| val) - .map(YaccKind::try_from) - .transpose()?; - header.mark_used(&"yacckind".to_string()); - let ast_validation = if let Some(ast) = &self.from_ast { - ast.clone() - } else if let Some(yk) = self.yacckind { - ASTWithValidityInfo::new(yk, &inc) - } else { - Err("Missing 'yacckind'".to_string())? - }; - - header.mark_used(&"recoverer".to_string()); - let rk_val = header.get("recoverer").map(|HeaderValue(_, rk_val)| rk_val); - - if let Some(rk_val) = rk_val { - self.recoverer = Some(RecoveryKind::try_from(rk_val)?); - } else { - // Fallback to the default recoverykind. - self.recoverer = Some(RecoveryKind::CPCTPlus); - } - self.yacckind = Some(ast_validation.yacc_kind()); - let warnings = ast_validation.ast().warnings(); - let res = YaccGrammar::::new_from_ast_with_validity_info(&ast_validation); - let grm = match res { - Ok(_) if self.warnings_are_errors && !warnings.is_empty() => { - let mut out = String::new(); - out.push_str(&format!( - "\n{ERROR}{}\n", - yacc_diag.file_location_msg("", None) - )); - for e in warnings { - out.push_str(&format!( - "{}\n", - indent(" ", &yacc_diag.format_warning(e).to_string()) - )); - } - return Err(ErrorString(out))?; - } - Ok(grm) => { - if !warnings.is_empty() { - for w in warnings { - let ws_loc = yacc_diag.file_location_msg("", None); - let ws = indent(" ", &yacc_diag.format_warning(w).to_string()); - // Assume if this variable is set we are running under cargo. - if std::env::var("OUT_DIR").is_ok() && self.show_warnings { - for line in ws_loc.lines().chain(ws.lines()) { - println!("cargo:warning={}", line); - } - } else if self.show_warnings { - eprintln!("{}", ws_loc); - eprintln!("{WARNING} {}", ws); - } - } - } - grm - } + match parsed_header { Err(errs) => { let mut out = String::new(); out.push_str(&format!( "\n{ERROR}{}\n", - yacc_diag.file_location_msg("", None) + yacc_diag.file_location_msg(" parsing the `%grmtools` section", None) )); for e in errs { out.push_str(&indent(" ", &yacc_diag.format_error(e).to_string())); - out.push('\n'); } - return Err(ErrorString(out))?; } - }; + Ok((parsed_header, _)) => { + header.merge_from(parsed_header)?; + self.yacckind = header + .get("yacckind") + .map(|HeaderValue(_, val)| val) + .map(YaccKind::try_from) + .transpose()?; + header.mark_used(&"yacckind".to_string()); + let ast_validation = if let Some(ast) = &self.from_ast { + ast.clone() + } else if let Some(yk) = self.yacckind { + ASTWithValidityInfo::new(yk, &inc) + } else { + Err("Missing 'yacckind'".to_string())? + }; - #[cfg(test)] - if let Some(cb) = &self.inspect_callback { - cb(self.recoverer.expect("has a default value"))?; - } + header.mark_used(&"recoverer".to_string()); + let rk_val = header.get("recoverer").map(|HeaderValue(_, rk_val)| rk_val); - let rule_ids = grm - .tokens_map() - .iter() - .map(|(&n, &i)| (n.to_owned(), i.as_storaget())) - .collect::>(); + if let Some(rk_val) = rk_val { + self.recoverer = Some(RecoveryKind::try_from(rk_val)?); + } else { + // Fallback to the default recoverykind. + self.recoverer = Some(RecoveryKind::CPCTPlus); + } + self.yacckind = Some(ast_validation.yacc_kind()); + let warnings = ast_validation.ast().warnings(); + let res = YaccGrammar::::new_from_ast_with_validity_info(&ast_validation); + let grm = match res { + Ok(_) if self.warnings_are_errors && !warnings.is_empty() => { + let mut out = String::new(); + out.push_str(&format!( + "\n{ERROR}{}\n", + yacc_diag.file_location_msg("", None) + )); + for e in warnings { + out.push_str(&format!( + "{}\n", + indent(" ", &yacc_diag.format_warning(e).to_string()) + )); + } + return Err(ErrorString(out))?; + } + Ok(grm) => { + if !warnings.is_empty() { + for w in warnings { + let ws_loc = yacc_diag.file_location_msg("", None); + let ws = indent(" ", &yacc_diag.format_warning(w).to_string()); + // Assume if this variable is set we are running under cargo. + if std::env::var("OUT_DIR").is_ok() && self.show_warnings { + for line in ws_loc.lines().chain(ws.lines()) { + println!("cargo:warning={}", line); + } + } else if self.show_warnings { + eprintln!("{}", ws_loc); + eprintln!("{WARNING} {}", ws); + } + } + } + grm + } + Err(errs) => { + let mut out = String::new(); + out.push_str(&format!( + "\n{ERROR}{}\n", + yacc_diag.file_location_msg("", None) + )); + for e in errs { + out.push_str(&indent(" ", &yacc_diag.format_error(e).to_string())); + out.push('\n'); + } - let derived_mod_name = match self.mod_name { - Some(s) => s.to_owned(), - None => { - // The user hasn't specified a module name, so we create one automatically: what we - // do is strip off all the filename extensions (note that it's likely that inp ends - // with `y.rs`, so we potentially have to strip off more than one extension) and - // then add `_y` to the end. - let mut stem = grmp.to_str().unwrap(); - loop { - let new_stem = Path::new(stem).file_stem().unwrap().to_str().unwrap(); - if stem == new_stem { - break; + return Err(ErrorString(out))?; } - stem = new_stem; + }; + + #[cfg(test)] + if let Some(cb) = &self.inspect_callback { + cb(self.recoverer.expect("has a default value"))?; } - format!("{}_y", stem) - } - }; - let cache = self.rebuild_cache(&derived_mod_name, &grm); - - // We don't need to go through the full rigmarole of generating an output file if all of - // the following are true: the output file exists; it is newer than the input file; and the - // cache hasn't changed. The last of these might be surprising, but it's vital: we don't - // know, for example, what the IDs map might be from one run to the next, and it might - // change for reasons beyond lrpar's control. If it does change, that means that the lexer - // and lrpar would get out of sync, so we have to play it safe and regenerate in such - // cases. - if let Ok(ref inmd) = fs::metadata(grmp) { - if let Ok(ref out_rs_md) = fs::metadata(outp) { - if FileTime::from_last_modification_time(out_rs_md) - > FileTime::from_last_modification_time(inmd) - { - if let Ok(outc) = read_to_string(outp) { - if outc.contains(&cache.to_string()) { - return Ok(CTParser { - regenerated: false, - rule_ids, - yacc_grammar: grm, - grammar_src: inc, - grammar_path: self.grammar_path.unwrap(), - conflicts: None, - }); - } else { - #[cfg(grmtools_extra_checks)] - if std::env::var("CACHE_EXPECTED").is_ok() { - eprintln!("outc: {}", outc); - eprintln!("using cache: {}", cache,); - // Primarily for use in the testsuite. - panic!("The cache regenerated however, it was expected to match"); + let rule_ids = grm + .tokens_map() + .iter() + .map(|(&n, &i)| (n.to_owned(), i.as_storaget())) + .collect::>(); + + let derived_mod_name = match self.mod_name { + Some(s) => s.to_owned(), + None => { + // The user hasn't specified a module name, so we create one automatically: what we + // do is strip off all the filename extensions (note that it's likely that inp ends + // with `y.rs`, so we potentially have to strip off more than one extension) and + // then add `_y` to the end. + let mut stem = grmp.to_str().unwrap(); + loop { + let new_stem = Path::new(stem).file_stem().unwrap().to_str().unwrap(); + if stem == new_stem { + break; } + stem = new_stem; + } + format!("{}_y", stem) + } + }; + + let cache = self.rebuild_cache(&derived_mod_name, &grm); + + // We don't need to go through the full rigmarole of generating an output file if all of + // the following are true: the output file exists; it is newer than the input file; and the + // cache hasn't changed. The last of these might be surprising, but it's vital: we don't + // know, for example, what the IDs map might be from one run to the next, and it might + // change for reasons beyond lrpar's control. If it does change, that means that the lexer + // and lrpar would get out of sync, so we have to play it safe and regenerate in such + // cases. + if let Ok(ref inmd) = fs::metadata(grmp) + && let Ok(ref out_rs_md) = fs::metadata(outp) + && FileTime::from_last_modification_time(out_rs_md) + > FileTime::from_last_modification_time(inmd) + && let Ok(outc) = read_to_string(outp) + { + if outc.contains(&cache.to_string()) { + return Ok(CTParser { + regenerated: false, + rule_ids, + yacc_grammar: grm, + grammar_src: inc, + grammar_path: self.grammar_path.unwrap(), + conflicts: None, + }); + } else { + #[cfg(grmtools_extra_checks)] + if std::env::var("CACHE_EXPECTED").is_ok() { + eprintln!("outc: {}", outc); + eprintln!("using cache: {}", cache,); + // Primarily for use in the testsuite. + panic!("The cache regenerated however, it was expected to match"); } } } - } - } - // At this point, we know we're going to generate fresh output; however, if something goes - // wrong in the process between now and us writing /out/blah.rs, rustc thinks that - // everything's gone swimmingly (even if build.rs errored!), and tries to carry on - // compilation, leading to weird errors. We therefore delete /out/blah.rs at this point, - // which means, at worse, the user gets a "file not found" error from rustc (which is less - // confusing than the alternatives). - fs::remove_file(outp).ok(); - - let (sgraph, stable) = from_yacc(&grm, Minimiser::Pager)?; - if self.error_on_conflicts { - if let Some(c) = stable.conflicts() { - match (grm.expect(), grm.expectrr()) { - (Some(i), Some(j)) if i == c.sr_len() && j == c.rr_len() => (), - (Some(i), None) if i == c.sr_len() && 0 == c.rr_len() => (), - (None, Some(j)) if 0 == c.sr_len() && j == c.rr_len() => (), - (None, None) if 0 == c.rr_len() && 0 == c.sr_len() => (), - _ => { - let conflicts_diagnostic = yacc_diag.format_conflicts::( - &grm, - ast_validation.ast(), - c, - &sgraph, - &stable, - ); - return Err(Box::new(CTConflictsError { - conflicts_diagnostic, - phantom: PhantomData, - #[cfg(test)] - stable, - })); + // At this point, we know we're going to generate fresh output; however, if something goes + // wrong in the process between now and us writing /out/blah.rs, rustc thinks that + // everything's gone swimmingly (even if build.rs errored!), and tries to carry on + // compilation, leading to weird errors. We therefore delete /out/blah.rs at this point, + // which means, at worse, the user gets a "file not found" error from rustc (which is less + // confusing than the alternatives). + fs::remove_file(outp).ok(); + + let (sgraph, stable) = from_yacc(&grm, Minimiser::Pager)?; + if self.error_on_conflicts + && let Some(c) = stable.conflicts() + { + match (grm.expect(), grm.expectrr()) { + (Some(i), Some(j)) if i == c.sr_len() && j == c.rr_len() => (), + (Some(i), None) if i == c.sr_len() && 0 == c.rr_len() => (), + (None, Some(j)) if 0 == c.sr_len() && j == c.rr_len() => (), + (None, None) if 0 == c.rr_len() && 0 == c.sr_len() => (), + _ => { + let conflicts_diagnostic = yacc_diag.format_conflicts::( + &grm, + ast_validation.ast(), + c, + &sgraph, + &stable, + ); + return Err(Box::new(CTConflictsError { + conflicts_diagnostic, + phantom: PhantomData, + #[cfg(test)] + stable, + })); + } } } - } - } - if let Some(ref mut inspector_rt) = self.inspect_rt { - let rt: RTParserBuilder<'_, StorageT, LexerTypesT> = - RTParserBuilder::new(&grm, &stable); - let rt = if let Some(rk) = self.recoverer { - rt.recoverer(rk) - } else { - rt - }; - inspector_rt(&mut header, rt, &rule_ids, grmp)? - } + if let Some(ref mut inspector_rt) = self.inspect_rt { + let rt: RTParserBuilder<'_, StorageT, LexerTypesT> = + RTParserBuilder::new(&grm, &stable); + let rt = if let Some(rk) = self.recoverer { + rt.recoverer(rk) + } else { + rt + }; + inspector_rt(&mut header, rt, &rule_ids, grmp)? + } - let unused_keys = header.unused(); - if !unused_keys.is_empty() { - return Err(format!("Unused keys in header: {}", unused_keys.join(", ")).into()); - } - let missing_keys = header - .missing() - .iter() - .map(|s| s.as_str()) - .collect::>(); - if !missing_keys.is_empty() { - return Err(format!( - "Required values were missing from the header: {}", - missing_keys.join(", ") - ) - .into()); - } + let unused_keys = header.unused(); + if !unused_keys.is_empty() { + return Err(format!("Unused keys in header: {}", unused_keys.join(", ")).into()); + } + let missing_keys = header + .missing() + .iter() + .map(|s| s.as_str()) + .collect::>(); + if !missing_keys.is_empty() { + return Err(format!( + "Required values were missing from the header: {}", + missing_keys.join(", ") + ) + .into()); + } - self.output_file( - &grm, - &stable, - &derived_mod_name, - outp, - &format!("/* CACHE INFORMATION {} */\n", cache), - &yacc_diag, - )?; - let conflicts = if stable.conflicts().is_some() { - Some((sgraph, stable)) - } else { - None - }; - Ok(CTParser { - regenerated: true, - rule_ids, - yacc_grammar: grm, - grammar_src: inc, - grammar_path: self.grammar_path.unwrap(), - conflicts, - }) + self.output_file( + &grm, + &stable, + &derived_mod_name, + outp, + &format!("/* CACHE INFORMATION {} */\n", cache), + &yacc_diag, + )?; + let conflicts = if stable.conflicts().is_some() { + Some((sgraph, stable)) + } else { + None + }; + Ok(CTParser { + regenerated: true, + rule_ids, + yacc_grammar: grm, + grammar_src: inc, + grammar_path: self.grammar_path.unwrap(), + conflicts, + }) + } + } } /// Given the filename `a/b.y` as input, statically compile the grammar `src/a/b.y` into a Rust @@ -1475,7 +1475,7 @@ where let mut s = String::from("\n"); let rule_span = grm.rule_name_span(ref_ridx); s.push_str(&diag.file_location_msg("Error", Some(rule_span))); - s.push_str("\n"); + s.push('\n'); s.push_str(&diag.underline_span_with_text( rule_span, "Rule missing action type".to_string(), @@ -1524,7 +1524,7 @@ where let mut s = String::from("\n"); let span = grm.prod_span(pidx); s.push_str(&diag.file_location_msg("Error", Some(span))); - s.push_str("\n"); + s.push('\n'); s.push_str(&diag.underline_span_with_text( span, "Production is missing action code".to_string(), @@ -1560,7 +1560,7 @@ where Span::new(span.start() + last + off + "$".len(), span.end()); let mut s = String::from("\n"); s.push_str(&diag.file_location_msg("Error", Some(inner_span))); - s.push_str("\n"); + s.push('\n'); s.push_str(&diag.underline_span_with_text( inner_span, "Unknown text following '$'".to_string(), diff --git a/lrpar/src/lib/diagnostics.rs b/lrpar/src/lib/diagnostics.rs index 5aeca8131..c58757bb6 100644 --- a/lrpar/src/lib/diagnostics.rs +++ b/lrpar/src/lib/diagnostics.rs @@ -130,7 +130,7 @@ impl<'a> SpannedDiagnosticFormatter<'a> { // Add indentation from the start of the underlined span out.push_str(&format!( "{prefix}{}", - &" ".repeat( + " ".repeat( UnicodeWidthStr::width(&self.src[line_start_byte..underline_span.start()]) + (line_num_digits + "| ".len() - prefix.len()) ) @@ -145,7 +145,7 @@ impl<'a> SpannedDiagnosticFormatter<'a> { if source_lines.peek().is_none() { // If we're at the end print the message. - out.push_str(&format!(" {}", &s)); + out.push_str(&format!(" {}", s)); } else { // Otherwise set next span to start at the beginning of the next line. out.push('\n'); diff --git a/lrpar/src/lib/parser.rs b/lrpar/src/lib/parser.rs index 9ff9f6934..8479eabb1 100644 --- a/lrpar/src/lib/parser.rs +++ b/lrpar/src/lib/parser.rs @@ -472,16 +472,16 @@ where pstack.push(self.stable.goto(prior, ridx).unwrap()); } Action::Shift(state_id) => { - if let Some(ref mut astack_uw) = *astack { - if let Some(spans_uw) = spans { - let la_lexeme = if let Some(l) = lexeme_prefix { - l - } else { - self.next_lexeme(laidx) - }; - astack_uw.push(AStackType::Lexeme(la_lexeme)); - spans_uw.push(la_lexeme.span()); - } + if let Some(ref mut astack_uw) = *astack + && let Some(spans_uw) = spans + { + let la_lexeme = if let Some(l) = lexeme_prefix { + l + } else { + self.next_lexeme(laidx) + }; + astack_uw.push(AStackType::Lexeme(la_lexeme)); + spans_uw.push(la_lexeme.span()); } pstack.push(state_id); laidx += 1; @@ -811,12 +811,12 @@ where let mut j = i + 1; let mut last_end = l.span().end(); while j < rs.len() { - if let ParseRepair::Delete(next_l) = rs[j] { - if next_l.span().start() == last_end { - last_end = next_l.span().end(); - j += 1; - continue; - } + if let ParseRepair::Delete(next_l) = rs[j] + && next_l.span().start() == last_end + { + last_end = next_l.span().end(); + j += 1; + continue; } break; } diff --git a/lrtable/src/lib/stategraph.rs b/lrtable/src/lib/stategraph.rs index f9d7ab20f..57dc83b39 100644 --- a/lrtable/src/lib/stategraph.rs +++ b/lrtable/src/lib/stategraph.rs @@ -174,7 +174,7 @@ where o.push_str("}]"); } let mut edges = self.edges(stidx).iter().collect::>(); - edges.sort_by(|(_, x), (_, y)| x.cmp(y)); + edges.sort_by_key(|(_, x)| *x); for (esym, e_stidx) in edges { write!( o, diff --git a/nimbleparse/src/main.rs b/nimbleparse/src/main.rs index 173626b40..8150d972f 100644 --- a/nimbleparse/src/main.rs +++ b/nimbleparse/src/main.rs @@ -324,7 +324,7 @@ fn main() { let (sgraph, stable) = match from_yacc(&grm, Minimiser::Pager) { Ok(x) => x, Err(s) => { - eprintln!("{}: {}", &yacc_y_path.display(), &s); + eprintln!("{}: {}", yacc_y_path.display(), s); process::exit(1); } }; @@ -333,38 +333,36 @@ fn main() { println!("Stategraph:\n{}\n", sgraph.pp_core_states(&grm)); } - if !quiet { - if let Some(c) = stable.conflicts() { - let pp_rr = if let Some(i) = grm.expectrr() { - i != c.rr_len() - } else { - 0 != c.rr_len() - }; - let pp_sr = if let Some(i) = grm.expect() { - i != c.sr_len() - } else { - 0 != c.sr_len() - }; - if pp_rr { - println!("{}", c.pp_rr(&grm)); - } - if pp_sr { - println!("{}", c.pp_sr(&grm)); - } - if (pp_rr || pp_sr) && !dump_state_graph { - println!("Stategraph:\n{}\n", sgraph.pp_core_states(&grm)); - } - eprintln!( - "{}", - yacc_diag.format_conflicts::>( - &grm, - ast_validation.ast(), - c, - &sgraph, - &stable, - ) - ); + if !quiet && let Some(c) = stable.conflicts() { + let pp_rr = if let Some(i) = grm.expectrr() { + i != c.rr_len() + } else { + 0 != c.rr_len() + }; + let pp_sr = if let Some(i) = grm.expect() { + i != c.sr_len() + } else { + 0 != c.sr_len() + }; + if pp_rr { + println!("{}", c.pp_rr(&grm)); + } + if pp_sr { + println!("{}", c.pp_sr(&grm)); } + if (pp_rr || pp_sr) && !dump_state_graph { + println!("Stategraph:\n{}\n", sgraph.pp_core_states(&grm)); + } + eprintln!( + "{}", + yacc_diag.format_conflicts::>( + &grm, + ast_validation.ast(), + c, + &sgraph, + &stable, + ) + ); } let (missing_from_lexer, missing_from_parser) = set_rule_ids(&mut lexerdef, &grm); @@ -575,15 +573,14 @@ where } for path in glob_paths { let path = path?; - if let Some(ext) = path.extension() { - if let Some(ext) = ext.to_str() { - if ext.starts_with("grm") { - Err(NimbleparseError::Other( + if let Some(ext) = path.extension() + && let Some(ext) = ext.to_str() + && ext.starts_with("grm") + { + Err(NimbleparseError::Other( "test_files extensions beginning with `grm` are reserved." .into(), ))? - } - } } paths.push(path); }