diff --git a/crates/regex-cli/Cargo.toml b/crates/regex-cli/Cargo.toml index a58e11f..36576c8 100644 --- a/crates/regex-cli/Cargo.toml +++ b/crates/regex-cli/Cargo.toml @@ -6,7 +6,7 @@ edition.workspace = true [dependencies] clap = { version = "4.5.11", features = ["derive"] } regex-core = { path = "../regex-core" } -thiserror = "1.0" +thiserror = "2.0.18" [dev-dependencies] tempfile = "3.0" diff --git a/crates/regex-core/src/engine/ast.rs b/crates/regex-core/src/engine/ast.rs index f65b1f8..81ef826 100644 --- a/crates/regex-core/src/engine/ast.rs +++ b/crates/regex-core/src/engine/ast.rs @@ -1,5 +1,4 @@ //! AST definitions for the regex engine. -#![allow(dead_code)] /// Inclusive character range. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -10,17 +9,6 @@ pub struct CharRange { pub end: char, } -impl CharRange { - /// Creates a range when `start <= end`; otherwise returns `None`. - pub fn new(start: char, end: char) -> Option { - if start <= end { - Some(Self { start, end }) - } else { - None - } - } -} - /// Character class. /// /// `ranges` represents inclusive `[start, end]` spans. @@ -41,6 +29,7 @@ impl CharClass { } /// Zero-width assertion kinds. +#[allow(dead_code)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Predicate { /// Line start assertion (`^`). diff --git a/crates/regex-core/src/engine/compiler.rs b/crates/regex-core/src/engine/compiler.rs index 2f069f1..0ac7339 100644 --- a/crates/regex-core/src/engine/compiler.rs +++ b/crates/regex-core/src/engine/compiler.rs @@ -1,5 +1,4 @@ //! Compile an AST into an instruction sequence (`Instruction`). -#![allow(dead_code)] use thiserror::Error; diff --git a/crates/regex-core/src/engine/evaluator.rs b/crates/regex-core/src/engine/evaluator.rs index 6723058..6b24f0d 100644 --- a/crates/regex-core/src/engine/evaluator.rs +++ b/crates/regex-core/src/engine/evaluator.rs @@ -1,5 +1,4 @@ //! Evaluate an instruction sequence. -#![allow(dead_code)] use std::collections::HashSet; diff --git a/crates/regex-core/src/engine/instruction.rs b/crates/regex-core/src/engine/instruction.rs index f1361eb..19920eb 100644 --- a/crates/regex-core/src/engine/instruction.rs +++ b/crates/regex-core/src/engine/instruction.rs @@ -1,5 +1,4 @@ //! Instruction set used by the compiler and evaluator. -#![allow(dead_code)] use std::fmt::{self, Display}; diff --git a/crates/regex-core/src/engine/parser.rs b/crates/regex-core/src/engine/parser.rs index 36693dd..6ab9aec 100644 --- a/crates/regex-core/src/engine/parser.rs +++ b/crates/regex-core/src/engine/parser.rs @@ -1,7 +1,6 @@ //! Recursive-descent parser for regex patterns. //! //! The parser converts a pattern string into an `Ast` used by the compiler. -#![allow(dead_code)] use crate::engine::ast::{Ast, CharClass, CharRange, Predicate}; use thiserror::Error; @@ -53,9 +52,9 @@ struct Parser { captures: usize, } -/// Parses `regex` and returns its AST representation. -pub fn parse(regex: &str) -> Result { - let mut parser = Parser::new(regex); +/// Parses `pattern` and returns its AST representation. +pub fn parse(pattern: &str) -> Result { + let mut parser = Parser::new(pattern); let ast = parser.parse_expression()?; if parser.peek().is_some() { return Err(ParseError::UnexpectedChar(parser.peek().unwrap())); @@ -65,9 +64,9 @@ pub fn parse(regex: &str) -> Result { impl Parser { /// Creates a parser from a pattern string. - fn new(regex: &str) -> Self { + fn new(pattern: &str) -> Self { Self { - input: regex.chars().collect(), + input: pattern.chars().collect(), pos: 0, captures: 1, } @@ -205,10 +204,7 @@ impl Parser { Some(ch) if Self::is_special_char(ch) => Err(ParseError::UnexpectedChar(ch)), Some(_) => { let ch = self.next().ok_or(ParseError::UnexpectedEnd)?; - Ok(Ast::CharClass(CharClass::new( - vec![CharRange { start: ch, end: ch }], - false, - ))) + Ok(Self::parse_single_char(ch)) } None => Err(ParseError::UnexpectedEnd), } @@ -287,7 +283,7 @@ impl Parser { } Ast::Backreference(num as usize) } - _ => single_char_class(ch), + _ => Self::parse_single_char(ch), }; Ok(ast) } @@ -369,28 +365,28 @@ impl Parser { false } } -} -/// Builds an `Ast::CharClass` representing exactly one literal character. -fn single_char_class(ch: char) -> Ast { - Ast::CharClass(CharClass::new( - vec![CharRange { start: ch, end: ch }], - false, - )) + /// Builds an `Ast::CharClass` that matches exactly one literal character. + fn parse_single_char(ch: char) -> Ast { + Ast::CharClass(CharClass::new( + vec![CharRange { start: ch, end: ch }], + false, + )) + } } #[cfg(test)] mod tests { - use super::{ParseError, Parser, parse, single_char_class}; + use super::{ParseError, Parser, parse}; use crate::engine::ast::{Ast, CharClass, CharRange, Predicate}; #[test] fn test_parse_abc() { let actual = parse("abc").unwrap(); let expect = Ast::Concat(vec![ - single_char_class('a'), - single_char_class('b'), - single_char_class('c'), + Parser::parse_single_char('a'), + Parser::parse_single_char('b'), + Parser::parse_single_char('c'), ]); assert_eq!(actual, expect); } @@ -400,10 +396,10 @@ mod tests { let actual = parse("a|b|c").unwrap(); let expect = Ast::Alternate( Box::new(Ast::Alternate( - Box::new(single_char_class('a')), - Box::new(single_char_class('b')), + Box::new(Parser::parse_single_char('a')), + Box::new(Parser::parse_single_char('b')), )), - Box::new(single_char_class('c')), + Box::new(Parser::parse_single_char('c')), ); assert_eq!(actual, expect); } @@ -413,12 +409,12 @@ mod tests { let actual = parse("ab|cd").unwrap(); let expect = Ast::Alternate( Box::new(Ast::Concat(vec![ - single_char_class('a'), - single_char_class('b'), + Parser::parse_single_char('a'), + Parser::parse_single_char('b'), ])), Box::new(Ast::Concat(vec![ - single_char_class('c'), - single_char_class('d'), + Parser::parse_single_char('c'), + Parser::parse_single_char('d'), ])), ); assert_eq!(actual, expect); @@ -427,11 +423,17 @@ mod tests { #[test] fn test_parse_alternation_empty_side() { let actual = parse("a|").unwrap(); - let expect = Ast::Alternate(Box::new(single_char_class('a')), Box::new(Ast::Empty)); + let expect = Ast::Alternate( + Box::new(Parser::parse_single_char('a')), + Box::new(Ast::Empty), + ); assert_eq!(actual, expect); let actual = parse("|a").unwrap(); - let expect = Ast::Alternate(Box::new(Ast::Empty), Box::new(single_char_class('a'))); + let expect = Ast::Alternate( + Box::new(Ast::Empty), + Box::new(Parser::parse_single_char('a')), + ); assert_eq!(actual, expect); } @@ -440,30 +442,30 @@ mod tests { let actual_star = parse("a*b").unwrap(); let expect_star = Ast::Concat(vec![ Ast::ZeroOrMore { - expr: Box::new(single_char_class('a')), + expr: Box::new(Parser::parse_single_char('a')), greedy: true, }, - single_char_class('b'), + Parser::parse_single_char('b'), ]); assert_eq!(actual_star, expect_star); let actual_plus = parse("a+b").unwrap(); let expect_plus = Ast::Concat(vec![ Ast::OneOrMore { - expr: Box::new(single_char_class('a')), + expr: Box::new(Parser::parse_single_char('a')), greedy: true, }, - single_char_class('b'), + Parser::parse_single_char('b'), ]); assert_eq!(actual_plus, expect_plus); let actual_question = parse("a?b").unwrap(); let expect_question = Ast::Concat(vec![ Ast::ZeroOrOne { - expr: Box::new(single_char_class('a')), + expr: Box::new(Parser::parse_single_char('a')), greedy: true, }, - single_char_class('b'), + Parser::parse_single_char('b'), ]); assert_eq!(actual_question, expect_question); } @@ -474,8 +476,8 @@ mod tests { let expect = Ast::ZeroOrMore { expr: Box::new(Ast::Capture { expr: Box::new(Ast::Concat(vec![ - single_char_class('a'), - single_char_class('b'), + Parser::parse_single_char('a'), + Parser::parse_single_char('b'), ])), index: 1, }), @@ -487,8 +489,8 @@ mod tests { let expect = Ast::Repeat { expr: Box::new(Ast::Capture { expr: Box::new(Ast::Concat(vec![ - single_char_class('a'), - single_char_class('b'), + Parser::parse_single_char('a'), + Parser::parse_single_char('b'), ])), index: 1, }), @@ -503,7 +505,7 @@ mod tests { fn test_parse_repeat_forms() { let actual = parse("a{3}").unwrap(); let expect = Ast::Repeat { - expr: Box::new(single_char_class('a')), + expr: Box::new(Parser::parse_single_char('a')), greedy: true, min: 3, max: Some(3), @@ -512,7 +514,7 @@ mod tests { let actual = parse("a{2,}").unwrap(); let expect = Ast::Repeat { - expr: Box::new(single_char_class('a')), + expr: Box::new(Parser::parse_single_char('a')), greedy: true, min: 2, max: None, @@ -521,7 +523,7 @@ mod tests { let actual = parse("a{2,5}").unwrap(); let expect = Ast::Repeat { - expr: Box::new(single_char_class('a')), + expr: Box::new(Parser::parse_single_char('a')), greedy: true, min: 2, max: Some(5), @@ -637,7 +639,7 @@ mod tests { fn test_parse_char_class_concat() { let actual = parse("a[bc]d").unwrap(); let expect = Ast::Concat(vec![ - single_char_class('a'), + Parser::parse_single_char('a'), Ast::CharClass(CharClass::new( vec![ CharRange { @@ -651,7 +653,7 @@ mod tests { ], false, )), - single_char_class('d'), + Parser::parse_single_char('d'), ]); assert_eq!(actual, expect); } @@ -685,17 +687,17 @@ mod tests { let expect = Ast::Concat(vec![ Ast::Capture { expr: Box::new(Ast::Concat(vec![ - single_char_class('a'), - single_char_class('b'), - single_char_class('c'), + Parser::parse_single_char('a'), + Parser::parse_single_char('b'), + Parser::parse_single_char('c'), ])), index: 1, }, Ast::Capture { expr: Box::new(Ast::Concat(vec![ - single_char_class('d'), - single_char_class('e'), - single_char_class('f'), + Parser::parse_single_char('d'), + Parser::parse_single_char('e'), + Parser::parse_single_char('f'), ])), index: 2, }, @@ -709,9 +711,9 @@ mod tests { let expect = Ast::Concat(vec![ Ast::Capture { expr: Box::new(Ast::Concat(vec![ - single_char_class('a'), - single_char_class('b'), - single_char_class('c'), + Parser::parse_single_char('a'), + Parser::parse_single_char('b'), + Parser::parse_single_char('c'), ])), index: 1, }, @@ -725,9 +727,9 @@ mod tests { let actual = parse("^abc$").unwrap(); let expect = Ast::Concat(vec![ Ast::Assertion(Predicate::StartOfLine), - single_char_class('a'), - single_char_class('b'), - single_char_class('c'), + Parser::parse_single_char('a'), + Parser::parse_single_char('b'), + Parser::parse_single_char('c'), Ast::Assertion(Predicate::EndOfLine), ]); assert_eq!(actual, expect); @@ -744,7 +746,7 @@ mod tests { fn test_parse_dot() { let actual = parse("a.c").unwrap(); let expect = Ast::Concat(vec![ - single_char_class('a'), + Parser::parse_single_char('a'), Ast::CharClass(CharClass::new( vec![CharRange { start: '\u{0000}', @@ -752,7 +754,7 @@ mod tests { }], false, )), - single_char_class('c'), + Parser::parse_single_char('c'), ]); assert_eq!(actual, expect); } @@ -767,23 +769,23 @@ mod tests { #[test] fn test_parse_escaped_literals() { let actual = parse("\\*").unwrap(); - let expect = single_char_class('*'); + let expect = Parser::parse_single_char('*'); assert_eq!(actual, expect); let actual = parse("\\\\").unwrap(); - let expect = single_char_class('\\'); + let expect = Parser::parse_single_char('\\'); assert_eq!(actual, expect); let actual = parse("\\+").unwrap(); - let expect = single_char_class('+'); + let expect = Parser::parse_single_char('+'); assert_eq!(actual, expect); let actual = parse("\\?").unwrap(); - let expect = single_char_class('?'); + let expect = Parser::parse_single_char('?'); assert_eq!(actual, expect); let actual = parse("\\a").unwrap(); - let expect = single_char_class('a'); + let expect = Parser::parse_single_char('a'); assert_eq!(actual, expect); }