asciidoc_parser/parser/parser.rs
1use std::collections::HashMap;
2
3use crate::{
4 document::InterpretedValue,
5 parser::{AllowableValue, AttributeValue, ModificationContext},
6 Document,
7};
8
9/// The [`Parser`] struct and its related structs allow a caller to configure
10/// how AsciiDoc parsing occurs and then to initiate the parsing process.
11#[derive(Clone, Debug, Default, Eq, PartialEq)]
12pub struct Parser<'p> {
13 /// Attribute values at current state of parsing.
14 pub(crate) attribute_values: HashMap<String, AttributeValue<'p>>,
15}
16
17impl<'p> Parser<'p> {
18 /// Parse a UTF-8 string as an AsciiDoc document.
19 ///
20 /// Note that the document references the underlying source string and
21 /// necessarily has the same lifetime as the source.
22 ///
23 /// The [`Document`] data structure returned by this call and nearly all
24 /// data structures contained within it are gated by the lifetime of the
25 /// `source` text passed in to this function. For that reason all of
26 /// those data structures are given the lifetime `'src`.
27 ///
28 /// **IMPORTANT:** The AsciiDoc language documentation states that UTF-16
29 /// encoding is allowed if a byte-order-mark (BOM) is present at the
30 /// start of a file. This format is not directly supported by the
31 /// `asciidoc-parser` crate. Any UTF-16 content must be re-encoded as
32 /// UTF-8 prior to parsing.
33 ///
34 /// # Warnings, not errors
35 ///
36 /// Any UTF-8 string is a valid AsciiDoc document, so this function does not
37 /// return an [`Option`] or [`Result`] data type. There may be any number of
38 /// character sequences that have ambiguous or potentially unintended
39 /// meanings. For that reason, a caller is advised to review the warnings
40 /// provided via the [`warnings()`] iterator.
41 ///
42 /// [`warnings()`]: Document::warnings
43 pub fn parse<'src>(&self, source: &'src str) -> Document<'src> {
44 let mut temp_copy = self.clone();
45 Document::parse(source, &mut temp_copy)
46 }
47
48 /// Retrieves the current interpreted value of a [document attribute].
49 ///
50 /// Each document holds a set of name-value pairs called document
51 /// attributes. These attributes provide a means of configuring the AsciiDoc
52 /// processor, declaring document metadata, and defining reusable content.
53 /// This page introduces document attributes and answers some questions
54 /// about the terminology used when referring to them.
55 ///
56 /// ## What are document attributes?
57 ///
58 /// Document attributes are effectively document-scoped variables for the
59 /// AsciiDoc language. The AsciiDoc language defines a set of built-in
60 /// attributes, and also allows the author (or extensions) to define
61 /// additional document attributes, which may replace built-in attributes
62 /// when permitted.
63 ///
64 /// Built-in attributes either provide access to read-only information about
65 /// the document and its environment or allow the author to configure
66 /// behavior of the AsciiDoc processor for a whole document or select
67 /// regions. Built-in attributes are effectively unordered. User-defined
68 /// attribute serve as a powerful text replacement tool. User-defined
69 /// attributes are stored in the order in which they are defined.
70 ///
71 /// [document attribute]: https://docs.asciidoctor.org/asciidoc/latest/attributes/document-attributes/
72 pub fn attribute_value<N: AsRef<str>>(&self, name: N) -> InterpretedValue<'p> {
73 self.attribute_values
74 .get(name.as_ref())
75 .map(|av| av.value.clone())
76 .unwrap_or(InterpretedValue::Unset)
77 }
78
79 /// Sets the value of an [intrinsic attribute].
80 ///
81 /// Intrinsic attributes are set automatically by the processor. These
82 /// attributes provide information about the document being processed (e.g.,
83 /// `docfile`), the security mode under which the processor is running
84 /// (e.g., `safe-mode-name`), and information about the user’s environment
85 /// (e.g., `user-home`).
86 ///
87 /// The [`modification_context`](ModificationContext) establishes whether
88 /// the value can be subsequently modified by the document header and/or in
89 /// the document body.
90 ///
91 /// Subsequent calls to this function or [`with_intrinsic_attribute_bool()`]
92 /// are always permitted. The last such call for any given attribute name
93 /// takes precendence.
94 ///
95 /// [intrinsic attribute]: https://docs.asciidoctor.org/asciidoc/latest/attributes/document-attributes-ref/#intrinsic-attributes
96 ///
97 /// [`with_intrinsic_attribute_bool()`]: Self::with_intrinsic_attribute_bool
98 pub fn with_intrinsic_attribute<N: AsRef<str>, V: AsRef<str>>(
99 mut self,
100 name: N,
101 value: V,
102 modification_context: ModificationContext,
103 ) -> Self {
104 let attribute_value = AttributeValue {
105 allowable_value: AllowableValue::Any,
106 modification_context,
107 value: InterpretedValue::Value(value.as_ref().to_string().into()),
108 };
109
110 self.attribute_values
111 .insert(name.as_ref().to_string(), attribute_value);
112
113 self
114 }
115
116 /// Sets the value of an [intrinsic attribute] from a boolean flag.
117 ///
118 /// A boolean `true` is interpreted as "set." A boolean `false` is
119 /// interpreted as "unset."
120 ///
121 /// Intrinsic attributes are set automatically by the processor. These
122 /// attributes provide information about the document being processed (e.g.,
123 /// `docfile`), the security mode under which the processor is running
124 /// (e.g., `safe-mode-name`), and information about the user’s environment
125 /// (e.g., `user-home`).
126 ///
127 /// The [`modification_context`](ModificationContext) establishes whether
128 /// the value can be subsequently modified by the document header and/or in
129 /// the document body.
130 ///
131 /// Subsequent calls to this function or [`with_intrinsic_attribute()`] are
132 /// always permitted. The last such call for any given attribute name takes
133 /// precendence.
134 ///
135 /// [intrinsic attribute]: https://docs.asciidoctor.org/asciidoc/latest/attributes/document-attributes-ref/#intrinsic-attributes
136 ///
137 /// [`with_intrinsic_attribute()`]: Self::with_intrinsic_attribute
138 pub fn with_intrinsic_attribute_bool<N: AsRef<str>>(
139 mut self,
140 name: N,
141 value: bool,
142 modification_context: ModificationContext,
143 ) -> Self {
144 let attribute_value = AttributeValue {
145 allowable_value: AllowableValue::Any,
146 modification_context,
147 value: if value {
148 InterpretedValue::Set
149 } else {
150 InterpretedValue::Unset
151 },
152 };
153
154 self.attribute_values
155 .insert(name.as_ref().to_string(), attribute_value);
156
157 self
158 }
159}