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
157
158
159
//! AST definitions and utilities for the lex format
//!
//! This module provides the core Abstract Syntax Tree (AST) definitions,
//! along with utilities for working with AST nodes, tracking source positions,
//! and performing position-based lookups.
//!
//! Document and Sessions
//!
//! Lex documents are plain text, utf-8 encoded files with the file extension .lex. Line width
//! is not limited, and is considered a presentation detail. Best practice dictates only
//! limiting line length when publishing, not while authoring.
//!
//! The document node holds the document metadata and the content's root node, which is a
//! session node. The structure of the document then is a tree of sessions, which can be nested
//! arbitrarily. This creates powerful addressing capabilities as one can target any sub-session
//! from an index.
//!
//! See [Document](elements::Document) for the document node definition, and [Session](elements::Session)
//! for session nodes.
//!
//! Nesting
//!
//! The ability to make deep structures is core to Lex, and this is reflected throughout the
//! grammar. In fact the only element that does not contain children is the paragraph and the
//! verbatim block (by definition content that is not parsed).
//!
//! Nesting is pretty unrestricted with the following logical exceptions:
//!
//! - Only sessions can contain other sessions: you don't want a session popping up in the
//! middle of a list item.
//! - Annotations (metadata) cannot host inner annotations, that is you can't have metadata
//! on metadata (pretty reasonable, no?).
//!
//! This nesting structure is enforced at compile time through type-safe containers. Containers
//! such as Session, Definition, and Annotation take typed vectors (SessionContent,
//! ContentElement, etc.) so invalid nesting is ruled out at compile time. See the
//! [container](elements::container) module for details.
//!
//! For more details on element types, how they structure content, and the relationship between
//! indentation and the AST, see the [elements](elements) module.
//!
//! ## How Location Tracking Works in lex
//!
//! Location tracking flows through the entire compilation pipeline from raw source code to AST nodes.
//!
//! ### 1. Tokenization (Lexer)
//!
//! The lexer produces tokens paired with byte-offset ranges into the source:
//!
//! ```text
//! Source: "Hello\nWorld"
//! 012345678901
//! ↓
//! Lexer: (Token::Text("Hello"), 0..5)
//! (Token::Newline, 5..6)
//! (Token::Text("World"), 6..11)
//! ```
//!
//! The lexer pipeline applies transformations while preserving byte ranges:
//! - Whitespace processing - removes tokens, preserves ranges
//! - Indentation transformation - converts to semantic Indent/Dedent tokens
//! - Blank line transformation - aggregates multiple Newlines
//!
//! ### 2. Byte-to-Line Conversion
//!
//! Before building AST nodes, byte ranges are converted to line:column positions
//! using `SourceLocation` (one-time setup, O(log n) per conversion):
//!
//! ```text
//! SourceLocation pre-computes line starts: [0, 6]
//! byte_to_position(8) → binary search → Position { line: 1, column: 2 }
//! ```
//!
//! ### 3. Parser (AST Construction)
//!
//! The parser builds AST nodes with `Range` objects via bottom-up construction:
//! 1. Parse child elements (which have locations)
//! 2. Convert byte ranges to `Range` objects
//! 3. Aggregate child locations via `compute_location_from_locations()`
//! 4. Create parent node with aggregated location (bounding box)
//!
//! See `src/lex/building/location.rs` for the canonical implementations.
//!
//! ### 4. Complete Document Structure
//!
//! The final document has location information at every level - every element
//! knows its exact position in the source (start line:column to end line:column).
//!
//! ## Modules
//!
//! - `range` - Position and Range types for source code locations
//! - `elements` - AST node type definitions organized by element type
//! - `traits` - Common traits for AST nodes (AstNode, Container, Visitor)
//! - `lookup` - Position-based AST node lookup functionality
//! - `snapshot` - Normalized intermediate representation for serialization
//! - `error` - Error types for AST operations
//!
//! ## Type-Safe Containers
//!
//! Containers such as `Session`, `Definition`, and `Annotation` now take typed
//! vectors (`SessionContent`, `ContentElement`, etc.) so invalid nesting is ruled
//! out at compile time. See `docs/architecture/type-safe-containers.md` for
//! details and compile-fail examples.
// Re-export commonly used types at module root
pub use ;
pub use ;
pub use PositionLookupError;
pub use ;
pub use ;
pub use ;
pub use TextContent;
pub use ;
// Convenience functions that delegate to Document methods
// These are provided for backwards compatibility with existing code
/// Find nodes at a given position in the document
///
/// This is a convenience wrapper around `Document::find_nodes_at_position()`.
/// Returns a vector containing the deepest AST node at the given position.
/// Find the path of nodes at a given position in the document
///
/// Returns a vector containing the path of AST nodes from root to the deepest node at the given position.
/// Format information about nodes at a given position
///
/// This is a convenience wrapper around `Document::format_at_position()`.
/// Returns a formatted string describing the AST nodes at the given position.