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}