From 7c9e7621266a68533c099acb319e4519953ed204 Mon Sep 17 00:00:00 2001 From: LunaStev Date: Wed, 7 Jan 2026 15:52:26 +0900 Subject: [PATCH] refactor: introduce utils crate and remove external regex dependency Create a new `utils` crate to centralize utility functions and remove the heavy `regex` dependency, replacing it with a custom lightweight placeholder parser. Also integrates the `colorex` module. Changes: - **New Crate `utils`**: - Added `utils/src/colorex.rs`: Custom color formatting logic (moved from `colorex` crate or inline). - Added `utils/src/formatx.rs`: Implements `count_placeholders` to replace regex usage for `{}` counting. - Updated workspace `Cargo.toml` to include `utils`. - **Dependency Removal**: - Removed `regex` from `front/parser/Cargo.toml`. - Replaced `regex::Regex` usage in `front/parser/src/parser/io.rs` with `utils::formatx::count_placeholders`. - **Integration**: - Updated `front/error/Cargo.toml` and `Cargo.toml` to depend on `utils`. - Updated `src/main.rs`, `src/lib.rs`, and `front/error/src/error.rs` to use `utils::colorex`. - **Cleanup**: - Removed placeholder `lib.rs` content in `utils`. This change significantly reduces compilation time and binary size by eliminating the regex engine dependency. Signed-off-by: LunaStev --- Cargo.toml | 3 +- front/error/Cargo.toml | 2 +- front/error/src/error.rs | 2 +- front/lexer/Cargo.toml | 1 - front/parser/Cargo.toml | 2 +- front/parser/src/parser/io.rs | 17 ++----- src/lib.rs | 2 +- src/main.rs | 2 +- utils/Cargo.toml | 4 ++ utils/src/colorex.rs | 92 +++++++++++++++++++++++++++++++++++ utils/src/formatx.rs | 43 ++++++++++++++++ utils/src/lib.rs | 4 ++ 12 files changed, 154 insertions(+), 20 deletions(-) create mode 100644 utils/Cargo.toml create mode 100644 utils/src/colorex.rs create mode 100644 utils/src/formatx.rs create mode 100644 utils/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 69ff6ce3..a5e5e948 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ path = "src/lib.rs" # linker = "clang" [dependencies] -colorex = "0.1.0" +utils = { path = "utils" } lexer = { path = "front/lexer" } parser = { path = "front/parser" } error = { path = "front/error" } @@ -25,5 +25,6 @@ members = [ "front/parser", "llvm_temporary", "front/error", + "utils", ".", ] diff --git a/front/error/Cargo.toml b/front/error/Cargo.toml index b29f53ee..91d2b272 100644 --- a/front/error/Cargo.toml +++ b/front/error/Cargo.toml @@ -4,4 +4,4 @@ version = "0.1.0" edition = "2021" [dependencies] -colorex = "0.1.1" +utils = { path = "../../utils" } diff --git a/front/error/src/error.rs b/front/error/src/error.rs index 51fc0c9d..a4bed27c 100644 --- a/front/error/src/error.rs +++ b/front/error/src/error.rs @@ -178,7 +178,7 @@ impl WaveError { /// Display error in Rust-style format pub fn display(&self) { - use colorex::Colorize; + use utils::colorex::*; let severity_str = match self.severity { ErrorSeverity::Error => "error".color("255,71,71").bold(), diff --git a/front/lexer/Cargo.toml b/front/lexer/Cargo.toml index 940c2728..657d9a44 100644 --- a/front/lexer/Cargo.toml +++ b/front/lexer/Cargo.toml @@ -3,4 +3,3 @@ name = "lexer" version = "0.1.0" edition = "2021" -[dependencies] diff --git a/front/parser/Cargo.toml b/front/parser/Cargo.toml index fe82a0a7..985c56e4 100644 --- a/front/parser/Cargo.toml +++ b/front/parser/Cargo.toml @@ -6,4 +6,4 @@ edition = "2021" [dependencies] lexer = { path = "../lexer" } error = { path = "../error" } -regex = "1.11.1" \ No newline at end of file +utils = { path = "../../utils" } \ No newline at end of file diff --git a/front/parser/src/parser/io.rs b/front/parser/src/parser/io.rs index 02f90f0e..afc766ec 100644 --- a/front/parser/src/parser/io.rs +++ b/front/parser/src/parser/io.rs @@ -1,6 +1,6 @@ use std::iter::Peekable; use std::slice::Iter; -use regex::Regex; +use utils::formatx::*; use lexer::Token; use lexer::token::TokenType; use crate::ast::{ASTNode, StatementNode}; @@ -25,10 +25,7 @@ pub fn parse_println(tokens: &mut Peekable>) -> Option { return None; }; - let placeholder_count = Regex::new(r"\{[^}]*\}") - .unwrap() - .find_iter(&content) - .count(); + let placeholder_count = count_placeholders(&content); if placeholder_count == 0 { if tokens.peek()?.token_type != TokenType::Rparen { @@ -110,10 +107,7 @@ pub fn parse_print(tokens: &mut Peekable>) -> Option { return None; }; - let placeholder_count = Regex::new(r"\{[^}]*\}") - .unwrap() - .find_iter(&content) - .count(); + let placeholder_count = count_placeholders(&content); if placeholder_count == 0 { // No format → Print just a string @@ -195,10 +189,7 @@ pub fn parse_input(tokens: &mut Peekable>) -> Option { return None; }; - let placeholder_count = Regex::new(r"\{[^}]*\}") - .unwrap() - .find_iter(&content) - .count(); + let placeholder_count = count_placeholders(&content); let mut args = Vec::new(); while let Some(Token { diff --git a/src/lib.rs b/src/lib.rs index 06e69617..a7cb9bb8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,7 @@ pub mod runner; pub mod version; use crate::version::get_os_pretty_name; -use colorex::Colorize; +use utils::colorex::*; use std::path::Path; use commands::DebugFlags; diff --git a/src/main.rs b/src/main.rs index 2eb3bffa..761da36f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use std::path::Path; use std::{env, process}; -use colorex::Colorize; +use utils::colorex::*; use wavec::commands::{handle_build, handle_run, DebugFlags}; use wavec::errors::CliError; use wavec::version_wave; diff --git a/utils/Cargo.toml b/utils/Cargo.toml new file mode 100644 index 00000000..bd645df1 --- /dev/null +++ b/utils/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "utils" +version = "0.1.0" +edition = "2021" diff --git a/utils/src/colorex.rs b/utils/src/colorex.rs new file mode 100644 index 00000000..91508ed5 --- /dev/null +++ b/utils/src/colorex.rs @@ -0,0 +1,92 @@ +pub struct Color(u8, u8, u8); + +impl Color { + pub fn from_rgb(rgb: &str) -> Result { + let parts: Vec<&str> = rgb.split(',').collect(); + if parts.len() == 3 { + let r = parts[0].parse::().map_err(|_| "Invalid RGB format")?; + let g = parts[1].parse::().map_err(|_| "Invalid RGB format")?; + let b = parts[2].parse::().map_err(|_| "Invalid RGB format")?; + Ok(Color(r, g, b)) + } else { + Err("Invalid RGB format") + } + } + + pub fn from_hex(hex: &str) -> Result { + if hex.len() != 7 || !hex.starts_with('#') { + return Err("Invalid HEX format"); + } + + let r = u8::from_str_radix(&hex[1..3], 16).map_err(|_| "Invalid HEX value")?; + let g = u8::from_str_radix(&hex[3..5], 16).map_err(|_| "Invalid HEX value")?; + let b = u8::from_str_radix(&hex[5..7], 16).map_err(|_| "Invalid HEX value")?; + + Ok(Color(r, g, b)) + } +} + +pub trait Colorize { + fn color(self, color: &str) -> String; + fn bg_color(self, color: &str) -> String; + fn bold(self) -> String; + fn italic(self) -> String; + fn underline(self) -> String; + fn strikethrough(self) -> String; + fn dim(self) -> String; + fn invert(self) -> String; +} + +impl Colorize for &str { + fn color(self, color: &str) -> String { + let color = if color.starts_with('#') { + Color::from_hex(color) + } else { + Color::from_rgb(color) + }; + + match color { + Ok(c) => format!("\x1b[38;2;{};{};{}m{}\x1b[0m", c.0, c.1, c.2, self), + Err(_) => self.to_string(), + } + } + + fn bg_color(self, color: &str) -> String { + let color = if color.starts_with('#') { + Color::from_hex(color) + } else { + Color::from_rgb(color) + }; + + match color { + Ok(c) => format!("\x1b[48;2;{};{};{}m{}\x1b[0m", c.0, c.1, c.2, self), + Err(_) => self.to_string(), + } + } + + fn bold(self) -> String { + format!("\x1b[1m{}\x1b[0m", self) + } + + fn italic(self) -> String { + format!("\x1b[3m{}\x1b[0m", self) + } + + fn underline(self) -> String { + format!("\x1b[4m{}\x1b[0m", self) + } + + fn strikethrough(self) -> String { + format!("\x1b[9m{}\x1b[0m", self) + } + + fn dim(self) -> String { + format!("\x1b[2m{}\x1b[0m", self) + } + + fn invert(self) -> String { + format!("\x1b[7m{}\x1b[0m", self) + } +} + + diff --git a/utils/src/formatx.rs b/utils/src/formatx.rs new file mode 100644 index 00000000..f51c7c62 --- /dev/null +++ b/utils/src/formatx.rs @@ -0,0 +1,43 @@ +// utils/formatx.rs +// +// Wave internal format utilities. +// This module replaces regex usage for placeholder detection. +// Supported pattern: `{ ... }` (non-nested, no escape) + +/// Count `{...}` placeholders in the given string. +/// +/// Equivalent to the regex pattern: `\{[^}]*\}` +/// +/// Examples: +/// - "hello {}" -> 1 +/// - "{a}{b}{c}" -> 3 +/// - "{ not closed" -> 0 +pub fn count_placeholders(input: &str) -> usize { + let bytes = input.as_bytes(); + let mut i = 0; + let mut count = 0; + + while i < bytes.len() { + if bytes[i] == b'{' { + let start = i; + i += 1; + + while i < bytes.len() { + if bytes[i] == b'}' { + count += 1; + i += 1; + break; + } + i += 1; + } + + if i >= bytes.len() && bytes[start] == b'{' { + break; + } + } else { + i += 1; + } + } + + count +} diff --git a/utils/src/lib.rs b/utils/src/lib.rs new file mode 100644 index 00000000..7f894b76 --- /dev/null +++ b/utils/src/lib.rs @@ -0,0 +1,4 @@ +pub mod colorex; +pub mod formatx; + +pub use colorex::Colorize; \ No newline at end of file