rustemo::rustemo_mod!(#[allow(unreachable_patterns)] pub(crate) phenotyper, "/src/parser");
#[allow(unused)]
#[rustfmt::skip]
pub mod phenotyper_actions;
use rustemo::Parser;
use crate::diagnostic::Diagnostic;
use crate::lexer::source_map::extract_pht_blocks;
pub fn parse_pht(source: &str, file: &str) -> Result<phenotyper_actions::File, Vec<Diagnostic>> {
let parser = phenotyper::PhenotyperParser::new();
let forest = parser
.parse(source)
.map_err(|e| rustemo_error_to_diags(e, file))?;
forest
.get_first_tree()
.map(|tree| tree.build(&mut phenotyper::DefaultBuilder::new()))
.ok_or_else(|| {
vec![Diagnostic {
severity: crate::diagnostic::Severity::Error,
summary: "GLR parse produced no valid trees".to_string(),
file: file.to_string(),
line: 0,
col: 0,
explanation: Some(
"the parser could not disambiguate the input into a valid AST".to_string(),
),
suggestion: None,
}]
})
}
pub fn parse_md(markdown: &str, file: &str) -> Result<phenotyper_actions::File, Vec<Diagnostic>> {
let (_blocks, source_map) = extract_pht_blocks(markdown);
if source_map.source.is_empty() {
return Err(vec![Diagnostic {
severity: crate::diagnostic::Severity::Error,
summary: "no ```pht blocks found in markdown file".to_string(),
file: file.to_string(),
line: 0,
col: 0,
explanation: Some(
"the .md file must contain at least one fenced code block tagged 'pht'".to_string(),
),
suggestion: Some("add a ```pht ... ``` block".to_string()),
}]);
}
let source_with_dot = format!("{}\n.", source_map.source);
let parser = phenotyper::PhenotyperParser::new();
let forest = parser.parse(&source_with_dot).map_err(|e| {
let mut diags = rustemo_error_to_diags(e, file);
for diag in &mut diags {
if diag.line > 0 {
diag.line = source_map.original_line(diag.line);
}
}
diags
})?;
forest
.get_first_tree()
.map(|tree| tree.build(&mut phenotyper::DefaultBuilder::new()))
.ok_or_else(|| {
vec![Diagnostic {
severity: crate::diagnostic::Severity::Error,
summary: "GLR parse produced no valid trees".to_string(),
file: file.to_string(),
line: 0,
col: 0,
explanation: Some(
"the parser could not disambiguate the input into a valid AST".to_string(),
),
suggestion: None,
}]
})
}
fn rustemo_error_to_diags(err: rustemo::Error, file: &str) -> Vec<Diagnostic> {
vec![Diagnostic {
severity: crate::diagnostic::Severity::Error,
summary: format!("{err}"),
file: file.to_string(),
line: 0,
col: 0,
explanation: None,
suggestion: None,
}]
}
#[cfg(test)]
mod tests;