use super::Diagnostic;
use super::Span;
use super::lexer::PreambleToken;
use super::parser::Event;
use super::parser::Marker;
use super::parser::Parser;
use super::tree::SyntaxKind;
use crate::SupportedVersion;
use crate::lexer::VersionStatementToken;
pub mod v1;
mod macros {
macro_rules! expected {
($parser:ident, $marker:ident, $token:expr) => {
if let Err(e) = $parser.expect($token) {
return Err(($marker, e));
}
};
($parser:ident, $marker:ident, $token:expr, $name:literal) => {
if let Err(e) = $parser.expect_with_name($token, $name) {
return Err(($marker, e));
}
};
}
macro_rules! expected_in {
($parser:ident, $marker:ident, $set:ident $(, $names:literal)+ $(,)?) => {
if let Err(e) = $parser.expect_in($set, &[$($names),+]) {
return Err(($marker, e));
}
};
}
macro_rules! expected_fn {
($parser:ident, $marker:ident, $func:ident) => {
let inner = $parser.start();
if let Err((inner, e)) = $func($parser, inner) {
inner.abandon($parser);
return Err(($marker, e));
}
};
($parser:ident, $func:ident) => {
let inner = $parser.start();
if let Err((inner, e)) = $func($parser, inner) {
inner.abandon($parser);
return Err(e);
}
};
}
pub(crate) use expected;
pub(crate) use expected_fn;
pub(crate) use expected_in;
}
type PreambleParser<'a> = Parser<'a, PreambleToken>;
pub fn document(source: &str, mut parser: PreambleParser<'_>) -> (Vec<Event>, Vec<Diagnostic>) {
let root = parser.start();
let (mut parser, diagnostic) = match parser.peek() {
Some((PreambleToken::VersionKeyword, _)) => {
let marker = parser.start();
let (mut parser, res) = version_statement(parser, marker);
match res {
Ok(span) => {
let version = &source[span.start()..span.end()];
match version.parse::<SupportedVersion>() {
Ok(_) => {
let mut parser = parser.morph();
v1::items(&mut parser);
root.complete(&mut parser, SyntaxKind::RootNode);
let output = parser.finish();
return (output.events, output.diagnostics);
}
_ => (
parser,
Diagnostic::error(format!("unsupported WDL version `{version}`"))
.with_label("this version of WDL is not supported", span),
),
}
}
Err((marker, e)) => {
marker.abandon(&mut parser);
(parser, e)
}
}
}
found => {
let mut diagnostic =
Diagnostic::error("a WDL document must start with a version statement");
if let Some((_, span)) = found {
diagnostic =
diagnostic.with_label("a version statement must come before this", span);
}
(parser, diagnostic)
}
};
parser.diagnostic(diagnostic);
parser.consume_remainder();
root.complete(&mut parser, SyntaxKind::RootNode);
let output = parser.finish();
(output.events, output.diagnostics)
}
pub fn version_statement(
mut parser: Parser<'_, PreambleToken>,
marker: Marker,
) -> (
Parser<'_, PreambleToken>,
Result<Span, (Marker, Diagnostic)>,
) {
parser.require(PreambleToken::VersionKeyword);
let mut parser: Parser<'_, VersionStatementToken> = parser.morph();
let span = match parser.expect(VersionStatementToken::Version) {
Ok(span) => span,
Err(e) => return (parser.morph(), Err((marker, e))),
};
marker.complete(&mut parser, SyntaxKind::VersionStatementNode);
(parser.morph(), Ok(span))
}