diff options
| author | Philipp A | 2019-12-26 23:01:00 +0100 | 
|---|---|---|
| committer | Philipp A | 2019-12-26 23:36:48 +0100 | 
| commit | a0e3c53758d526bb418c068bce1c99fa5a597ed3 (patch) | |
| tree | e640238b011a9ea7806ccccaf1a435e4b371a376 /src/parser | |
| parent | 7018f5d3c42f18b6c83f398db9f1915361a7c679 (diff) | |
| download | rust-rst-a0e3c53758d526bb418c068bce1c99fa5a597ed3.tar.bz2 | |
Split into smaller crates
Diffstat (limited to 'src/parser')
| -rw-r--r-- | src/parser/conversion.rs | 165 | ||||
| -rw-r--r-- | src/parser/conversion/block.rs | 202 | ||||
| -rw-r--r-- | src/parser/conversion/inline.rs | 161 | ||||
| -rw-r--r-- | src/parser/pair_ext_parse.rs | 21 | ||||
| -rw-r--r-- | src/parser/pest_rst.rs | 7 | ||||
| -rw-r--r-- | src/parser/simplify.rs | 662 | ||||
| -rw-r--r-- | src/parser/tests.rs | 241 | ||||
| -rw-r--r-- | src/parser/token.rs | 16 | 
8 files changed, 0 insertions, 1475 deletions
| diff --git a/src/parser/conversion.rs b/src/parser/conversion.rs deleted file mode 100644 index f9e2a78..0000000 --- a/src/parser/conversion.rs +++ /dev/null @@ -1,165 +0,0 @@ -mod block; -mod inline; - -use failure::Error; -use pest::iterators::Pairs; - -use crate::document_tree::{ -	Element,HasChildren, -	elements as e, -	element_categories as c, -	attribute_types as at, -}; - -use super::pest_rst::Rule; - - -fn ssubel_to_section_unchecked_mut(ssubel: &mut c::StructuralSubElement) -> &mut e::Section { -	match ssubel { -		c::StructuralSubElement::SubStructure(ref mut b) => match **b { -			c::SubStructure::Section(ref mut s) => s, -			_ => unreachable!(), -		}, -		_ => unreachable!(), -	} -} - - -fn get_level<'tl>(toplevel: &'tl mut Vec<c::StructuralSubElement>, section_idxs: &[Option<usize>]) -> &'tl mut Vec<c::StructuralSubElement> { -	let mut level = toplevel; -	for maybe_i in section_idxs { -		if let Some(i) = *maybe_i { -			level = ssubel_to_section_unchecked_mut(&mut level[i]).children_mut(); -		} -	} -	level -} - - -pub fn convert_document(pairs: Pairs<Rule>) -> Result<e::Document, Error> { -	use self::block::TitleOrSsubel::*; -	 -	let mut toplevel: Vec<c::StructuralSubElement> = vec![]; -	// The kinds of section titles encountered. -	// `section_idx[x]` has the kind `kinds[x]`, but `kinds` can be longer -	let mut kinds: Vec<block::TitleKind> = vec![]; -	// Recursive indices into the tree, pointing at the active sections. -	// `None`s indicate skipped section levels: -	// toplevel[section_idxs.flatten()[0]].children[section_idxs.flatten()[1]]... -	let mut section_idxs: Vec<Option<usize>> = vec![]; -	 -	for pair in pairs { -		if let Some(ssubel) = block::convert_ssubel(pair)? { match ssubel { -			Title(title, kind) => { -				match kinds.iter().position(|k| k == &kind) { -					// Idx points to the level we want to add, -					// so idx-1 needs to be the last valid index. -					Some(idx) => { -						// If idx < len: Remove found section and all below -						section_idxs.truncate(idx); -						// If idx > len: Add None for skipped levels -						// TODO: test skipped levels -						while section_idxs.len() < idx { section_idxs.push(None) } -					}, -					None => kinds.push(kind), -				} -				let super_level = get_level(&mut toplevel, §ion_idxs); -				let slug = title.names().iter().next().map(|at::NameToken(name)| at::ID(name.to_owned())); -				let mut section = e::Section::with_children(vec![title.into()]); -				section.ids_mut().extend(slug.into_iter()); -				super_level.push(section.into()); -				section_idxs.push(Some(super_level.len() - 1)); -			}, -			Ssubel(elem) => get_level(&mut toplevel, §ion_idxs).push(elem), -		}} -	} -	Ok(e::Document::with_children(toplevel)) -} - -/// Normalizes a name in terms of whitespace. Equivalent to docutils's -/// `docutils.nodes.whitespace_normalize_name`. -pub fn whitespace_normalize_name(name: &str) -> String { -	// Python's string.split() defines whitespace differently than Rust does. -	let split_iter = name.split( -		|ch: char| ch.is_whitespace() || (ch >= '\x1C' && ch <= '\x1F') -	).filter(|split| !split.is_empty()); -	let mut ret = String::new(); -	for split in split_iter { -		if !ret.is_empty() { -			ret.push(' '); -		} -		ret.push_str(split); -	} -	ret -} - - -#[cfg(test)] -mod tests { -	use crate::{ -		parser::parse, -		document_tree::{ -			elements as e, -			element_categories as c, -			HasChildren, -		} -	}; -	 -	fn ssubel_to_section(ssubel: &c::StructuralSubElement) -> &e::Section { -		match ssubel { -			c::StructuralSubElement::SubStructure(ref b) => match **b { -				c::SubStructure::Section(ref s) => s, -				ref c => panic!("Expected section, not {:?}", c), -			}, -			ref c => panic!("Expected SubStructure, not {:?}", c), -		} -	} -	 -	const SECTIONS: &str = "\ -Intro before first section title - -Level 1 -******* - -------- -Level 2 -------- - -Level 3 -======= - -L1 again -******** - -L3 again, skipping L2 -===================== -"; -	 -	#[test] -	fn convert_skipped_section() { -		let doctree = parse(SECTIONS).unwrap(); -		let lvl0 = doctree.children(); -		assert_eq!(lvl0.len(), 3, "Should be a paragraph and 2 sections: {:?}", lvl0); -		 -		assert_eq!(lvl0[0], e::Paragraph::with_children(vec![ -			"Intro before first section title".to_owned().into() -		]).into(), "The intro text should fit"); -		 -		let lvl1a = ssubel_to_section(&lvl0[1]).children(); -		assert_eq!(lvl1a.len(), 2, "The 1st lvl1 section should have (a title and) a single lvl2 section as child: {:?}", lvl1a); -		//TODO: test title lvl1a[0] -		let lvl2  = ssubel_to_section(&lvl1a[1]).children(); -		assert_eq!(lvl2.len(), 2, "The lvl2 section should have (a title and) a single lvl3 section as child: {:?}", lvl2); -		//TODO: test title lvl2[0] -		let lvl3a = ssubel_to_section(&lvl2[1]).children(); -		assert_eq!(lvl3a.len(), 1, "The 1st lvl3 section should just a title: {:?}", lvl3a); -		//TODO: test title lvl3a[0] -		 -		let lvl1b = ssubel_to_section(&lvl0[2]).children(); -		assert_eq!(lvl1b.len(), 2, "The 2nd lvl1 section should have (a title and) a single lvl2 section as child: {:?}", lvl1b); -		//TODO: test title lvl1b[0] -		let lvl3b = ssubel_to_section(&lvl1b[1]).children(); -		assert_eq!(lvl3b.len(), 1, "The 2nd lvl3 section should have just a title: {:?}", lvl3b); -		//TODO: test title lvl3b[0] -	} -} diff --git a/src/parser/conversion/block.rs b/src/parser/conversion/block.rs deleted file mode 100644 index b14c2b5..0000000 --- a/src/parser/conversion/block.rs +++ /dev/null @@ -1,202 +0,0 @@ -use failure::{Error,bail}; -use pest::iterators::Pair; - -use crate::document_tree::{ -	Element,HasChildren,ExtraAttributes, -	elements as e, -	element_categories as c, -	extra_attributes as a, -	attribute_types as at -}; - -use crate::parser::{ -	pest_rst::Rule, -	pair_ext_parse::PairExt, -}; -use super::{whitespace_normalize_name, inline::convert_inlines}; - - -#[derive(PartialEq)] -pub(super) enum TitleKind { Double(char), Single(char) } - -pub(super) enum TitleOrSsubel { -	Title(e::Title, TitleKind), -	Ssubel(c::StructuralSubElement), -} - - -pub(super) fn convert_ssubel(pair: Pair<Rule>) -> Result<Option<TitleOrSsubel>, Error> { -	use self::TitleOrSsubel::*; -	Ok(Some(match pair.as_rule() { -		Rule::title => { let (t, k) = convert_title(pair)?; Title(t, k) }, -		//TODO: subtitle, decoration, docinfo -		Rule::EOI   => return Ok(None), -		_           => Ssubel(convert_substructure(pair)?.into()), -	})) -} - - -fn convert_substructure(pair: Pair<Rule>) -> Result<c::SubStructure, Error> { -	Ok(match pair.as_rule() { -		// todo: Topic, Sidebar, Transition -		// no section here, as it’s constructed from titles -		_ => convert_body_elem(pair)?.into(), -	}) -} - - -fn convert_body_elem(pair: Pair<Rule>) -> Result<c::BodyElement, Error> { -	Ok(match pair.as_rule() { -		Rule::paragraph        => convert_paragraph(pair)?.into(), -		Rule::target           => convert_target(pair)?.into(), -		Rule::substitution_def => convert_substitution_def(pair)?.into(), -		Rule::admonition_gen   => convert_admonition_gen(pair)?.into(), -		Rule::image            => convert_image::<e::Image>(pair)?.into(), -		Rule::bullet_list      => convert_bullet_list(pair)?.into(), -		rule => unimplemented!("unhandled rule {:?}", rule), -	}) -} - - -fn convert_title(pair: Pair<Rule>) -> Result<(e::Title, TitleKind), Error> { -	let mut title: Option<String> = None; -	let mut title_inlines: Option<Vec<c::TextOrInlineElement>> = None; -	let mut adornment_char: Option<char> = None; -	// title_double or title_single. Extract kind before consuming -	let inner_pair = pair.into_inner().next().unwrap(); -	let kind = inner_pair.as_rule(); -	for p in inner_pair.into_inner() { -		match p.as_rule() { -			Rule::line => { -				title = Some(p.as_str().to_owned()); -				title_inlines = Some(convert_inlines(p)?); -			}, -			Rule::adornments => adornment_char = Some(p.as_str().chars().next().expect("Empty adornment?")), -			rule => unimplemented!("Unexpected rule in title: {:?}", rule), -		}; -	} -	// now we encountered one line of text and one of adornments -	// TODO: emit error if the adornment line is too short (has to match title length) -	let mut elem = e::Title::with_children(title_inlines.expect("No text in title")); -	if let Some(title) = title { -		//TODO: slugify properly -		let slug =  title.to_lowercase().replace("\n", "").replace(" ", "-"); -		elem.names_mut().push(at::NameToken(slug)); -	} -	let title_kind = match kind { -		Rule::title_double => TitleKind::Double(adornment_char.unwrap()), -		Rule::title_single => TitleKind::Single(adornment_char.unwrap()), -		_ => unreachable!(), -	}; -	Ok((elem, title_kind)) -} - - -fn convert_paragraph(pair: Pair<Rule>) -> Result<e::Paragraph, Error> { -	Ok(e::Paragraph::with_children(convert_inlines(pair)?)) -} - - -fn convert_target(pair: Pair<Rule>) -> Result<e::Target, Error> { -	let mut elem: e::Target = Default::default(); -	elem.extra_mut().anonymous = false; -	for p in pair.into_inner() { -		match p.as_rule() { -			Rule::target_name_uq | Rule::target_name_qu => { -				elem.ids_mut().push(p.as_str().into()); -				elem.names_mut().push(p.as_str().into()); -			}, -			// TODO: also handle non-urls -			Rule::link_target => elem.extra_mut().refuri = Some(p.parse()?), -			rule => panic!("Unexpected rule in target: {:?}", rule), -		} -	} -	Ok(elem) -} - -fn convert_substitution_def(pair: Pair<Rule>) -> Result<e::SubstitutionDefinition, Error> { -	let mut pairs = pair.into_inner(); -	let name = whitespace_normalize_name(pairs.next().unwrap().as_str());  // Rule::substitution_name -	let inner_pair = pairs.next().unwrap(); -	let inner: Vec<c::TextOrInlineElement> = match inner_pair.as_rule() { -		Rule::replace => convert_replace(inner_pair)?, -		Rule::image   => vec![convert_image::<e::ImageInline>(inner_pair)?.into()], -		rule => panic!("Unknown substitution rule {:?}", rule), -	}; -	let mut subst_def = e::SubstitutionDefinition::with_children(inner); -	subst_def.names_mut().push(at::NameToken(name)); -	Ok(subst_def) -} - -fn convert_replace(pair: Pair<Rule>) -> Result<Vec<c::TextOrInlineElement>, Error> { -	let mut pairs = pair.into_inner(); -	let paragraph = pairs.next().unwrap(); -	convert_inlines(paragraph) -}  - -fn convert_image<I>(pair: Pair<Rule>) -> Result<I, Error> where I: Element + ExtraAttributes<a::Image> { -	let mut pairs = pair.into_inner(); -	let mut image = I::with_extra(a::Image::new( -		pairs.next().unwrap().as_str().trim().parse()?,  // line -	)); -	for opt in pairs { -		let mut opt_iter = opt.into_inner(); -		let opt_name = opt_iter.next().unwrap(); -		let opt_val = opt_iter.next().unwrap(); -		match opt_name.as_str() { -			"class"  => image.classes_mut().push(opt_val.as_str().to_owned()), -			"name"   => image.names_mut().push(opt_val.as_str().into()), -			"alt"    => image.extra_mut().alt    = Some(opt_val.as_str().to_owned()), -			"height" => image.extra_mut().height = Some(opt_val.parse()?), -			"width"  => image.extra_mut().width  = Some(opt_val.parse()?), -			"scale"  => image.extra_mut().scale  = Some(parse_scale(&opt_val)?), -			"align"  => image.extra_mut().align  = Some(opt_val.parse()?), -			"target" => image.extra_mut().target = Some(opt_val.parse()?), -			name => bail!("Unknown Image option {}", name), -		} -	} -	Ok(image) -} - -fn parse_scale(pair: &Pair<Rule>) -> Result<u8, Error> { -	let input = if pair.as_str().chars().rev().next() == Some('%') { &pair.as_str()[..pair.as_str().len()-1] } else { pair.as_str() }; -	use pest::error::{Error,ErrorVariant}; -	Ok(input.parse().map_err(|e: std::num::ParseIntError| { -		let var: ErrorVariant<Rule> = ErrorVariant::CustomError { message: e.to_string() }; -		Error::new_from_span(var, pair.as_span()) -	})?) -} - -fn convert_admonition_gen(pair: Pair<Rule>) -> Result<c::BodyElement, Error> { -	let mut iter = pair.into_inner(); -	let typ = iter.next().unwrap().as_str(); -	// TODO: in reality it contains body elements. -	let children: Vec<c::BodyElement> = iter.map(|p| e::Paragraph::with_children(vec![p.as_str().into()]).into()).collect(); -	Ok(match typ { -		"attention" => e::Attention::with_children(children).into(), -		"hint"      =>      e::Hint::with_children(children).into(), -		"note"      =>      e::Note::with_children(children).into(), -		"caution"   =>   e::Caution::with_children(children).into(), -		"danger"    =>    e::Danger::with_children(children).into(), -		"error"     =>     e::Error::with_children(children).into(), -		"important" => e::Important::with_children(children).into(), -		"tip"       =>       e::Tip::with_children(children).into(), -		"warning"   =>   e::Warning::with_children(children).into(), -		typ         => panic!("Unknown admontion type {}!", typ), -	}) -} - -fn convert_bullet_list(pair: Pair<Rule>) -> Result<e::BulletList, Error> { -	Ok(e::BulletList::with_children(pair.into_inner().map(convert_bullet_item).collect::<Result<_, _>>()?)) -} - -fn convert_bullet_item(pair: Pair<Rule>) -> Result<e::ListItem, Error> { -	let mut iter = pair.into_inner(); -	let mut children: Vec<c::BodyElement> = vec![ -		convert_paragraph(iter.next().unwrap())?.into() -	]; -	for p in iter { -		children.push(convert_body_elem(p)?); -	} -	Ok(e::ListItem::with_children(children)) -} diff --git a/src/parser/conversion/inline.rs b/src/parser/conversion/inline.rs deleted file mode 100644 index b2fffa5..0000000 --- a/src/parser/conversion/inline.rs +++ /dev/null @@ -1,161 +0,0 @@ -use failure::Error; -use pest::iterators::Pair; - -use crate::document_tree::{ -	HasChildren, -	elements as e, -	element_categories as c, -	extra_attributes as a, -	attribute_types as at, -}; - -use crate::parser::{ -	pest_rst::Rule, -//    pair_ext_parse::PairExt, -}; - -use crate::url::Url; -use super::whitespace_normalize_name; - - -pub fn convert_inline(pair: Pair<Rule>) -> Result<c::TextOrInlineElement, Error> { -	Ok(match pair.as_rule() { -		Rule::str | Rule::str_nested => pair.as_str().into(), -		Rule::ws_newline        => " ".to_owned().into(), -		Rule::reference         => convert_reference(pair)?, -		Rule::substitution_name => convert_substitution_ref(pair)?.into(), -		Rule::emph              => e::Emphasis::with_children(convert_inlines(pair)?).into(), -		Rule::strong            => e::Strong::with_children(convert_inlines(pair)?).into(), -		Rule::literal           => e::Literal::with_children(convert_inlines(pair)?).into(), -		rule => unimplemented!("unknown rule {:?}", rule), -	}) -} - -pub fn convert_inlines(pair: Pair<Rule>) -> Result<Vec<c::TextOrInlineElement>, Error> { -	pair.into_inner().map(convert_inline).collect() -} - -fn convert_reference(pair: Pair<Rule>) -> Result<c::TextOrInlineElement, Error> { -	let name; -	let refuri; -	let refid; -	let mut refname = vec![]; -	let mut children: Vec<c::TextOrInlineElement> = vec![]; -	let concrete = pair.into_inner().next().unwrap(); -	match concrete.as_rule() { -		Rule::reference_target => { -			let rt_inner = concrete.into_inner().next().unwrap(); // reference_target_uq or target_name_qu -			match rt_inner.as_rule() { -				Rule::reference_target_uq => { -					refid  = None; -					name   = Some(rt_inner.as_str().into()); -					refuri = None; -					refname.push(rt_inner.as_str().into()); -					children.push(rt_inner.as_str().into()); -				}, -				Rule::reference_target_qu => { -					let (text, reference) = { -						let mut text = None; -						let mut reference = None; -						for inner in rt_inner.clone().into_inner() { -							match inner.as_rule() { -								Rule::reference_text => text = Some(inner), -								Rule::reference_bracketed => reference = Some(inner), -								_ => unreachable!() -							} -						} -						(text, reference) -					}; -					let trimmed_text = match (&text, &reference) { -						(Some(text), None) => text.as_str(), -						(_, Some(reference)) => { -							text -								.map(|text| text.as_str().trim_end_matches(|ch| " \n\r".contains(ch))) -								.filter(|text| !text.is_empty()) -								.unwrap_or_else(|| reference.clone().into_inner().next().unwrap().as_str()) -						} -						(None, None) => unreachable!() -					}; -					refid = None; -					name = Some(trimmed_text.into()); -					refuri = if let Some(reference) = reference { -						let inner = reference.into_inner().next().unwrap(); -						match inner.as_rule() { -							// The URL rules in our parser accept a narrow superset of -							// valid URLs, so we need to handle false positives. -							Rule::url => if let Ok(target) = Url::parse_absolute(inner.as_str()) { -								Some(target) -							} else if inner.as_str().ends_with('_') { -								// like target_name_qu (minus the final underscore) -								let full_str = inner.as_str(); -								refname.push(full_str[0..full_str.len() - 1].into()); -								None -							} else { -								// like relative_reference -								Some(Url::parse_relative(inner.as_str())?) -							}, -							Rule::target_name_qu => { -								refname.push(inner.as_str().into()); -								None -							}, -							Rule::relative_reference => { -								Some(Url::parse_relative(inner.as_str())?) -							}, -							_ => unreachable!() -						} -					} else { -						refname.push(trimmed_text.into()); -						None -					}; -					children.push(trimmed_text.into()); -				}, -				_ => unreachable!() -			} -		}, -		Rule::reference_explicit => unimplemented!("explicit reference"), -		Rule::reference_auto => { -			let rt_inner = concrete.into_inner().next().unwrap(); -			match rt_inner.as_rule() { -				Rule::url_auto => match Url::parse_absolute(rt_inner.as_str()) { -					Ok(target) => { -						refuri = Some(target); -						name   = None; -						refid  = None; -						children.push(rt_inner.as_str().into()); -					}, -					// if our parser got a URL wrong, return it as a string -					Err(_) => return Ok(rt_inner.as_str().into()) -				}, -				Rule::email => { -					let mailto_url = String::from("mailto:") + rt_inner.as_str(); -					match Url::parse_absolute(&mailto_url) { -						Ok(target) => { -							refuri = Some(target); -							name   = None; -							refid  = None; -							children.push(rt_inner.as_str().into()); -						}, -						// if our parser got a URL wrong, return it as a string -						Err(_) => return Ok(rt_inner.as_str().into()) -					} -				}, -				_ => unreachable!() -			} -		}, -		_ => unreachable!(), -	}; -	Ok(e::Reference::new( -		Default::default(), -		a::Reference { name, refuri, refid, refname }, -		children -	).into()) -} - -fn convert_substitution_ref(pair: Pair<Rule>) -> Result<e::SubstitutionReference, Error> { -	let name = whitespace_normalize_name(pair.as_str()); -	Ok(a::ExtraAttributes::with_extra( -		a::SubstitutionReference { -			refname: vec![at::NameToken(name)] -		} -	)) -} diff --git a/src/parser/pair_ext_parse.rs b/src/parser/pair_ext_parse.rs deleted file mode 100644 index a04b3dd..0000000 --- a/src/parser/pair_ext_parse.rs +++ /dev/null @@ -1,21 +0,0 @@ -use std::str::FromStr; - -use pest::Span; -use pest::iterators::Pair; -use pest::error::{Error,ErrorVariant}; - - -pub trait PairExt<R> where R: pest::RuleType { -	fn parse<T, E>(&self) -> Result<T, Error<R>> where T: FromStr<Err = E>, E: ToString; -} - -impl<'l, R> PairExt<R> for Pair<'l, R> where R: pest::RuleType { -	fn parse<T, E>(&self) -> Result<T, Error<R>> where T: FromStr<Err = E>, E: ToString { -		self.as_str().parse().map_err(|e| to_parse_error(self.as_span(), &e)) -	} -} - -pub(crate) fn to_parse_error<E, R>(span: Span, e: &E) -> Error<R> where E: ToString, R: pest::RuleType { -	let var: ErrorVariant<R> = ErrorVariant::CustomError { message: e.to_string() }; -	Error::new_from_span(var, span) -} diff --git a/src/parser/pest_rst.rs b/src/parser/pest_rst.rs deleted file mode 100644 index 74199a8..0000000 --- a/src/parser/pest_rst.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![allow(clippy::redundant_closure)] - -use pest_derive::Parser; - -#[derive(Parser)] -#[grammar = "rst.pest"] -pub struct RstParser; diff --git a/src/parser/simplify.rs b/src/parser/simplify.rs deleted file mode 100644 index cc169ee..0000000 --- a/src/parser/simplify.rs +++ /dev/null @@ -1,662 +0,0 @@ -/* -http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#hyperlink-targets - -Links can have internal or external targets. -In the source, targets look like: - -	.. targetname1: -	.. targetname2: - -	some paragraph or list item or so - -or: - -    .. targetname1: -	.. targetname2: https://link - -There’s also anonymous links and targets without names. - -TODO: continue documenting how it’s done via https://repo.or.cz/docutils.git/blob/HEAD:/docutils/docutils/transforms/references.py -*/ - -use std::collections::HashMap; - -use crate::url::Url; -use crate::document_tree::{ -	Document, -	HasChildren, -	attribute_types::NameToken, -	elements::{self as e, Element}, -	element_categories as c, -	extra_attributes::ExtraAttributes, -}; - - -#[derive(Debug)] -enum NamedTargetType { -	NumberedFootnote(usize), -	LabeledFootnote(usize), -	Citation, -	InternalLink, -	ExternalLink(Url), -	IndirectLink(NameToken), -	SectionTitle, -} -impl NamedTargetType { -	fn is_implicit_target(&self) -> bool { -		match self { -			NamedTargetType::SectionTitle => true, -			_ => false, -		} -	} -} - -#[derive(Clone, Debug)] -struct Substitution { -	content: Vec<c::TextOrInlineElement>, -	/// If true and the sibling before the reference is a text node, -	/// the text node gets right-trimmed.  -	ltrim: bool, -	/// Same as `ltrim` with the sibling after the reference. -	rtrim: bool, -} - -#[derive(Default, Debug)] -struct TargetsCollected { -	named_targets: HashMap<NameToken, NamedTargetType>, -	substitutions: HashMap<NameToken, Substitution>, -	normalized_substitutions: HashMap<String, Substitution>, -} -impl TargetsCollected { -	fn target_url<'t>(self: &'t TargetsCollected, refname: &[NameToken]) -> Option<&'t Url> { -		// TODO: Check if the target would expand circularly -		if refname.len() != 1 { -			panic!("Expected exactly one name in a reference."); -		} -		let name = refname[0].clone(); -		match self.named_targets.get(&name)? { -			NamedTargetType::ExternalLink(url) => Some(url), -			_ => unimplemented!(), -		} -	} -	 -	fn substitution<'t>(self: &'t TargetsCollected, refname: &[NameToken]) -> Option<&'t Substitution> { -		// TODO: Check if the substitution would expand circularly -		if refname.len() != 1 { -			panic!("Expected exactly one name in a substitution reference."); -		} -		let name = refname[0].clone(); -		self.substitutions.get(&name).or_else(|| { -			self.normalized_substitutions.get(&name.0.to_lowercase()) -		}) -	} -} - -trait ResolvableRefs { -	fn populate_targets(&self, refs: &mut TargetsCollected); -	fn resolve_refs(self, refs: &TargetsCollected) -> Vec<Self> where Self: Sized; -} - -pub fn resolve_references(mut doc: Document) -> Document { -	let mut references: TargetsCollected = Default::default(); -	for c in doc.children() { -		c.populate_targets(&mut references); -	} -	let new: Vec<_> = doc.children_mut().drain(..).flat_map(|c| c.resolve_refs(&references)).collect(); -	Document::with_children(new) -} - -fn sub_pop<P, C>(parent: &P, refs: &mut TargetsCollected) where P: HasChildren<C>, C: ResolvableRefs { -	for c in parent.children() { -		c.populate_targets(refs); -	} -} - -fn sub_res<P, C>(mut parent: P, refs: &TargetsCollected) -> P where P: e::Element + HasChildren<C>, C: ResolvableRefs { -	let new: Vec<_> = parent.children_mut().drain(..).flat_map(|c| c.resolve_refs(refs)).collect(); -	parent.children_mut().extend(new); -	parent -} - -fn sub_sub_pop<P, C1, C2>(parent: &P, refs: &mut TargetsCollected) where P: HasChildren<C1>, C1: HasChildren<C2>, C2: ResolvableRefs { -	for c in parent.children() { -		sub_pop(c, refs); -	} -} - -fn sub_sub_res<P, C1, C2>(mut parent: P, refs: &TargetsCollected) -> P where P: e::Element + HasChildren<C1>, C1: e::Element + HasChildren<C2>, C2: ResolvableRefs { -	let new: Vec<_> = parent.children_mut().drain(..).map(|c| sub_res(c, refs)).collect(); -	parent.children_mut().extend(new); -	parent -} - -impl ResolvableRefs for c::StructuralSubElement { -	fn populate_targets(&self, refs: &mut TargetsCollected) { -		use c::StructuralSubElement::*; -		match self { -			Title(e)        => sub_pop(&**e, refs), -			Subtitle(e)     => sub_pop(&**e, refs), -			Decoration(e)   => sub_pop(&**e, refs), -			Docinfo(e)      => sub_pop(&**e, refs), -			SubStructure(e) => e.populate_targets(refs), -		} -	} -	fn resolve_refs(self, refs: &TargetsCollected) -> Vec<Self> { -		use c::StructuralSubElement::*; -		vec![match self { -			Title(e)        => sub_res(*e, refs).into(), -			Subtitle(e)     => sub_res(*e, refs).into(), -			Decoration(e)   => sub_res(*e, refs).into(), -			Docinfo(e)      => sub_res(*e, refs).into(), -			SubStructure(e) => return e.resolve_refs(refs).drain(..).map(Into::into).collect(), -		}] -	} -} - -impl ResolvableRefs for c::SubStructure { -	fn populate_targets(&self, refs: &mut TargetsCollected) { -		use c::SubStructure::*; -		match self { -			Topic(e) => sub_pop(&**e, refs), -			Sidebar(e) => sub_pop(&**e, refs), -			Transition(_) => {}, -			Section(e) => sub_pop(&**e, refs), -			BodyElement(e) => e.populate_targets(refs), -		} -	} -	fn resolve_refs(self, refs: &TargetsCollected) -> Vec<Self> { -		use c::SubStructure::*; -		vec![match self { -			Topic(e) => sub_res(*e, refs).into(), -			Sidebar(e) => sub_res(*e, refs).into(), -			Transition(e) => Transition(e), -			Section(e) => sub_res(*e, refs).into(), -			BodyElement(e) => return e.resolve_refs(refs).drain(..).map(Into::into).collect(), -		}] -	} -} - -impl ResolvableRefs for c::BodyElement { -	fn populate_targets(&self, refs: &mut TargetsCollected) { -		use c::BodyElement::*; -		match self { -			Paragraph(e) => sub_pop(&**e, refs), -			LiteralBlock(e) => sub_pop(&**e, refs), -			DoctestBlock(e) => sub_pop(&**e, refs), -			MathBlock(_) => {}, -			Rubric(e) => sub_pop(&**e, refs), -			SubstitutionDefinition(e) => { -				let subst = Substitution { -					content: e.children().clone(), -					ltrim: e.extra().ltrim, -					rtrim: e.extra().rtrim -				}; -				for name in e.names() { -					if refs.substitutions.contains_key(name) { -						// TODO: Duplicate substitution name (level 3 system message). -					} -					// Intentionally overriding any previous values. -					refs.substitutions.insert(name.clone(), subst.clone()); -					refs.normalized_substitutions.insert(name.0.to_lowercase(), subst.clone()); -				} -			}, -			Comment(_) => {}, -			Pending(_) => { -				unimplemented!(); -			}, -			Target(e) => { -				if let Some(uri) = &e.extra().refuri { -					for name in e.names() { -						refs.named_targets.insert(name.clone(), NamedTargetType::ExternalLink(uri.clone())); -					} -				} -				// TODO: as is, people can only refer to the target directly containing the URL. -				// add refid and refnames to some HashMap and follow those later. -			}, -			Raw(_) => {}, -			Image(_) => {}, -			Compound(e) => sub_pop(&**e, refs), -			Container(e) => sub_pop(&**e, refs), -			BulletList(e) => sub_sub_pop(&**e, refs), -			EnumeratedList(e) => sub_sub_pop(&**e, refs), -			DefinitionList(e) => sub_sub_pop(&**e, refs), -			FieldList(e) => sub_sub_pop(&**e, refs), -			OptionList(e) => sub_sub_pop(&**e, refs), -			LineBlock(e) => sub_pop(&**e, refs), -			BlockQuote(e) => sub_pop(&**e, refs), -			Admonition(e) => sub_pop(&**e, refs), -			Attention(e) => sub_pop(&**e, refs), -			Hint(e) => sub_pop(&**e, refs), -			Note(e) => sub_pop(&**e, refs), -			Caution(e) => sub_pop(&**e, refs), -			Danger(e) => sub_pop(&**e, refs), -			Error(e) => sub_pop(&**e, refs), -			Important(e) => sub_pop(&**e, refs), -			Tip(e) => sub_pop(&**e, refs), -			Warning(e) => sub_pop(&**e, refs), -			Footnote(e) => sub_pop(&**e, refs), -			Citation(e) => sub_pop(&**e, refs), -			SystemMessage(e) => sub_pop(&**e, refs), -			Figure(e) => sub_pop(&**e, refs), -			Table(e) => sub_pop(&**e, refs) -		} -	} -	fn resolve_refs(self, refs: &TargetsCollected) -> Vec<Self> { -		use c::BodyElement::*; -		vec![match self { -			Paragraph(e) => sub_res(*e, refs).into(), -			LiteralBlock(e) => sub_res(*e, refs).into(), -			DoctestBlock(e) => sub_res(*e, refs).into(), -			MathBlock(e) => MathBlock(e), -			Rubric(e) => sub_res(*e, refs).into(), -			SubstitutionDefinition(_) => return vec![], -			Comment(e) => Comment(e), -			Pending(e) => Pending(e), -			Target(e) => Target(e), -			Raw(e) => Raw(e), -			Image(e) => Image(e), -			Compound(e) => sub_res(*e, refs).into(), -			Container(e) => sub_res(*e, refs).into(), -			BulletList(e) => sub_sub_res(*e, refs).into(), -			EnumeratedList(e) => sub_sub_res(*e, refs).into(), -			DefinitionList(e) => sub_sub_res(*e, refs).into(), -			FieldList(e) => sub_sub_res(*e, refs).into(), -			OptionList(e) => sub_sub_res(*e, refs).into(), -			LineBlock(e) => sub_res(*e, refs).into(), -			BlockQuote(e) => sub_res(*e, refs).into(), -			Admonition(e) => sub_res(*e, refs).into(), -			Attention(e) => sub_res(*e, refs).into(), -			Hint(e) => sub_res(*e, refs).into(), -			Note(e) => sub_res(*e, refs).into(), -			Caution(e) => sub_res(*e, refs).into(), -			Danger(e) => sub_res(*e, refs).into(), -			Error(e) => sub_res(*e, refs).into(), -			Important(e) => sub_res(*e, refs).into(), -			Tip(e) => sub_res(*e, refs).into(), -			Warning(e) => sub_res(*e, refs).into(), -			Footnote(e) => sub_res(*e, refs).into(), -			Citation(e) => sub_res(*e, refs).into(), -			SystemMessage(e) => sub_res(*e, refs).into(), -			Figure(e) => sub_res(*e, refs).into(), -			Table(e) => sub_res(*e, refs).into() -		}] -	} -} - -impl ResolvableRefs for c::BibliographicElement { -	fn populate_targets(&self, refs: &mut TargetsCollected) { -		use c::BibliographicElement::*; -		match self { -			Author(e) => sub_pop(&**e, refs), -			Authors(e) => sub_pop(&**e, refs), -			Organization(e) => sub_pop(&**e, refs), -			Address(e) => sub_pop(&**e, refs), -			Contact(e) => sub_pop(&**e, refs), -			Version(e) => sub_pop(&**e, refs), -			Revision(e) => sub_pop(&**e, refs), -			Status(e) => sub_pop(&**e, refs), -			Date(e) => sub_pop(&**e, refs), -			Copyright(e) => sub_pop(&**e, refs), -			Field(e) => sub_pop(&**e, refs), -		} -	} -	fn resolve_refs(self, refs: &TargetsCollected) -> Vec<Self> { -		use c::BibliographicElement::*; -		vec![match self { -			Author(e) => sub_res(*e, refs).into(), -			Authors(e) => sub_res(*e, refs).into(), -			Organization(e) => sub_res(*e, refs).into(), -			Address(e) => sub_res(*e, refs).into(), -			Contact(e) => sub_res(*e, refs).into(), -			Version(e) => sub_res(*e, refs).into(), -			Revision(e) => sub_res(*e, refs).into(), -			Status(e) => sub_res(*e, refs).into(), -			Date(e) => sub_res(*e, refs).into(), -			Copyright(e) => sub_res(*e, refs).into(), -			Field(e) => sub_res(*e, refs).into(), -		}] -	} -} - -impl ResolvableRefs for c::TextOrInlineElement { -	fn populate_targets(&self, refs: &mut TargetsCollected) { -		use c::TextOrInlineElement::*; -		match self { -			String(_) => {}, -			Emphasis(e) => sub_pop(&**e, refs), -			Strong(e) => sub_pop(&**e, refs), -			Literal(e) => sub_pop(&**e, refs), -			Reference(e) => sub_pop(&**e, refs), -			FootnoteReference(e) => sub_pop(&**e, refs), -			CitationReference(e) => sub_pop(&**e, refs), -			SubstitutionReference(e) => sub_pop(&**e, refs), -			TitleReference(e) => sub_pop(&**e, refs), -			Abbreviation(e) => sub_pop(&**e, refs), -			Acronym(e) => sub_pop(&**e, refs), -			Superscript(e) => sub_pop(&**e, refs), -			Subscript(e) => sub_pop(&**e, refs), -			Inline(e) => sub_pop(&**e, refs), -			Problematic(e) => sub_pop(&**e, refs), -			Generated(e) => sub_pop(&**e, refs), -			Math(_) => {}, -			TargetInline(_) => { -				unimplemented!(); -			}, -			RawInline(_) => {}, -			ImageInline(_) => {} -		} -	} -	fn resolve_refs(self, refs: &TargetsCollected) -> Vec<Self> { -		use c::TextOrInlineElement::*; -		vec![match self { -			String(e) => String(e), -			Emphasis(e) => sub_res(*e, refs).into(), -			Strong(e) => sub_res(*e, refs).into(), -			Literal(e) => sub_res(*e, refs).into(), -			Reference(mut e) => { -				if e.extra().refuri.is_none() { -					if let Some(uri) = refs.target_url(&e.extra().refname) { -						e.extra_mut().refuri = Some(uri.clone()); -					} -				} -				(*e).into() -			}, -			FootnoteReference(e) => sub_res(*e, refs).into(), -			CitationReference(e) => sub_res(*e, refs).into(), -			SubstitutionReference(e) => match refs.substitution(&e.extra().refname) { -				Some(Substitution {content, ltrim, rtrim}) => { -					// (level 3 system message). -					// TODO: ltrim and rtrim. -					if *ltrim || *rtrim { -						dbg!(content, ltrim, rtrim); -					} -					return content.clone() -				}, -				None => { -					// Undefined substitution name (level 3 system message). -					// TODO: This replaces the reference by a Problematic node. -					// The corresponding SystemMessage node should go in a generated -					// section with class "system-messages" at the end of the document. -					use crate::document_tree::Problematic; -					let mut replacement: Box<Problematic> = Box::new(Default::default()); -					replacement.children_mut().push( -						c::TextOrInlineElement::String(Box::new(format!("|{}|", e.extra().refname[0].0))) -					); -					// TODO: Create an ID for replacement for the system_message to reference. -					// TODO: replacement.refid pointing to the system_message. -					Problematic(replacement) -				} -			}, -			TitleReference(e) => sub_res(*e, refs).into(), -			Abbreviation(e) => sub_res(*e, refs).into(), -			Acronym(e) => sub_res(*e, refs).into(), -			Superscript(e) => sub_res(*e, refs).into(), -			Subscript(e) => sub_res(*e, refs).into(), -			Inline(e) => sub_res(*e, refs).into(), -			Problematic(e) => sub_res(*e, refs).into(), -			Generated(e) => sub_res(*e, refs).into(), -			Math(e) => Math(e), -			TargetInline(e) => TargetInline(e), -			RawInline(e) => RawInline(e), -			ImageInline(e) => ImageInline(e) -		}] -	} -} - -impl ResolvableRefs for c::AuthorInfo { -	fn populate_targets(&self, refs: &mut TargetsCollected) { -		use c::AuthorInfo::*; -		match self { -			Author(e) => sub_pop(&**e, refs), -			Organization(e) => sub_pop(&**e, refs), -			Address(e) => sub_pop(&**e, refs), -			Contact(e) => sub_pop(&**e, refs), -		} -	} -	fn resolve_refs(self, refs: &TargetsCollected) -> Vec<Self> { -		use c::AuthorInfo::*; -		vec![match self { -			Author(e) => sub_res(*e, refs).into(), -			Organization(e) => sub_res(*e, refs).into(), -			Address(e) => sub_res(*e, refs).into(), -			Contact(e) => sub_res(*e, refs).into(), -		}] -	} -} - -impl ResolvableRefs for c::DecorationElement { -	fn populate_targets(&self, refs: &mut TargetsCollected) { -		use c::DecorationElement::*; -		match self { -			Header(e) => sub_pop(&**e, refs), -			Footer(e) => sub_pop(&**e, refs), -		} -	} -	fn resolve_refs(self, refs: &TargetsCollected) -> Vec<Self> { -		use c::DecorationElement::*; -		vec![match self { -			Header(e) => sub_res(*e, refs).into(), -			Footer(e) => sub_res(*e, refs).into(), -		}] -	} -} - -impl ResolvableRefs for c::SubTopic { -	fn populate_targets(&self, refs: &mut TargetsCollected) { -		use c::SubTopic::*; -		match self { -			Title(e) => sub_pop(&**e, refs), -			BodyElement(e) => e.populate_targets(refs), -		} -	} -	fn resolve_refs(self, refs: &TargetsCollected) -> Vec<Self> { -		use c::SubTopic::*; -		match self { -			Title(e) => vec![sub_res(*e, refs).into()], -			BodyElement(e) => e.resolve_refs(refs).drain(..).map(Into::into).collect(), -		} -	} -} - -impl ResolvableRefs for c::SubSidebar { -	fn populate_targets(&self, refs: &mut TargetsCollected) { -		use c::SubSidebar::*; -		match self { -			Topic(e) => sub_pop(&**e, refs), -			Title(e) => sub_pop(&**e, refs), -			Subtitle(e) => sub_pop(&**e, refs), -			BodyElement(e) => e.populate_targets(refs), -		} -	} -	fn resolve_refs(self, refs: &TargetsCollected) -> Vec<Self> { -		use c::SubSidebar::*; -		vec![match self { -			Topic(e) => sub_res(*e, refs).into(), -			Title(e) => sub_res(*e, refs).into(), -			Subtitle(e) => sub_res(*e, refs).into(), -			BodyElement(e) => return e.resolve_refs(refs).drain(..).map(Into::into).collect(), -		}] -	} -} - -impl ResolvableRefs for c::SubDLItem { -	fn populate_targets(&self, refs: &mut TargetsCollected) { -		use c::SubDLItem::*; -		match self { -			Term(e) => sub_pop(&**e, refs), -			Classifier(e) => sub_pop(&**e, refs), -			Definition(e) => sub_pop(&**e, refs), -		} -	} -	fn resolve_refs(self, refs: &TargetsCollected) -> Vec<Self> { -		use c::SubDLItem::*; -		vec![match self { -			Term(e) => sub_res(*e, refs).into(), -			Classifier(e) => sub_res(*e, refs).into(), -			Definition(e) => sub_res(*e, refs).into(), -		}] -	} -} - -impl ResolvableRefs for c::SubField { -	fn populate_targets(&self, refs: &mut TargetsCollected) { -		use c::SubField::*; -		match self { -			FieldName(e) => sub_pop(&**e, refs), -			FieldBody(e) => sub_pop(&**e, refs), -		} -	} -	fn resolve_refs(self, refs: &TargetsCollected) -> Vec<Self> { -		use c::SubField::*; -		vec![match self { -			FieldName(e) => sub_res(*e, refs).into(), -			FieldBody(e) => sub_res(*e, refs).into(), -		}] -	} -} - -impl ResolvableRefs for c::SubOptionListItem { -	fn populate_targets(&self, refs: &mut TargetsCollected) { -		use c::SubOptionListItem::*; -		match self { -			OptionGroup(e) => sub_sub_pop(&**e, refs), -			Description(e) => sub_pop(&**e, refs), -		} -	} -	fn resolve_refs(self, refs: &TargetsCollected) -> Vec<Self> { -		use c::SubOptionListItem::*; -		vec![match self { -			OptionGroup(e) => sub_sub_res(*e, refs).into(), -			Description(e) => sub_res(*e, refs).into(), -		}] -	} -} - -impl ResolvableRefs for c::SubOption { -	fn populate_targets(&self, _: &mut TargetsCollected) {} -	fn resolve_refs(self, _: &TargetsCollected) -> Vec<Self> { vec![self] } -} - -impl ResolvableRefs for c::SubLineBlock { -	fn populate_targets(&self, refs: &mut TargetsCollected) { -		use c::SubLineBlock::*; -		match self { -			LineBlock(e) => sub_pop(&**e, refs), -			Line(e) => sub_pop(&**e, refs), -		} -	} -	fn resolve_refs(self, refs: &TargetsCollected) -> Vec<Self> { -		use c::SubLineBlock::*; -		vec![match self { -			LineBlock(e) => sub_res(*e, refs).into(), -			Line(e) => sub_res(*e, refs).into(), -		}] -	} -} - -impl ResolvableRefs for c::SubBlockQuote { -	fn populate_targets(&self, refs: &mut TargetsCollected) { -		use c::SubBlockQuote::*; -		match self { -			Attribution(e) => sub_pop(&**e, refs), -			BodyElement(e) => e.populate_targets(refs), -		} -	} -	fn resolve_refs(self, refs: &TargetsCollected) -> Vec<Self> { -		use c::SubBlockQuote::*; -		match self { -			Attribution(e) => vec![sub_res(*e, refs).into()], -			BodyElement(e) => e.resolve_refs(refs).drain(..).map(Into::into).collect(), -		} -	} -} - -impl ResolvableRefs for c::SubFootnote { -	fn populate_targets(&self, refs: &mut TargetsCollected) { -		use c::SubFootnote::*; -		match self { -			Label(e) => sub_pop(&**e, refs), -			BodyElement(e) => e.populate_targets(refs), -		} -	} -	fn resolve_refs(self, refs: &TargetsCollected) -> Vec<Self> { -		use c::SubFootnote::*; -		match self { -			Label(e) => vec![sub_res(*e, refs).into()], -			BodyElement(e) => e.resolve_refs(refs).drain(..).map(Into::into).collect(), -		} -	} -} - -impl ResolvableRefs for c::SubFigure { -	fn populate_targets(&self, refs: &mut TargetsCollected) { -		use c::SubFigure::*; -		match self { -			Caption(e) => sub_pop(&**e, refs), -			Legend(e) => sub_pop(&**e, refs), -			BodyElement(e) => e.populate_targets(refs), -		} -	} -	fn resolve_refs(self, refs: &TargetsCollected) -> Vec<Self> { -		use c::SubFigure::*; -		vec![match self { -			Caption(e) => sub_res(*e, refs).into(), -			Legend(e) => sub_res(*e, refs).into(), -			BodyElement(e) => return e.resolve_refs(refs).drain(..).map(Into::into).collect(), -		}] -	} -} - -impl ResolvableRefs for c::SubTable { -	fn populate_targets(&self, refs: &mut TargetsCollected) { -		use c::SubTable::*; -		match self { -			Title(e) => sub_pop(&**e, refs), -			TableGroup(e) => sub_pop(&**e, refs), -		} -	} -	fn resolve_refs(self, refs: &TargetsCollected) -> Vec<Self> { -		use c::SubTable::*; -		vec![match self { -			Title(e) => sub_res(*e, refs).into(), -			TableGroup(e) => sub_res(*e, refs).into(), -		}] -	} -} - -impl ResolvableRefs for c::SubTableGroup { -	fn populate_targets(&self, refs: &mut TargetsCollected) { -		use c::SubTableGroup::*; -		match self { -			TableColspec(_) => { -				unimplemented!(); -			}, -			TableHead(e) => { -				for c in e.children() { -					sub_sub_pop(c, refs); -				} -			}, -			TableBody(e) => { -				for c in e.children() { -					sub_sub_pop(c, refs); -				} -			}, -		} -	} -	fn resolve_refs(self, refs: &TargetsCollected) -> Vec<Self> { -		use c::SubTableGroup::*; -		vec![match self { -			TableColspec(e) => TableColspec(e), -			TableHead(mut e) => { -				let new: Vec<_> = e.children_mut().drain(..).map(|c| sub_sub_res(c, refs)).collect(); -				e.children_mut().extend(new); -				TableHead(e) -			}, -			TableBody(mut e) => { -				let new: Vec<_> = e.children_mut().drain(..).map(|c| sub_sub_res(c, refs)).collect(); -				e.children_mut().extend(new); -				TableBody(e) -			}, -		}] -	} -} diff --git a/src/parser/tests.rs b/src/parser/tests.rs deleted file mode 100644 index a034c0e..0000000 --- a/src/parser/tests.rs +++ /dev/null @@ -1,241 +0,0 @@ -use pest::consumes_to; -use pest::parses_to; -use super::pest_rst::{RstParser, Rule}; - -#[test] -fn plain() { -	parses_to! { -		parser: RstParser, -		input: "line\n", -		rule: Rule::paragraph, -		tokens: [ -			paragraph(0, 4, [ -				str(0, 4) -			]) -		] -	}; -} - -#[test] -fn emph_only() { -	parses_to! { -		parser: RstParser, -		input: "*emphasis*", -		rule: Rule::emph_outer, -		tokens: [ -			emph(1, 9, [str_nested(1, 9)]) -		] -	}; -} - -#[test] -fn emph() { -	parses_to! { -		parser: RstParser, -		input: "line *with markup*\n", -		rule: Rule::paragraph, -		tokens: [ -			paragraph(0, 18, [ -				str(0, 5), -				emph(6, 17, [str_nested(6, 17)]), -			]) -		] -	}; -} - -#[test] -fn title() { -	parses_to! { -		parser: RstParser, -		input: "\ -Title -===== -", -		rule: Rule::title, -		tokens: [ -			title(0, 12, [ title_single(0, 12, [ -				line(0, 6, [ str(0, 5) ]), -				adornments(6, 11), -			]) ]) -		] -	}; -} - -#[test] -fn title_overline() { -	parses_to! { -		parser: RstParser, -		input: "\ ------ -Title ------ -", -		rule: Rule::title, -		tokens: [ -			title(0, 17, [ title_double(0, 17, [ -				adornments(0, 5), -				line(6, 12, [ str(6, 11) ]), -			]) ]) -		] -	}; -} - -#[allow(clippy::cognitive_complexity)] -#[test] -fn two_targets() { -	parses_to! { -		parser: RstParser, -		input: "\ -.. _a: http://example.com -.. _`b_`: https://example.org -", -		rule: Rule::document, -		tokens: [ -			target(0, 26, [ -				target_name_uq(4, 5), -				link_target(7, 25), -			]), -			target(26, 56, [ -				target_name_qu(31, 33), -				link_target(36, 55), -			]), -		] -	}; -} - -#[allow(clippy::cognitive_complexity)] -#[test] -fn admonitions() { -	parses_to! { -		parser: RstParser, -		input: "\ -.. note:: -   Just next line -.. admonition:: In line title - -   Next line - -.. danger:: Just this line -", -		rule: Rule::document, -		tokens: [ -			admonition_gen(0, 27, [ -				admonition_type(3, 7), -				paragraph(13, 27, [ str(13, 27) ]), -			]), -			admonition(28, 71, [ -				line(43, 58, [ str(43, 57) ]), -				paragraph(62, 71, [ str(62, 71) ]), -			]), -			admonition_gen(73, 100, [ -				admonition_type(76, 82), -				line(84, 100, [ str(84, 99) ]), -			]), -		] -	}; -} - - -#[allow(clippy::cognitive_complexity)] -#[test] -fn substitutions() { -	parses_to! { -		parser: RstParser, -		input: "\ -A |subst| in-line - -.. |subst| replace:: substitution -.. |subst2| replace:: it can also -   be hanging -", -		rule: Rule::document, -		tokens: [ -			paragraph(0, 17, [ -				str(0, 2), -				substitution_name(3, 8), -				str(9, 17), -			]), -			substitution_def(19, 52, [ -				substitution_name(23, 28), -				replace(30, 52, [ paragraph(40, 52, [str(40, 52)]) ]), -			]), -			substitution_def(53, 101, [ -				substitution_name(57, 63), -				replace(65, 101, [ paragraph(75, 101, [ -					str(75, 86), ws_newline(86, 87), -					str(88, 100), -				]) ]), -			]), -		] -	}; -} - - -#[allow(clippy::cognitive_complexity)] -#[test] -fn substitution_image() { -	parses_to! { -		parser: RstParser, -		input: "\ -.. |subst| image:: thing.png -   :target: foo.html -", -		rule: Rule::document, -		tokens: [ -			substitution_def(0, 50, [ -				substitution_name(4, 9), -				image(11, 50, [ -					line(18, 29, [ str(18, 28) ]), -					image_option(32, 50, [ -						image_opt_name(33, 39), -						line(40, 50, [ str(40, 49) ]), -					]), -				]), -			]), -		] -	}; -} - -// TODO: test images - -#[allow(clippy::cognitive_complexity)] -#[test] -fn nested_lists() { -	parses_to! { -		parser: RstParser, -		input: "\ -paragraph - --  item 1 --  item 2 -   more text -   more text 2 -   more text 3 -   - nested item 1 -   - nested item 2 -   - nested item 3 -", -		rule: Rule::document, -		tokens: [ -			paragraph(0, 9, [ str(0, 9) ]), -			bullet_list(11, 131, [ -				bullet_item(11, 21, [ -					line(14, 21, [ str(14, 20) ]), -				]), -				bullet_item(21, 131, [ -					line(24, 31, [ str(24, 30) ]), -					paragraph(34, 74, [ -						str(34, 43), ws_newline(43, 44), -						str(47, 58), ws_newline(58, 59), -						str(62, 73), -					]), -					bullet_list(77, 131, [ -						bullet_item( 77,  93, [ line( 79,  93, [str( 79,  92)]) ]), -						bullet_item( 96, 112, [ line( 98, 112, [str( 98, 111)]) ]), -						bullet_item(115, 131, [ line(117, 131, [str(117, 130)]) ]), -					]), -				]), -			]), -		] -	} -} diff --git a/src/parser/token.rs b/src/parser/token.rs deleted file mode 100644 index b3b7bac..0000000 --- a/src/parser/token.rs +++ /dev/null @@ -1,16 +0,0 @@ -//http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#bullet-lists - -// *, +, -, •, ‣, ⁃ -pub enum BulletListType { Ast, Plus, Minus, Bullet, TriBullet, HyphenBullet } -// 1, A, a, I, i -pub enum EnumListChar { Arabic, AlphaUpper, AlphaLower, RomanUpper, RomanLower, Auto } -// 1., (1), 1) -pub enum EnumListType { Period, ParenEnclosed, Paren } -// ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~ -pub enum AdornmentChar { -	Bang, DQuote, Hash, Dollar, Percent, Amp, SQuote, LParen, RParen, Ast, Plus, Comma, -	Minus, Period, Slash, Colon, Semicolon, Less, Eq, More, Question, At, LBrack, -	Backslash, RBrack, Caret, Underscore, Backtick, LBrace, Pipe, RBrace, Tilde, -} -// [1], [#], [*], [#foo] -pub enum FootnoteType { Numbered(usize), AutoNumber, AutoSymbol, AutoNamed(String) } | 
