///|
/// One diagnostic produced while parsing baseline text.
pub(all) struct BaselineParseIssue {
line : Int
content : String
message : String
} derive(Eq, Debug)
///|
/// Result of parsing a portable MoonBench baseline document.
pub(all) struct BaselineParseReport {
baselines : BaselineSet
issues : Array[BaselineParseIssue]
} derive(Eq, Debug)
///|
/// Parse `name=mean_us` lines into a baseline set.
///
/// Empty lines and lines beginning with `#` are ignored. Whitespace around
/// names and values is trimmed. Invalid lines are reported and skipped, while
/// duplicate names use the last valid value.
pub fn BaselineSet::parse_text(text : String) -> BaselineParseReport {
let mut baselines = BaselineSet::new()
let issues : Array[BaselineParseIssue] = []
let mut line_number = 0
for raw_line in text.split("\n") {
line_number = line_number + 1
let line = raw_line.trim().to_owned()
if line == "" || line.has_prefix("#") {
continue
}
match line.split_once("=") {
None =>
issues.push({
line: line_number,
content: line,
message: "expected name=mean_us",
})
Some((raw_name, raw_value)) => {
let name = raw_name.trim().to_owned()
let value_text = raw_value.trim().to_owned()
let validation = validate_benchmark_name(name)
if !validation.ok {
issues.push({
line: line_number,
content: line,
message: validation.message,
})
continue
}
match parse_baseline_value(value_text) {
None =>
issues.push({
line: line_number,
content: line,
message: "mean_us must be a finite non-negative number",
})
Some(value) =>
if value.is_nan() || value.is_inf() || value < 0.0 {
issues.push({
line: line_number,
content: line,
message: "mean_us must be a finite non-negative number",
})
} else {
baselines = baselines.set(name, value)
}
}
}
}
}
{ baselines, issues }
}
///|
fn parse_baseline_value(text : String) -> Double? {
try @string.parse_double(text) catch {
_ => None
} noraise {
value => Some(value)
}
}
///|
/// Whether the complete baseline document parsed without diagnostics.
pub fn BaselineParseReport::is_valid(self : BaselineParseReport) -> Bool {
self.issues.length() == 0
}
///|
/// Number of accepted, unique baseline entries.
pub fn BaselineParseReport::count(self : BaselineParseReport) -> Int {
self.baselines.count()
}
///|
/// Number of invalid input lines.
pub fn BaselineParseReport::issue_count(self : BaselineParseReport) -> Int {
self.issues.length()
}
///|
/// Render parser diagnostics as Markdown for CI summaries.
pub fn BaselineParseReport::issues_to_markdown(
self : BaselineParseReport,
) -> String {
if self.issues.length() == 0 {
return "No baseline parse issues.\n"
}
let mut body = "| line | content | issue |\n"
body = body + "| ---: | --- | --- |\n"
for issue in self.issues {
body = body +
"| \{issue.line} | \{escape_markdown(issue.content)} | \{escape_markdown(issue.message)} |\n"
}
body
}