1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//! # Parser
//! This is a handwritten top-down parser for the [twig templating language](https://twig.symfony.com/) combined with HTML.
//! It's mostly developed together with the linter / formatter [ludtwig](https://github.com/MalteJanz/ludtwig).
//!
//! Parsing both Twig and HTML together into a single hierarchical syntax tree gives some benefits,
//! valid syntax trees follow some desirable properties:
//! - non-self-closing HTML tags always need a corresponding closing tag
//! - opening and closing HTML tag must exist inside the same Twig block
//! - Twig syntax is only allowed in specific places instead of everywhere
//!
//! which in turn make these templates and the HTML generated in the end less error-prone.
//!
//! # Syntax trees
//! The parser constructs a syntax tree based on the library [rowan](https://github.com/rust-analyzer/rowan).
//! A conceptual overview can be found here [Syntax in rust-analyzer](https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/syntax.md).
//! Basically the syntax tree consists of three layers:
//! - GreenNodes
//! - SyntaxNodes (aka RedNodes)
//! - AstNodes (defined in this crate)
//!
//! # Examples
//!
//! ## Parsing into a syntax tree
//! ```
//! use ludtwig_parser::syntax::untyped::{debug_tree, SyntaxNode};
//!
//! let parse = ludtwig_parser::parse("{{ 42 }}");
//!
//! // parsing might result in errors
//! assert!(parse.errors.is_empty());
//!
//! // in any case it will always produce a usable syntax tree
//! // and provide a green node of the root.
//!
//! // for getting a SyntaxNode of the root you can use this shortcut
//! // or construct the root by hand from the GreenNode (see SyntaxNode::new_root)
//! let (tree_root, errors) = parse.split();
//!
//! // you can now iterate or search through the syntax tree
//! // or debug print it with
//! println!("{}", debug_tree(&tree_root));
//! # assert_eq!(debug_tree(&tree_root), r##"ROOT@0..8
//! # TWIG_VAR@0..8
//! # TK_OPEN_CURLY_CURLY@0..2 "{{"
//! # TWIG_EXPRESSION@2..5
//! # TWIG_LITERAL_NUMBER@2..5
//! # TK_WHITESPACE@2..3 " "
//! # TK_NUMBER@3..5 "42"
//! # TK_WHITESPACE@5..6 " "
//! # TK_CLOSE_CURLY_CURLY@6..8 "}}""##);
//! ```
//!
//! ## Iterate in Preorder
//! ```
//! # let parse = ludtwig_parser::parse("{{ 42 }}");
//! # let (tree_root, errors) = parse.split();
//!
//! use ludtwig_parser::syntax::untyped::WalkEvent;
//! use ludtwig_parser::syntax::typed::AstNode;
//! use ludtwig_parser::syntax::typed::TwigVar;
//!
//! let mut preorder = tree_root.preorder();
//! while let Some(walk_event) = preorder.next() {
//! match walk_event {
//! WalkEvent::Enter(syntax_node) => {
//! if let Some(twig_var) = TwigVar::cast(syntax_node) {
//! // do something with ast node here
//! }
//! }
//! WalkEvent::Leave(syntax_node) => {}
//! }
//! }
//! ```
//!
//! ## Utilities for retrieving a specific AstNode or Token
//! As of now there might be missing utility method implementations on AstNode's.
//! You can use these instead to retrieve any AstNode / Token you want (under a given AstNode).
//! ```
//! # let parse = ludtwig_parser::parse("{{ 42 }}");
//! # let (tree_root, errors) = parse.split();
//!
//! use ludtwig_parser::syntax::typed::{AstNode, support, TwigVar};
//! use ludtwig_parser::syntax::untyped::SyntaxToken;
//! use ludtwig_parser::T;
//!
//! // finding a specific AstNode in a (sub) tree (first occurrence)
//! // Note: only looks through the direct children of the given SyntaxNode
//! let twig_var: TwigVar = support::child(&tree_root).unwrap();
//!
//! // you can freely get the underlaying SyntaxNode of an AstNode with
//! let twig_var_syntax_node = twig_var.syntax();
//!
//! // finding a specific Token in a (sub) tree (first occurrence)
//! // Note: only looks through the direct children of the given SyntaxNode
//! let twig_var_opening_braces: SyntaxToken = support::token(twig_var_syntax_node, T!["{{"]).unwrap();
//!
//! // finding specific AstNode's in a (sub) tree (all occurrence)
//! // returns an iterator
//! // Note: only looks through the direct children of the given SyntaxNode
//! let twig_vars = support::children::<TwigVar>(&tree_root);
//! # assert_eq!(twig_vars.count(), 1);
//! ```
//!
pub use Parse;
pub use ParseError;
pub use parse;
use cratelex;
pub use TWIG_NAME_REGEX;