-
Notifications
You must be signed in to change notification settings - Fork 0
[JULES] Scheduled Maintenance: ⚡ Bolt: refactor pattern args logic and remove allocations #465
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,3 +1,4 @@ | ||||||||||||||||||||||||||||
| use super::helpers::{check_arg_count, expect_pattern, expect_text}; | ||||||||||||||||||||||||||||
| use crate::interpreter::environment::Environment; | ||||||||||||||||||||||||||||
| use crate::interpreter::error::RuntimeError; | ||||||||||||||||||||||||||||
| use crate::interpreter::value::Value; | ||||||||||||||||||||||||||||
|
|
@@ -19,74 +20,22 @@ pub fn register(env: &mut Environment) { | |||||||||||||||||||||||||||
| /// Native function: pattern_matches(text, pattern) -> boolean | ||||||||||||||||||||||||||||
| /// Tests if text matches the given compiled pattern | ||||||||||||||||||||||||||||
| pub fn pattern_matches_native(args: Vec<Value>) -> Result<Value, RuntimeError> { | ||||||||||||||||||||||||||||
| if args.len() != 2 { | ||||||||||||||||||||||||||||
| return Err(RuntimeError::new( | ||||||||||||||||||||||||||||
| "pattern_matches requires exactly 2 arguments (text, pattern)".to_string(), | ||||||||||||||||||||||||||||
| 0, | ||||||||||||||||||||||||||||
| 0, | ||||||||||||||||||||||||||||
| )); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| let text_str = match &args[0] { | ||||||||||||||||||||||||||||
| Value::Text(s) => s.as_ref(), | ||||||||||||||||||||||||||||
| _ => { | ||||||||||||||||||||||||||||
| return Err(RuntimeError::new( | ||||||||||||||||||||||||||||
| "First argument to pattern_matches must be text".to_string(), | ||||||||||||||||||||||||||||
| 0, | ||||||||||||||||||||||||||||
| 0, | ||||||||||||||||||||||||||||
| )); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| let compiled_pattern = match &args[1] { | ||||||||||||||||||||||||||||
| Value::Pattern(p) => p, | ||||||||||||||||||||||||||||
| _ => { | ||||||||||||||||||||||||||||
| return Err(RuntimeError::new( | ||||||||||||||||||||||||||||
| "Second argument to pattern_matches must be a compiled pattern".to_string(), | ||||||||||||||||||||||||||||
| 0, | ||||||||||||||||||||||||||||
| 0, | ||||||||||||||||||||||||||||
| )); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||
| check_arg_count("pattern_matches", &args, 2)?; | ||||||||||||||||||||||||||||
| let text_str = expect_text(&args[0])?; | ||||||||||||||||||||||||||||
| let compiled_pattern = expect_pattern(&args[1])?; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| let matches = compiled_pattern.matches(text_str); | ||||||||||||||||||||||||||||
| let matches = compiled_pattern.matches(text_str.as_ref()); | ||||||||||||||||||||||||||||
| Ok(Value::Bool(matches)) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| /// Native function: pattern_find(text, pattern) -> object or null | ||||||||||||||||||||||||||||
| /// Finds the first match of pattern in text | ||||||||||||||||||||||||||||
| pub fn pattern_find_native(args: Vec<Value>) -> Result<Value, RuntimeError> { | ||||||||||||||||||||||||||||
| if args.len() != 2 { | ||||||||||||||||||||||||||||
| return Err(RuntimeError::new( | ||||||||||||||||||||||||||||
| "pattern_find requires exactly 2 arguments (text, pattern)".to_string(), | ||||||||||||||||||||||||||||
| 0, | ||||||||||||||||||||||||||||
| 0, | ||||||||||||||||||||||||||||
| )); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| let text_str = match &args[0] { | ||||||||||||||||||||||||||||
| Value::Text(s) => s.as_ref(), | ||||||||||||||||||||||||||||
| _ => { | ||||||||||||||||||||||||||||
| return Err(RuntimeError::new( | ||||||||||||||||||||||||||||
| "First argument to pattern_find must be text".to_string(), | ||||||||||||||||||||||||||||
| 0, | ||||||||||||||||||||||||||||
| 0, | ||||||||||||||||||||||||||||
| )); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| let compiled_pattern = match &args[1] { | ||||||||||||||||||||||||||||
| Value::Pattern(p) => p, | ||||||||||||||||||||||||||||
| _ => { | ||||||||||||||||||||||||||||
| return Err(RuntimeError::new( | ||||||||||||||||||||||||||||
| "Second argument to pattern_find must be a compiled pattern".to_string(), | ||||||||||||||||||||||||||||
| 0, | ||||||||||||||||||||||||||||
| 0, | ||||||||||||||||||||||||||||
| )); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||
| check_arg_count("pattern_find", &args, 2)?; | ||||||||||||||||||||||||||||
| let text_str = expect_text(&args[0])?; | ||||||||||||||||||||||||||||
| let compiled_pattern = expect_pattern(&args[1])?; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| match compiled_pattern.find(text_str) { | ||||||||||||||||||||||||||||
| match compiled_pattern.find(text_str.as_ref()) { | ||||||||||||||||||||||||||||
| Some(match_result) => { | ||||||||||||||||||||||||||||
| let mut result_map = HashMap::new(); | ||||||||||||||||||||||||||||
| result_map.insert( | ||||||||||||||||||||||||||||
|
|
@@ -120,37 +69,11 @@ pub fn pattern_find_native(args: Vec<Value>) -> Result<Value, RuntimeError> { | |||||||||||||||||||||||||||
| /// Native function: pattern_find_all(text, pattern) -> list | ||||||||||||||||||||||||||||
| /// Finds all matches of pattern in text | ||||||||||||||||||||||||||||
| pub fn pattern_find_all_native(args: Vec<Value>) -> Result<Value, RuntimeError> { | ||||||||||||||||||||||||||||
| if args.len() != 2 { | ||||||||||||||||||||||||||||
| return Err(RuntimeError::new( | ||||||||||||||||||||||||||||
| "pattern_find_all requires exactly 2 arguments (text, pattern)".to_string(), | ||||||||||||||||||||||||||||
| 0, | ||||||||||||||||||||||||||||
| 0, | ||||||||||||||||||||||||||||
| )); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| let text_str = match &args[0] { | ||||||||||||||||||||||||||||
| Value::Text(s) => s.as_ref(), | ||||||||||||||||||||||||||||
| _ => { | ||||||||||||||||||||||||||||
| return Err(RuntimeError::new( | ||||||||||||||||||||||||||||
| "First argument to pattern_find_all must be text".to_string(), | ||||||||||||||||||||||||||||
| 0, | ||||||||||||||||||||||||||||
| 0, | ||||||||||||||||||||||||||||
| )); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| let compiled_pattern = match &args[1] { | ||||||||||||||||||||||||||||
| Value::Pattern(p) => p, | ||||||||||||||||||||||||||||
| _ => { | ||||||||||||||||||||||||||||
| return Err(RuntimeError::new( | ||||||||||||||||||||||||||||
| "Second argument to pattern_find_all must be a compiled pattern".to_string(), | ||||||||||||||||||||||||||||
| 0, | ||||||||||||||||||||||||||||
| 0, | ||||||||||||||||||||||||||||
| )); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||
| check_arg_count("pattern_find_all", &args, 2)?; | ||||||||||||||||||||||||||||
| let text_str = expect_text(&args[0])?; | ||||||||||||||||||||||||||||
| let compiled_pattern = expect_pattern(&args[1])?; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| let matches = compiled_pattern.find_all(text_str); | ||||||||||||||||||||||||||||
| let matches = compiled_pattern.find_all(text_str.as_ref()); | ||||||||||||||||||||||||||||
| let mut result_list = Vec::new(); | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| for match_result in matches { | ||||||||||||||||||||||||||||
|
|
@@ -197,41 +120,14 @@ pub fn native_pattern_replace( | |||||||||||||||||||||||||||
| )); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| let text = match &args[0] { | ||||||||||||||||||||||||||||
| Value::Text(t) => t.as_ref(), | ||||||||||||||||||||||||||||
| _ => { | ||||||||||||||||||||||||||||
| return Err(RuntimeError::new( | ||||||||||||||||||||||||||||
| "First argument must be text".to_string(), | ||||||||||||||||||||||||||||
| line, | ||||||||||||||||||||||||||||
| column, | ||||||||||||||||||||||||||||
| )); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| let _pattern = match &args[1] { | ||||||||||||||||||||||||||||
| Value::Pattern(p) => p.as_ref(), | ||||||||||||||||||||||||||||
| _ => { | ||||||||||||||||||||||||||||
| return Err(RuntimeError::new( | ||||||||||||||||||||||||||||
| "Second argument must be a pattern".to_string(), | ||||||||||||||||||||||||||||
| line, | ||||||||||||||||||||||||||||
| column, | ||||||||||||||||||||||||||||
| )); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| let _replacement = match &args[2] { | ||||||||||||||||||||||||||||
| Value::Text(t) => t.as_ref(), | ||||||||||||||||||||||||||||
| _ => { | ||||||||||||||||||||||||||||
| return Err(RuntimeError::new( | ||||||||||||||||||||||||||||
| "Third argument must be text".to_string(), | ||||||||||||||||||||||||||||
| line, | ||||||||||||||||||||||||||||
| column, | ||||||||||||||||||||||||||||
| )); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||
| let text = expect_text(&args[0]).map_err(|e| RuntimeError::new(e.message, line, column))?; | ||||||||||||||||||||||||||||
| let _pattern = | ||||||||||||||||||||||||||||
| expect_pattern(&args[1]).map_err(|e| RuntimeError::new(e.message, line, column))?; | ||||||||||||||||||||||||||||
| let _replacement = | ||||||||||||||||||||||||||||
| expect_text(&args[2]).map_err(|e| RuntimeError::new(e.message, line, column))?; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| // TODO: Update to use new pattern system for replacement | ||||||||||||||||||||||||||||
| Ok(Value::Text(Arc::from(text))) | ||||||||||||||||||||||||||||
| Ok(Value::Text(Arc::clone(&text))) | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
| Ok(Value::Text(Arc::clone(&text))) | |
| Ok(Value::Text(text)) |
Copilot
AI
Apr 23, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same pattern here: consider mutating and returning the existing RuntimeError from expect_* in the map_err closure (set line/column) instead of reconstructing it, to keep error metadata intact.
| let text = expect_text(&args[0]).map_err(|e| RuntimeError::new(e.message, line, column))?; | |
| let pattern = | |
| expect_pattern(&args[1]).map_err(|e| RuntimeError::new(e.message, line, column))?; | |
| let text = expect_text(&args[0]).map_err(|mut e| { | |
| e.line = line; | |
| e.column = column; | |
| e | |
| })?; | |
| let pattern = expect_pattern(&args[1]).map_err(|mut e| { | |
| e.line = line; | |
| e.column = column; | |
| e | |
| })?; |
Copilot
AI
Apr 23, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the no-matches early return, text can be moved directly into Value::Text (since this branch returns immediately) rather than Arc::clone(&text), avoiding an unnecessary atomic refcount bump.
| let parts = vec![Value::Text(Arc::clone(&text))]; | |
| let parts = vec![Value::Text(text)]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
map_err(|e| RuntimeError::new(e.message, line, column))recreates the error. SinceRuntimeErrorfields are public, you can setline/columnon the existing error in the closure and return it (preserves other fields likekindand avoids reconstructing).