Skip to content

Commit

Permalink
Added support for more langs and refactored
Browse files Browse the repository at this point in the history
  • Loading branch information
cdecompilador committed Mar 19, 2021
1 parent ce56ba8 commit d8b4184
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 37 deletions.
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,15 @@ PROJECT_NAME: ... TOTAL_LINES: 70

Just because I wanted some tool to do this before reading a codebase

# Supported languages
* C
* C++
* Rust
* Python
* Javascript (frameworks also)
* Typescript
* Java
* Golang

# Contrib Guidelines
Not to much just comment everything you do
Not to much just comment everything you do
17 changes: 10 additions & 7 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
use std::fmt;
use std::fs;
use std::io;
use std::path::Path;
use std::path::PathBuf;

use walkdir::WalkDir;
use rayon::prelude::*;
use clap::{Arg, App, SubCommand};
use clap::{Arg, App};

mod parser;
use parser::parse_file;
Expand All @@ -20,9 +19,11 @@ fn get_language_name<'a>(extension: &'a str) -> &'a str {
"cpp" | "cxx" | "c++" => "C++",
"py" => "Python",
"js" | "jsx" | "ejs" => "Javascript",
"ts" | ".d.ts" => "Typescript",
"html" => "HTML",
"css" => "css",
"ts" => "Typescript",
"html" => "HTML", // Not yet
"css" => "css", // Not yet
"java" => "Java",
"go" => "Golang",
_ => "Unknown"
}
}
Expand Down Expand Up @@ -150,12 +151,14 @@ fn main() {
// TODO: Create the project_data with the name of the folder
let mut project_data = ProjectData::new("");

// Process each file in the project
let a = filenames.par_iter()
// Process each file in the project, rayon is being used for the sake of
// speed
filenames.par_iter()
.map(|filename| {
let extension: &str = match filename.extension() {
Some(extension) => {
let ext: &str = extension.to_str().unwrap();
// If not supported the extension do nothing with it
if get_language_name(ext) == "Unknown" {
return None;
}
Expand Down
85 changes: 56 additions & 29 deletions src/parser.rs
Original file line number Diff line number Diff line change
@@ -1,56 +1,69 @@
use std::path::Path;
use std::fs::{self, File};
use std::fs::File;
use std::io::Read;

use regex::Regex;
use lazy_static::{lazy_static, __Deref};

/// Used to know the kind of comments used in the especified language
/// TODO: Add more languages
const KNOWN_EXTENSIONS_BINDINGS: &[(&str, &[&str])] = &[
("rs", &["//", "/*", "*/"]),
("c", &["//", "/*", "*/"]),
("cpp", &["//", "/*", "*/"]),
("c++", &["//", "/*", "*/"]),
("cxx", &["//", "/*", "*/"]),
("py", &["#", "\"\"\"", "\"\"\""]),
("js", &["//", "/*", "*/"]),
("jsx", &["//", "/*", "*/"]),
("ts", &["//", "/*", "*/"]),
];

fn linearizator(extension: &str) -> Option<impl Linearizator> {
fn linearizator(extension: &str) -> Option<Box<dyn Linearizator>> {
match extension {
"rs" | "c" | "cpp" | "cxx" | "js" | "ts" | "jsx" | "ejs"
=> Some(DefaultLinearizator {}),
"rs" | "c" | "cpp" | "cxx" | "js" | "ts" | "jsx" | "ejs"
| "java" | "go"
=> Some(Box::new(DefaultLinearizator {})),
"py" | "pyc"
=> Some(Box::new(PythonLinearizator {})),
_ => None
}
}

/// Abstract trait for all the future implementations of a Linearizator
/// (needed better name I know). It counts the lines of a file following this
/// rule: `lines` = `total_lines` - `lines_commented`
trait Linearizator {
fn count_lines(self, input: &String) -> usize where Self: Sized {
fn count_lines(&self, input: String) -> usize {
// Substracts the total lines of code inside the file and the lines of
// all the comments
input.lines().count()
- self.get_comments()
.find_iter(input)
.find_iter(input.as_str())
.map(|s| s.as_str().lines().count()).sum::<usize>()
}

fn get_comments(self) -> Regex where Self: Sized;

/// Get a Regex for the specific `Linearizator` implementation that matches
/// all kinds of comments
fn get_comments(&self) -> Regex;
}

struct DefaultLinearizator {}
impl Linearizator for DefaultLinearizator {
fn get_comments(self) -> Regex where Self: Sized {
Regex::new(r"(/\*[\w\s\n]*\*/)|(/+[\s\w]*)").unwrap()
fn get_comments(&self) -> Regex {
lazy_static! {
static ref RE: Regex = Regex::new(r"(/\*[\w\s\n]*\*/)|(/+[\s\w]*)")
.unwrap();
}
RE.deref().clone()
}
}

struct PythonLinearizator {}
impl Linearizator for PythonLinearizator {
fn get_comments(&self) -> Regex {
lazy_static! {
static ref RE: Regex = Regex::new(r#"(#+[\s\w]*)|("""[\w\s\n]*""")"#)
.unwrap();
}
RE.deref().clone()
}
}

fn lines_of_code(input: &String, extension: &str) -> usize {
/// Given an `input` and an `extension` (to match the kind of file to parse),
/// it returns the lines of code of that file, if not capable of parsing it
/// (not implemneted a parser yet) it counts 0
fn lines_of_code(input: String, extension: &str) -> usize {
if let Some(ltor) = linearizator(extension) {
return ltor.count_lines(input);
} else {
println!("Unimplemented extension {}", extension);
// println!("Unimplemented extension {}", extension);
return 0;
}
}
Expand All @@ -67,7 +80,7 @@ pub fn parse_file(filepath: impl AsRef<Path>) -> Option<usize> {
if 0 < file.read_to_string(&mut file_content).ok()? {
return Some(
lines_of_code(
&file_content,
file_content,
filepath.extension()?.to_str()?
)
);
Expand All @@ -79,16 +92,30 @@ pub fn parse_file(filepath: impl AsRef<Path>) -> Option<usize> {
}

#[cfg(test)]
mod tests {
mod parser {
use super::*;
#[test]
fn rust_tests() {
fn default_test() {
assert_eq!(
lines_of_code(&"// aaa\n// aaa\n// aaa\n/*\naaa\naaa\naaa\n*/\nHi".to_string(),"rs"),
1
);
}

#[test]
fn python_test() {
assert_eq!(
lines_of_code(
&r#"# Hello
""""
Multiline
Comment
""""
print("Hello")"#.to_string(), "py"),
1
);
}

#[test]
fn it_works() {
assert!(0 == 0);
Expand Down

0 comments on commit d8b4184

Please sign in to comment.