Introduce the document structure.

This commit is contained in:
Tom Alexander 2023-03-23 17:51:49 -04:00
parent 35d60c10ba
commit d98a11059c
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE
11 changed files with 120 additions and 36 deletions

View File

@ -1 +0,0 @@
Two line breaks to end paragraph except in code blocks

View File

@ -0,0 +1,23 @@
SHELL := bash
.ONESHELL:
.SHELLFLAGS := -eu -o pipefail -c
.DELETE_ON_ERROR:
MAKEFLAGS += --warn-undefined-variables
MAKEFLAGS += --no-builtin-rules
SRCFILES := $(wildcard *.org)
OUTFILES := $(patsubst %.org,%.tree.txt,$(SRCFILES))
ifeq ($(origin .RECIPEPREFIX), undefined)
$(error This Make does not support .RECIPEPREFIX. Please use GNU Make 4.0 or later)
endif
.RECIPEPREFIX = >
.PHONY: all
all: $(OUTFILES)
.PHONY: clean
clean:
> rm -rf $(OUTFILES)
%.tree.txt: %.org ../common.el ../dump_org_ast.bash
> ../dump_org_ast.bash $< $@

View File

@ -0,0 +1 @@
* Start a document with an immediate heading

View File

@ -0,0 +1,7 @@
Before the first heading
* The first heading
body of the first section
** Child heading
body of child heading
* second top-level heading
body of second top-level heading

View File

@ -1,4 +1,4 @@
use crate::parser::document; // use crate::parser::document;
use tracing::Level; use tracing::Level;
use tracing_subscriber::fmt::format::FmtSpan; use tracing_subscriber::fmt::format::FmtSpan;
@ -18,8 +18,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
.with_span_events(FmtSpan::ENTER | FmtSpan::EXIT) .with_span_events(FmtSpan::ENTER | FmtSpan::EXIT)
.finish(); .finish();
tracing::subscriber::set_global_default(subscriber)?; tracing::subscriber::set_global_default(subscriber)?;
let parsed = document(TEST_DOC); // let parsed = document(TEST_DOC);
println!("{}\n\n\n", TEST_DOC); // println!("{}\n\n\n", TEST_DOC);
println!("{:#?}", parsed); // println!("{:#?}", parsed);
Ok(()) Ok(())
} }

View File

@ -1,29 +1,42 @@
//! A single element of text. use super::element::Element;
use super::combinator::context_many1; use super::source::Source;
use super::error::Res;
use super::paragraph::paragraph;
use super::parser_context::ContextElement;
use super::parser_context::ContextTree;
use super::token::Paragraph;
use super::token::Token;
use super::Context;
use nom::IResult;
type UnboundMatcher<'r, 's, I, O, E> = dyn Fn(Context<'r, 's>, I) -> IResult<I, O, E>; #[derive(Debug)]
pub struct Document<'s> {
// TODO: Implement FromStr for Document pub source: &'s str,
pub zeroth_section: Option<Section<'s>>,
pub fn document(input: &str) -> Res<&str, Vec<Paragraph>> { pub children: Vec<Heading<'s>>,
let initial_context: ContextTree<'_, '_> = ContextTree::new(); }
let document_context =
initial_context.with_additional_node(ContextElement::DocumentRoot(input)); #[derive(Debug)]
let (remaining, tokens) = context_many1(&document_context, paragraph)(input)?; pub struct Heading<'s> {
let paragraphs = tokens pub source: &'s str,
.into_iter() pub children: Vec<DocumentElement<'s>>,
.map(|token| match token { }
Token::TextElement(_) => unreachable!(),
Token::Paragraph(paragraph) => paragraph, #[derive(Debug)]
}) pub struct Section<'s> {
.collect(); pub source: &'s str,
Ok((remaining, paragraphs)) pub children: Vec<Element<'s>>,
}
#[derive(Debug)]
pub enum DocumentElement<'s> {
Heading(Heading<'s>),
Section(Section<'s>),
}
impl<'s> Source<'s> for Document<'s> {
fn get_source(&'s self) -> &'s str {
self.source
}
}
impl<'s> Source<'s> for DocumentElement<'s> {
fn get_source(&'s self) -> &'s str {
match self {
DocumentElement::Heading(obj) => obj.source,
DocumentElement::Section(obj) => obj.source,
}
}
} }

View File

@ -1,7 +1,18 @@
use super::greater_element::PlainList; use super::greater_element::PlainList;
use super::lesser_element::Paragraph; use super::lesser_element::Paragraph;
use super::source::Source;
#[derive(Debug)]
pub enum Element<'s> { pub enum Element<'s> {
Paragraph(Paragraph<'s>), Paragraph(Paragraph<'s>),
PlainList(PlainList<'s>), PlainList(PlainList<'s>),
} }
impl<'s> Source<'s> for Element<'s> {
fn get_source(&'s self) -> &'s str {
match self {
Element::Paragraph(obj) => obj.source,
Element::PlainList(obj) => obj.source,
}
}
}

View File

@ -12,10 +12,10 @@ mod paragraph;
mod parser_context; mod parser_context;
mod parser_with_context; mod parser_with_context;
mod plain_list; mod plain_list;
mod source;
mod text; mod text;
mod token; mod token;
mod util; mod util;
pub use document::document;
type Context<'r, 's> = &'r parser_context::ContextTree<'r, 's>; type Context<'r, 's> = &'r parser_context::ContextTree<'r, 's>;
pub use parser_context::ContextTree; pub use parser_context::ContextTree;
pub use plain_list::item; pub use plain_list::item;

View File

@ -1,6 +1,4 @@
pub trait Source<'s> { use super::source::Source;
fn get_source(&'s self) -> &'s str;
}
#[derive(Debug)] #[derive(Debug)]
pub enum Object<'s> { pub enum Object<'s> {

View File

@ -0,0 +1,29 @@
//! A single element of text.
use super::combinator::context_many1;
use super::error::Res;
use super::paragraph::paragraph;
use super::parser_context::ContextElement;
use super::parser_context::ContextTree;
use super::token::Paragraph;
use super::token::Token;
use super::Context;
use nom::IResult;
type UnboundMatcher<'r, 's, I, O, E> = dyn Fn(Context<'r, 's>, I) -> IResult<I, O, E>;
// TODO: Implement FromStr for Document
pub fn document(input: &str) -> Res<&str, Vec<Paragraph>> {
let initial_context: ContextTree<'_, '_> = ContextTree::new();
let document_context =
initial_context.with_additional_node(ContextElement::DocumentRoot(input));
let (remaining, tokens) = context_many1(&document_context, paragraph)(input)?;
let paragraphs = tokens
.into_iter()
.map(|token| match token {
Token::TextElement(_) => unreachable!(),
Token::Paragraph(paragraph) => paragraph,
})
.collect();
Ok((remaining, paragraphs))
}

3
src/parser/source.rs Normal file
View File

@ -0,0 +1,3 @@
pub trait Source<'s> {
fn get_source(&'s self) -> &'s str;
}