1//! Fluent Translation List parsing utilities
2//!
3//! FTL resources can be parsed using one of two methods:
4//! * [`parse`] - parses an input into a complete Abstract Syntax Tree representation with all source information preserved.
5//! * [`parse_runtime`] - parses an input into a runtime optimized Abstract Syntax Tree
6//! representation with comments stripped.
7//!
8//! # Example
9//!
10//! ```
11//! use fluent_syntax::parser;
12//! use fluent_syntax::ast;
13//!
14//! let ftl = r#"
15//! #### Resource Level Comment
16//!
17//! ## This is a message comment
18//! hello-world = Hello World!
19//!
20//! "#;
21//!
22//! let resource = parser::parse(ftl)
23//! .expect("Failed to parse an FTL resource.");
24//!
25//! assert_eq!(
26//! resource.body[0],
27//! ast::Entry::ResourceComment(
28//! ast::Comment {
29//! content: vec![
30//! "Resource Level Comment"
31//! ]
32//! }
33//! )
34//! );
35//! assert_eq!(
36//! resource.body[1],
37//! ast::Entry::Message(
38//! ast::Message {
39//! id: ast::Identifier {
40//! name: "hello-world"
41//! },
42//! value: Some(ast::Pattern {
43//! elements: vec![
44//! ast::PatternElement::TextElement {
45//! value: "Hello World!"
46//! },
47//! ]
48//! }),
49//! attributes: vec![],
50//! comment: Some(
51//! ast::Comment {
52//! content: vec!["This is a message comment"]
53//! }
54//! )
55//! }
56//! ),
57//! );
58//! ```
59//!
60//! # Error Recovery
61//!
62//! In both modes the parser is lenient, attempting to recover from errors.
63//!
64//! The [`Result`] return the resulting AST in both scenarios, and in the
65//! error scenario a vector of [`ParserError`] elements is returned as well.
66//!
67//! Any unparsed parts of the input are returned as [`ast::Entry::Junk`] elements.
68#[macro_use]
69mod errors;
70#[macro_use]
71mod macros;
72mod comment;
73mod core;
74mod expression;
75mod helper;
76mod pattern;
77mod runtime;
78mod slice;
79
80use crate::ast;
81pub use errors::{ErrorKind, ParserError};
82pub use slice::Slice;
83
84/// Parser result always returns an AST representation of the input,
85/// and if parsing errors were encountered, a list of [`ParserError`] elements
86/// is also returned.
87///
88/// # Example
89///
90/// ```
91/// use fluent_syntax::parser;
92/// use fluent_syntax::ast;
93///
94/// let ftl = r#"
95/// key1 = Value 1
96///
97/// g@Rb@ge = #2y ds
98///
99/// key2 = Value 2
100///
101/// "#;
102///
103/// let (resource, errors) = parser::parse_runtime(ftl)
104/// .expect_err("Resource should contain errors.");
105///
106/// assert_eq!(
107/// errors,
108/// vec![
109/// parser::ParserError {
110/// pos: 18..19,
111/// slice: Some(17..35),
112/// kind: parser::ErrorKind::ExpectedToken('=')
113/// }
114/// ]
115/// );
116///
117/// assert_eq!(
118/// resource.body[0],
119/// ast::Entry::Message(
120/// ast::Message {
121/// id: ast::Identifier {
122/// name: "key1"
123/// },
124/// value: Some(ast::Pattern {
125/// elements: vec![
126/// ast::PatternElement::TextElement {
127/// value: "Value 1"
128/// },
129/// ]
130/// }),
131/// attributes: vec![],
132/// comment: None,
133/// }
134/// ),
135/// );
136///
137/// assert_eq!(
138/// resource.body[1],
139/// ast::Entry::Junk {
140/// content: "g@Rb@ge = #2y ds\n\n"
141/// }
142/// );
143///
144/// assert_eq!(
145/// resource.body[2],
146/// ast::Entry::Message(
147/// ast::Message {
148/// id: ast::Identifier {
149/// name: "key2"
150/// },
151/// value: Some(ast::Pattern {
152/// elements: vec![
153/// ast::PatternElement::TextElement {
154/// value: "Value 2"
155/// },
156/// ]
157/// }),
158/// attributes: vec![],
159/// comment: None,
160/// }
161/// ),
162/// );
163/// ```
164pub type Result<S> = std::result::Result<ast::Resource<S>, (ast::Resource<S>, Vec<ParserError>)>;
165
166/// Parses an input into a complete Abstract Syntax Tree representation with
167/// all source information preserved.
168///
169/// This mode is intended for tooling, linters and other scenarios where
170/// complete representation, with comments, is preferred over speed and memory
171/// utilization.
172///
173/// # Example
174///
175/// ```
176/// use fluent_syntax::parser;
177/// use fluent_syntax::ast;
178///
179/// let ftl = r#"
180/// #### Resource Level Comment
181///
182/// ## This is a message comment
183/// hello-world = Hello World!
184///
185/// "#;
186///
187/// let resource = parser::parse(ftl)
188/// .expect("Failed to parse an FTL resource.");
189///
190/// assert_eq!(
191/// resource.body[0],
192/// ast::Entry::ResourceComment(
193/// ast::Comment {
194/// content: vec![
195/// "Resource Level Comment"
196/// ]
197/// }
198/// )
199/// );
200/// assert_eq!(
201/// resource.body[1],
202/// ast::Entry::Message(
203/// ast::Message {
204/// id: ast::Identifier {
205/// name: "hello-world"
206/// },
207/// value: Some(ast::Pattern {
208/// elements: vec![
209/// ast::PatternElement::TextElement {
210/// value: "Hello World!"
211/// },
212/// ]
213/// }),
214/// attributes: vec![],
215/// comment: Some(
216/// ast::Comment {
217/// content: vec!["This is a message comment"]
218/// }
219/// )
220/// }
221/// ),
222/// );
223/// ```
224pub fn parse<'s, S>(input: S) -> Result<S>
225where
226 S: Slice<'s>,
227{
228 core::Parser::new(source:input).parse()
229}
230
231/// Parses an input into an Abstract Syntax Tree representation with comments stripped.
232///
233/// This mode is intended for runtime use of Fluent. It currently strips all
234/// comments improving parsing performance and reducing the size of the AST tree.
235///
236/// # Example
237///
238/// ```
239/// use fluent_syntax::parser;
240/// use fluent_syntax::ast;
241///
242/// let ftl = r#"
243/// #### Resource Level Comment
244///
245/// ## This is a message comment
246/// hello-world = Hello World!
247///
248/// "#;
249///
250/// let resource = parser::parse_runtime(ftl)
251/// .expect("Failed to parse an FTL resource.");
252///
253/// assert_eq!(
254/// resource.body[0],
255/// ast::Entry::Message(
256/// ast::Message {
257/// id: ast::Identifier {
258/// name: "hello-world"
259/// },
260/// value: Some(ast::Pattern {
261/// elements: vec![
262/// ast::PatternElement::TextElement {
263/// value: "Hello World!"
264/// },
265/// ]
266/// }),
267/// attributes: vec![],
268/// comment: None,
269/// }
270/// ),
271/// );
272/// ```
273pub fn parse_runtime<'s, S>(input: S) -> Result<S>
274where
275 S: Slice<'s>,
276{
277 core::Parser::new(source:input).parse_runtime()
278}
279