///|
fn append_document_slice(
output : String,
chars : Array[Char],
start : Int,
end : Int,
) -> String {
if start >= end {
output
} else {
output + scan_substring(chars, start, end)
}
}
///|
/// Rewrite accepted scanner matches while preserving replacement evidence.
pub fn rewrite_roman_text(
text : String,
config : RewriteConfig,
) -> Result[RomanRewriteReport, RomanRewriteError] {
let scan_report = match scan_roman_text(text, config.scan_config) {
Ok(report) => report
Err(error) => return Err(RewriteScanConfigurationFailed(error))
}
let chars = text.to_array()
let replacements : Array[RomanReplacement] = []
let skipped : Array[RomanRewriteSkipped] = []
let mut output = ""
let mut source_cursor = 0
let mut output_cursor = 0
for matched in scan_report.matches {
output = append_document_slice(
output,
chars,
source_cursor,
matched.span.start,
)
output_cursor = output_cursor + matched.span.start - source_cursor
match format_with_config(matched.report.value, config.target_format) {
Ok(replacement_text) => {
let replacement_length = replacement_text.to_array().length()
let output_span : SourceSpan = {
start: output_cursor,
end: output_cursor + replacement_length,
}
output = output + replacement_text
replacements.push({
source_span: matched.span,
output_span,
source_text: matched.source_text,
replacement_text,
value: matched.report.value,
})
output_cursor = output_span.end
}
Err(error) =>
match config.failure_policy {
FailOnUnformattableCandidate =>
return Err(RewriteFormatFailed(matched.span, error))
KeepUnformattableCandidate => {
output = output + matched.source_text
output_cursor = output_cursor +
matched.source_text.to_array().length()
skipped.push({
source_span: matched.span,
source_text: matched.source_text,
value: matched.report.value,
error,
})
}
}
}
source_cursor = matched.span.end
}
output = append_document_slice(output, chars, source_cursor, chars.length())
Ok({ original: text, output, replacements, skipped, scan_report })
}