From e2532f7afe350695d349c603f3d7c368f51ca353 Mon Sep 17 00:00:00 2001 From: Muhammad Mahad Date: Sun, 11 Aug 2024 21:30:37 +0500 Subject: [PATCH] doc: Add doc comments Signed-off-by: Muhammad Mahad --- src/cli.rs | 8 ++++++++ src/errors.rs | 25 ++++++++++++++++++++++++- src/main.rs | 2 ++ src/transform.rs | 19 +++++++++++++++---- 4 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index 4a1c0d0..db56671 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,15 +1,19 @@ +//! This module contains the command line interface for the tool + use { anyhow::{Context, Result}, clap::Parser, std::{fs, path}, }; +/// Command line arguments for the tool #[derive(Parser, Debug)] #[command( name = "rust test to DejaGnu", long_about = "A tool to convert rust tests into DejaGnu tests format" )] pub struct Arguments { + /// The rust source file to convert into `DejaGnu` format #[arg( short = 'f', long = "file", @@ -18,6 +22,7 @@ pub struct Arguments { )] pub source_file: path::PathBuf, + /// optional `stderr` file #[arg( short = 'e', long = "stderr", @@ -33,6 +38,7 @@ pub fn parse_arguments_and_read_file(args: &Arguments) -> Result<(String, Option let source_code = fs::read_to_string(&args.source_file) .with_context(|| format!("could not read sourcefile `{}`", args.source_file.display()))?; + // Read the stderr file if it exists let err_file = match &args.stderr_file { Some(stderr_file) => Some(fs::read_to_string(stderr_file).with_context(|| { @@ -66,6 +72,8 @@ mod tests { assert_eq!(args.stderr_file, Some(path::PathBuf::from("test.stderr"))); } + /// clap reports most development errors as `debug_assert!`s + /// See this for more details, [here](https://docs.rs/clap/4.5.15/clap/_derive/_tutorial/chapter_4/index.html) #[test] fn debug_args() { use clap::CommandFactory; diff --git a/src/errors.rs b/src/errors.rs index 93036b8..7845b08 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,3 +1,5 @@ +//! This module contains the logic for parsing rustc error messages. + use { self::WhichLine::*, std::{fmt, str::FromStr}, @@ -11,7 +13,9 @@ macro_rules! regex { RE.get_or_init(|| regex::Regex::new($re).unwrap()) }}; } -// https://rustc-dev-guide.rust-lang.org/tests/ui.html#error-levels + +/// Represents the different kinds of Rustc compiler messages. +/// See [rustc dev guide](https://rustc-dev-guide.rust-lang.org/tests/ui.html#error-levels) #[derive(Copy, Clone, Debug, PartialEq)] pub enum RustcErrorKind { Help, @@ -55,6 +59,7 @@ impl fmt::Display for RustcErrorKind { } } +/// To store information from rustc source file #[derive(Debug)] pub struct Error { pub line_num: usize, @@ -67,11 +72,14 @@ pub struct Error { /// What kind of message we expect (e.g., warning, error, suggestion). /// `None` if not specified or unknown message kind. pub kind: Option, + ///Note: if we are loading this from rustc source file, this might be incomplete pub msg: String, pub error_code: Option, } impl fmt::Display for Error { + /// Formats the `Error` for display according to `DejaGnu` format + /// See `DejaGnu` documentation [here](https://gcc.gnu.org/onlinedocs/gccint/testsuites/directives-used-within-dejagnu-tests/syntax-and-descriptions-of-test-directives.html) fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use RustcErrorKind::*; @@ -105,6 +113,9 @@ impl fmt::Display for Error { } } +/// Represents the line in the rustc source code where an error occurred. +/// Luckily, rust compile test only stores error messages on and after the line where the error occurred. +/// But `DejaGnu` can process error messages on the previous line, the current line, or the next line. #[derive(PartialEq, Debug)] enum WhichLine { ThisLine, @@ -112,8 +123,10 @@ enum WhichLine { AdjustBackward(usize), } +/// The main function for loading errors from source file and from optional stderr file. pub fn load_error(text_file: &str, stderr_file: Option<&str>) -> Vec { let mut last_unfollow_error = None; + // For storing the errors let mut errors = Vec::new(); for (line_num, line) in text_file.lines().enumerate() { @@ -126,12 +139,17 @@ pub fn load_error(text_file: &str, stderr_file: Option<&str>) -> Vec { } } + // If stderr file is not provided, return the errors if stderr_file.is_none() { return errors; } // TODO: improve this code incrementally + // parsing error related information from `.stderr` file let error_code_stderr = parse_error_code(stderr_file.expect("stderr file is not found")); + // TODO: We need to load error messages from `.stderr` instead of source file become sometimes source file contains incomplete error messages + // finding the error code w.r.t line number and error message + // TODO: sometimes, the error message might not be same but this doesn't matter as we are not comparing the row number for the message for error in errors.iter_mut() { for error_code in error_code_stderr.iter() { if error.line_num == error_code.line_number @@ -141,9 +159,11 @@ pub fn load_error(text_file: &str, stderr_file: Option<&str>) -> Vec { } } } + // return error detail with error codes errors } +/// To represent information from `stderr` file #[derive(Debug)] struct StderrResult { error_code: String, @@ -155,6 +175,7 @@ fn is_error_code(s: &str) -> bool { regex!(r"^E\d{4}$").is_match(s) } +/// Parses error codes from the `stderr` file fn parse_error_code(stderr_content: &str) -> Vec { // Modified regex pattern with named capture groups let error_pattern = regex!( @@ -191,6 +212,7 @@ fn parse_error_code(stderr_content: &str) -> Vec { results } +/// Parses error details from a source line. fn parse_expected( last_nonfollow_error: Option, line_num: usize, @@ -228,6 +250,7 @@ fn parse_expected( let msg = msg.trim().to_owned(); + // If we find `//~|` or `//~^`, we need to adjust the line number. let mut relative_line_num = line_num as i32; let (which, line_num) = if follow { assert_eq!(adjusts, 0, "use either //~| or //~^, not both."); diff --git a/src/main.rs b/src/main.rs index bbf45f0..28c30fe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +//! The main entry point of the program. + use { anyhow::{Context, Result}, clap::Parser, diff --git a/src/transform.rs b/src/transform.rs index f1da343..ab9c213 100644 --- a/src/transform.rs +++ b/src/transform.rs @@ -1,36 +1,47 @@ +//! This module contains the code transformation logic. + use { crate::{errors, regex}, anyhow::Result, }; -/// This function takes the rust code as input -/// and returns the code with DejaGnu directive +/// Transform code to `DejaGnu` format pub fn transform_code(code: &str, stderr_file: Option<&str>) -> Result { + // Load the rustc error messages, codes, lines and relative line numbers let errors = errors::load_error(code, stderr_file); + // For storing the transformed code let mut new_code = String::new(); let mut line_num = 1; + // finding the respective line number and adding the error code for line in code.lines() { let mut new_line = line.to_string(); // TODO: This is not the efficient way to find respective line number for error in errors.iter() { + // Checking the original line number if (error.line_num as i32 - error.relative_line_num) != line_num { continue; } // In rustc test suites, the error directive is - // on the same line or the next line not on the previous line + // on the same line or on the next line, but not on the previous line + // See this: https://rustc-dev-guide.rust-lang.org/tests/ui.html#error-annotations // For the error on the next line if error.relative_line_num != 0 { + // We simply add the error message, not to worry about the code + // The error was printed by our overloaded `Display` trait new_line = format!("{}", error); } else { - // For the error on the same line + // For the error on the same line, we need to add error message at the end of the line let captures = regex!(r"//(?:\[(?P[\w\-,]+)])?~(?P\||\^*)") .captures(line) .expect("Could not find the error directive"); // Get the part of comment before the sigil (e.g. `~^` or ~|) let whole_match = captures.get(0).unwrap(); + // Get the existing source code before the error directive //~ ERROR or similar to this let before_match = &line[..whole_match.start()]; + + // The error was printed by our overloaded `Display` trait new_line = format!("{}{}", before_match, error); } break;