From 3d8492ca99d4dcb4d4fc085fce4e8b5468c3ee6a Mon Sep 17 00:00:00 2001 From: dak2 Date: Sat, 31 Jan 2026 16:28:12 +0900 Subject: [PATCH] Support Regexp --- rust/src/analyzer/literals.rs | 15 +++++- rust/src/analyzer/tests/integration_test.rs | 54 +++++++++++++++++++++ rust/src/types.rs | 6 +++ 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/rust/src/analyzer/literals.rs b/rust/src/analyzer/literals.rs index 2628fd4..98f3995 100644 --- a/rust/src/analyzer/literals.rs +++ b/rust/src/analyzer/literals.rs @@ -1,7 +1,7 @@ //! Literal Handlers - Processing Ruby literal values //! //! This module is responsible for: -//! - String, Integer, Float, Hash literals +//! - String, Integer, Float, Hash, Regexp literals //! - nil, true, false, Symbol literals //! - Creating Source vertices with fixed types //! @@ -57,6 +57,11 @@ pub fn install_literal(genv: &mut GlobalEnv, node: &Node) -> Option { return Some(genv.new_source(Type::symbol())); } + // /pattern/ + if node.as_regular_expression_node().is_some() { + return Some(genv.new_source(Type::regexp())); + } + None } @@ -89,4 +94,12 @@ mod tests { let vtx = genv.new_source(Type::float()); assert_eq!(genv.get_source(vtx).unwrap().ty.show(), "Float"); } + + #[test] + fn test_install_regexp_literal() { + let mut genv = GlobalEnv::new(); + + let vtx = genv.new_source(Type::regexp()); + assert_eq!(genv.get_source(vtx).unwrap().ty.show(), "Regexp"); + } } diff --git a/rust/src/analyzer/tests/integration_test.rs b/rust/src/analyzer/tests/integration_test.rs index c645123..3898940 100644 --- a/rust/src/analyzer/tests/integration_test.rs +++ b/rust/src/analyzer/tests/integration_test.rs @@ -34,6 +34,11 @@ fn analyze(source: &str) -> (GlobalEnv, LocalEnv) { genv.register_builtin_method(Type::array(), "map", Type::array()); genv.register_builtin_method(Type::hash(), "each", Type::hash()); + // Register Regexp methods + genv.register_builtin_method(Type::regexp(), "match", Type::instance("MatchData")); + genv.register_builtin_method(Type::regexp(), "match?", Type::instance("TrueClass")); + genv.register_builtin_method(Type::regexp(), "source", Type::string()); + let mut lenv = LocalEnv::new(); let mut installer = AstInstaller::new(&mut genv, &mut lenv, source); @@ -471,3 +476,52 @@ c = x.abs let c_vtx = lenv.get_var("c").unwrap(); assert_eq!(genv.get_vertex(c_vtx).unwrap().show(), "Float"); } + +// ============================================ +// Regexp Literal Tests +// ============================================ + +#[test] +fn test_regexp_literal_basic() { + let source = r#"x = /hello/"#; + + let (genv, lenv) = analyze(source); + + let x_vtx = lenv.get_var("x").unwrap(); + assert_eq!(genv.get_vertex(x_vtx).unwrap().show(), "Regexp"); +} + +#[test] +fn test_regexp_literal_type_error() { + let source = r#" +class Matcher + def find + x = /pattern/ + y = x.upcase + end +end +"#; + + let (genv, _lenv) = analyze(source); + + // Type error should be detected: Regexp doesn't have upcase method + assert_eq!(genv.type_errors.len(), 1); + assert_eq!(genv.type_errors[0].method_name, "upcase"); +} + +#[test] +fn test_regexp_specific_methods() { + let source = r#" +x = /hello/ +a = x.source +"#; + + let (genv, lenv) = analyze(source); + + // No type errors - source is a valid Regexp method + assert_eq!(genv.type_errors.len(), 0); + + // source returns String + let a_vtx = lenv.get_var("a").unwrap(); + assert_eq!(genv.get_vertex(a_vtx).unwrap().show(), "String"); +} diff --git a/rust/src/types.rs b/rust/src/types.rs index 0675e12..4580a1c 100644 --- a/rust/src/types.rs +++ b/rust/src/types.rs @@ -242,6 +242,12 @@ impl Type { } } + pub fn regexp() -> Self { + Type::Instance { + name: QualifiedName::simple("Regexp"), + } + } + /// Create a generic Array type: Array[element_type] pub fn array_of(element_type: Type) -> Self { Type::Generic {