refactor(parser): process the parsed pairs in the 'title' module

This commit is contained in:
Orhun Parmaksız 2021-10-06 00:13:57 +03:00
parent 764b706c87
commit 2d1b9daf4a
No known key found for this signature in database
GPG key ID: F83424824B3E4B90
5 changed files with 80 additions and 32 deletions

View file

@ -6,6 +6,9 @@ pub enum Error {
/// Error that might occur during I/O operations.
#[error("IO error: `{0}`")]
IoError(#[from] std::io::Error),
/// Error that might occur while parsing documents.
#[error("parse error: `{0}`")]
ParseError(String),
}
/// Type alias for the standard [`Result`] type.

View file

@ -5,5 +5,8 @@
/// RST parser.
pub mod parser;
/// Parsed title.
pub mod title;
#[macro_use]
extern crate pest_derive;

View file

@ -1,8 +1,10 @@
#![allow(missing_docs)] // pest_derive does not have doc comments.
#![allow(missing_docs)] // pest_derive does not generate doc comments
use crate::title::Title;
use kparams_core::error::{Error, Result};
use kparams_core::kernel::{Documentation, Parameter};
use pest::Parser;
use pest::Token;
use std::convert::TryFrom;
/// Parser for the reStructuredText format.
#[derive(Parser)]
@ -13,37 +15,23 @@ impl RstParser {
/// Parses the given reStructuredText input and returns the [`kernel documentation`].
///
/// [`kernel documentation`]: Documentation
pub fn parse_docs(input: &str) -> Documentation {
let rst_document = Self::parse(Rule::document, input).expect("failed to parse document");
pub fn parse_docs(input: &str) -> Result<Documentation> {
let mut kernel_parameters = Vec::new();
let rst_document =
Self::parse(Rule::document, input).map_err(|e| Error::ParseError(e.to_string()))?;
let titles = rst_document
.filter(|block| block.as_rule() == Rule::title)
.map(|title| {
(
title.as_str().lines().next().unwrap(),
title
.tokens()
.filter_map(|token| match token {
Token::Start { rule, pos } | Token::End { rule, pos } => {
if rule == Rule::title {
Some(pos.pos())
} else {
None
}
}
})
.collect::<Vec<usize>>(),
)
})
.collect::<Vec<(&str, Vec<usize>)>>();
for (i, (title, pos)) in titles.iter().enumerate() {
assert_eq!(2, pos.len());
kernel_parameters.push(if let Some(next_title) = titles.get(i + 1) {
Parameter::new(*title, (input[pos[1]..next_title.1[0]]).as_ref())
} else {
Parameter::new(*title, (input[pos[1]..]).as_ref())
});
.filter_map(|pair| Title::try_from(pair).ok())
.collect::<Vec<Title<'_>>>();
for (i, title) in titles.iter().enumerate() {
kernel_parameters.push(Parameter::new(
title.value,
if let Some(next_title) = titles.get(i + 1) {
(input[title.end_pos..next_title.start_pos]).as_ref()
} else {
(input[title.end_pos..]).as_ref()
},
));
}
Documentation::new(kernel_parameters)
Ok(Documentation::new(kernel_parameters))
}
}

View file

@ -0,0 +1,54 @@
use crate::parser::Rule;
use kparams_core::error::Error as ErrorImpl;
use pest::iterators::Pair;
use pest::Token;
use std::convert::TryFrom;
/// Title from the parsed RST document.
#[derive(Debug, Default)]
pub struct Title<'a> {
/// Title value.
pub value: &'a str,
/// Start position of the title.
pub start_pos: usize,
/// End position of the title.
pub end_pos: usize,
}
impl<'a> TryFrom<Pair<'a, Rule>> for Title<'a> {
type Error = ErrorImpl;
fn try_from(pair: Pair<'a, Rule>) -> Result<Self, Self::Error> {
let mut title = Title::default();
// check if the rule matches
if pair.as_rule() == Rule::title {
return Err(ErrorImpl::ParseError(String::from(
"parsed section is not a title",
)));
}
// set the actual title
if let Some(value) = pair.as_str().lines().next() {
title.value = value;
} else {
return Err(ErrorImpl::ParseError(String::from("invalid title")));
}
// set token positions
pair.tokens().for_each(|token| match token {
Token::Start { rule, pos } => {
if rule == Rule::title {
title.start_pos = pos.pos();
}
}
Token::End { rule, pos } => {
if rule == Rule::title {
title.end_pos = pos.pos();
}
}
});
Ok(title)
}
}

View file

@ -13,7 +13,7 @@ pub fn run() -> Result<()> {
let sysctl_docs = kernel_docs.join("admin-guide").join("sysctl");
let kernel_section = reader::read_to_string(&sysctl_docs.join("kernel.rst"))?;
let kernel_section_docs = RstParser::parse_docs(&kernel_section);
let kernel_section_docs = RstParser::parse_docs(&kernel_section)?;
for kernel_parameter in kernel_section_docs.parameters {
println!("## {}", kernel_parameter.name);
println!("{}", kernel_parameter.description);