gridline_engine/engine/
preprocess.rs1use regex::Regex;
2
3use super::cell_ref::CellRef;
4
5pub fn preprocess_script(script: &str) -> String {
9 let with_ranges = crate::builtins::range_fn_re()
10 .replace_all(script, |caps: ®ex::Captures| {
11 let start_ref = &caps[2];
12 let end_ref = &caps[3];
13 let rest_args = caps.get(4).map(|m| m.as_str()).unwrap_or("");
14
15 let Some(rhai_name) = crate::builtins::range_rhai_name(&caps[1]) else {
16 return caps[0].to_string();
17 };
18
19 if let (Some(start), Some(end)) =
20 (CellRef::from_str(start_ref), CellRef::from_str(end_ref))
21 {
22 format!(
23 "{}({}, {}, {}, {}{})",
24 rhai_name, start.row, start.col, end.row, end.col, rest_args
25 )
26 } else {
27 caps[0].to_string()
28 }
29 })
30 .to_string();
31
32 replace_cell_refs_outside_strings(&with_ranges)
33}
34
35fn replace_cell_refs_outside_strings(script: &str) -> String {
36 let cell_re = Regex::new(r"\b([A-Za-z]+)([0-9]+)\b").unwrap();
37 let value_re = Regex::new(r"@([A-Za-z]+)([0-9]+)\b").unwrap();
38
39 let replace_cells = |seg: &str| {
40 let seg = value_re
41 .replace_all(seg, |caps: ®ex::Captures| {
42 let cell_ref = format!("{}{}", &caps[1], &caps[2]);
43 if let Some(cr) = CellRef::from_str(&cell_ref) {
44 format!("value({}, {})", cr.row, cr.col)
45 } else {
46 caps[0].to_string()
47 }
48 })
49 .to_string();
50
51 cell_re
52 .replace_all(&seg, |caps: ®ex::Captures| {
53 let cell_ref = format!("{}{}", &caps[1], &caps[2]);
54 if let Some(cr) = CellRef::from_str(&cell_ref) {
55 format!("cell({}, {})", cr.row, cr.col)
56 } else {
57 caps[0].to_string()
58 }
59 })
60 .to_string()
61 };
62
63 let bytes = script.as_bytes();
64 let mut out = String::new();
65 let mut seg_start = 0;
66 let mut in_string = false;
67 let mut backslashes = 0usize;
68 let mut i = 0usize;
69
70 while i < bytes.len() {
71 let b = bytes[i];
72 if in_string {
73 if b == b'\\' {
74 backslashes += 1;
75 i += 1;
76 continue;
77 }
78 if b == b'"' && backslashes.is_multiple_of(2) {
79 out.push_str(&script[seg_start..=i]);
80 in_string = false;
81 seg_start = i + 1;
82 }
83 backslashes = 0;
84 i += 1;
85 continue;
86 }
87
88 if b == b'"' {
89 out.push_str(&replace_cells(&script[seg_start..i]));
90 in_string = true;
91 seg_start = i;
92 backslashes = 0;
93 i += 1;
94 continue;
95 }
96
97 i += 1;
98 }
99
100 if seg_start < script.len() {
101 if in_string {
102 out.push_str(&script[seg_start..]);
103 } else {
104 out.push_str(&replace_cells(&script[seg_start..]));
105 }
106 }
107
108 out
109}