use super::calls::{
format_helper_with_casts, match_collection_constructor, match_numeric_helper,
match_unary_pattern,
};
use super::literals::{match_big_byte_literal, match_big_integer_literal, match_map_literal};
pub(super) fn csharpize_expression(text: &str) -> String {
rewrite_numeric_helpers(&rewrite_cat_operator(text))
}
fn rewrite_numeric_helpers(line: &str) -> String {
let bytes = line.as_bytes();
let mut out = String::with_capacity(line.len());
let mut i = 0;
let mut in_string: Option<u8> = None;
while i < bytes.len() {
let b = bytes[i];
if !b.is_ascii() {
if line.is_char_boundary(i) {
let ch = line[i..].chars().next().unwrap_or('\u{FFFD}');
out.push(ch);
i += ch.len_utf8();
} else {
i += 1;
}
continue;
}
if let Some(quote) = in_string {
out.push(b as char);
if b == b'\\' && i + 1 < bytes.len() {
let esc = line[i + 1..].chars().next().unwrap_or('\u{FFFD}');
out.push(esc);
i += 1 + esc.len_utf8();
continue;
}
if b == quote {
in_string = None;
}
i += 1;
continue;
}
if b == b'"' || b == b'\'' {
in_string = Some(b);
out.push(b as char);
i += 1;
continue;
}
let prev_is_ident_continuation = i > 0 && {
let p = bytes[i - 1];
p.is_ascii_alphanumeric() || p == b'_'
};
if !prev_is_ident_continuation {
if let Some(rendered) = match_unary_pattern(&line[i..]) {
out.push_str(&rendered.body);
i += rendered.consumed;
continue;
}
if let Some((replacement, consumed)) = match_collection_constructor(&line[i..]) {
out.push_str(replacement);
i += consumed;
continue;
}
if let Some((rendered, consumed)) = match_map_literal(&line[i..]) {
out.push_str(&rendered);
i += consumed;
continue;
}
if let Some((rendered, consumed)) = match_big_byte_literal(&line[i..]) {
out.push_str(&rendered);
i += consumed;
continue;
}
if let Some((rendered, consumed)) = match_big_integer_literal(&line[i..]) {
out.push_str(&rendered);
i += consumed;
continue;
}
if let Some(rule) = match_numeric_helper(&bytes[i..]) {
if !rule.int_cast_args.is_empty() {
if let Some(rendered) = format_helper_with_casts(&line[i..], &rule) {
out.push_str(&rendered.body);
i += rendered.consumed;
continue;
}
}
out.push_str(rule.replacement);
out.push('(');
i += rule.needle_len;
continue;
}
}
out.push(b as char);
i += 1;
}
out
}
fn rewrite_cat_operator(line: &str) -> String {
if !line.contains(" cat ") {
return line.to_string();
}
let bytes = line.as_bytes();
let mut out = String::with_capacity(line.len());
let mut i = 0;
let mut in_string: Option<u8> = None;
while i < bytes.len() {
let b = bytes[i];
if !b.is_ascii() {
if line.is_char_boundary(i) {
let ch = line[i..].chars().next().unwrap_or('\u{FFFD}');
out.push(ch);
i += ch.len_utf8();
} else {
i += 1;
}
continue;
}
if let Some(quote) = in_string {
out.push(b as char);
if b == b'\\' && i + 1 < bytes.len() {
let esc = line[i + 1..].chars().next().unwrap_or('\u{FFFD}');
out.push(esc);
i += 1 + esc.len_utf8();
continue;
}
if b == quote {
in_string = None;
}
i += 1;
continue;
}
if b == b'"' || b == b'\'' {
in_string = Some(b);
out.push(b as char);
i += 1;
continue;
}
if b == b' ' && i + 4 < bytes.len() && &bytes[i..i + 5] == b" cat " && i > 0 {
out.push_str(" + ");
i += 5;
continue;
}
out.push(b as char);
i += 1;
}
out
}