#[doc(hidden)]
#[macro_use]
pub mod internal_prelude;
#[macro_use]
mod structural;
#[macro_use]
mod derive;
mod error;
mod impls;
pub mod keyword;
mod lex;
mod lines;
pub mod multiplicity;
mod signatures;
mod traits;
use internal_prelude::*;
pub use error::{ArgumentError, ErrorProblem, ParseError, UnexpectedArgument, VerifyFailed};
pub use impls::times::NdaSystemTimeDeprecatedSyntax;
pub use keyword::KeywordRef;
pub use lex::{ArgumentStream, ItemStream, NoFurtherArguments, UnparsedItem, UnparsedObject};
pub use lines::{Lines, Peeked, StrExt};
pub use signatures::{
HasUnverifiedParsedBody, NetdocParseableSignatures, NetdocParseableUnverified,
SignatureHashInputs, SignatureHashesAccumulator, SignatureItemParseable, SignaturesData,
sig_hashes,
};
#[allow(deprecated)]
#[deprecated]
pub use signatures::{check_validity_time, check_validity_time_tolerance};
pub use structural::{StopAt, StopPredicate};
pub use traits::{
IsStructural, ItemArgumentParseable, ItemObjectParseable, ItemValueParseable, NetdocParseable,
NetdocParseableFields,
};
#[doc(hidden)]
pub use derive::netdoc_parseable_derive_debug;
pub(crate) use internal_prelude::EP;
#[derive(educe::Educe, Debug, Clone)]
#[allow(clippy::manual_non_exhaustive)]
#[educe(Default)]
pub struct ParseOptions {
#[educe(Default(expression = "Unknown::new_discard()"))]
pub retain_unknown_values: Unknown<()>,
#[doc(hidden)]
_private_non_exhaustive: (),
}
#[derive(Debug, Clone, amplify::Getters)]
pub struct ParseInput<'s> {
#[getter(as_copy)]
input: &'s str,
#[getter(as_copy)]
file: &'s str,
#[getter(as_ref, as_mut)]
options: ParseOptions,
}
impl<'s> ParseInput<'s> {
pub fn new(input: &'s str, file: &'s str) -> Self {
ParseInput {
input,
file,
options: ParseOptions::default(),
}
}
#[cfg(feature = "retain-unknown")]
pub fn retain_unknown_values(&mut self) {
self.options_mut().retain_unknown_values = Unknown::Retained(());
}
}
fn parse_internal<T, D: NetdocParseable>(
input: &ParseInput<'_>,
parse_completely: impl FnOnce(&mut ItemStream) -> Result<T, ErrorProblem>,
) -> Result<T, ParseError> {
let mut items = ItemStream::new(input);
parse_completely(&mut items).map_err(error_handler::<D>(input, &items))
}
fn error_handler<D: NetdocParseable>(
input: &ParseInput<'_>,
items: &ItemStream<'_>,
) -> impl Fn(ErrorProblem) -> ParseError {
|problem| ParseError {
problem,
doctype: D::doctype_for_error(),
file: input.file.to_owned(),
lno: items.lno_for_error(),
column: problem.column(),
}
}
pub fn parse_netdoc<D: NetdocParseable>(input: &ParseInput<'_>) -> Result<D, ParseError> {
parse_internal::<_, D>(input, |items| {
let doc = D::from_items(items, StopAt(false))?;
if let Some(_kw) = items.peek_keyword()? {
return Err(EP::MultipleDocuments);
}
Ok(doc)
})
}
pub fn parse_netdoc_multiple<D: NetdocParseable>(
input: &ParseInput<'_>,
) -> Result<Vec<D>, ParseError> {
parse_internal::<_, D>(input, |items| {
let mut docs = vec![];
while items.peek_keyword()?.is_some() {
let doc = D::from_items(items, StopAt(false))?;
docs.push(doc);
}
Ok(docs)
})
}
#[derive(Debug, Error)]
#[error("out of bounds bug")]
struct OutOfBoundsBug;
fn multi_push_doc<T>(
docs: &mut Vec<(T, usize, usize)>,
input: &ParseInput<'_>,
doc: T,
start_pos: usize,
end_pos: usize,
) -> Result<(), OutOfBoundsBug> {
if input.input.get(start_pos..end_pos).is_none() {
return Err(OutOfBoundsBug);
}
docs.push((doc, start_pos, end_pos));
Ok(())
}
pub fn parse_netdoc_multiple_with_offsets<D: NetdocParseable>(
input: &ParseInput<'_>,
) -> Result<Vec<(D, usize, usize)>, ParseError> {
parse_internal::<_, D>(input, |items| {
let mut docs = vec![];
while items.peek_keyword()?.is_some() {
let start_pos = items.byte_position();
let doc = D::from_items(items, StopAt(false))?;
let end_pos = items.byte_position();
multi_push_doc(&mut docs, input, doc, start_pos, end_pos)
.map_err(|OutOfBoundsBug| ErrorProblem::Internal("out-of-bounds bug?"))?;
}
Ok(docs)
})
}
#[allow(clippy::type_complexity)] pub fn parse_netdoc_multiple_sophisticated<D: NetdocParseable>(
input: &ParseInput<'_>,
) -> Result<Vec<(Result<D, ParseError>, usize, usize)>, Bug> {
let mut items = ItemStream::new(input);
let mut docs = vec![];
let mut push_doc = |doc, start, end| {
multi_push_doc(&mut docs, input, doc, start, end)
.map_err(into_internal!("while parsing netdoc sequence"))
};
'docs: loop {
let start_pos = items.byte_position();
let _intro_kw: KeywordRef = match items.peek_keyword() {
Ok(Some(kw)) => kw,
Ok(None) => break 'docs,
Err(e) => {
push_doc(
Err(error_handler::<D>(input, &items)(e)),
start_pos,
items.whole_input().len(),
)?;
break 'docs;
}
};
let doc = D::from_items(&mut items, StopAt(false)) .map_err(error_handler::<D>(input, &items));
let is_err = doc.is_err();
let end_pos = items.byte_position();
push_doc(doc, start_pos, end_pos)?;
if is_err {
let _next_intro_kw: KeywordRef = 'skip: loop {
let _discard_item: UnparsedItem = match items.peek_keyword().unwrap_or(None) {
None => break 'docs,
Some(kw) if D::is_intro_item_keyword(kw) => break 'skip kw,
Some(_other_kw) => match items.next().transpose().unwrap_or(None) {
Some(item) => item,
None => break 'docs,
},
};
};
}
}
Ok(docs)
}