Coverage Report

Created: 2026-06-15 06:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/lexpr-0.2.7/src/datum.rs
Line
Count
Source
1
//! S-expression values including source location.
2
3
use std::{io, iter, slice};
4
5
use crate::{
6
    parse::{read, Options, Parser, Position, Result},
7
    Cons, Value,
8
};
9
10
/// Combines an S-expression value with location information.
11
///
12
/// A `Datum` keeps, along with a plain `Value`, information about the text
13
/// location the value was parsed from. For compound values, such as lists and
14
/// vectors, that includes information for all contained values, recursively.
15
///
16
/// A `Datum` can be obtained by using the [`next_datum`] and [`expect_datum`]
17
/// methods on `Parser`, or via the iterator obtained with [`datum_iter`].
18
///
19
/// [`next_datum`]: Parser::next_datum
20
/// [`expect_datum`]: Parser::expect_datum
21
/// [`datum_iter`]: Parser::datum_iter
22
#[derive(Debug, Clone, PartialEq)]
23
pub struct Datum {
24
    value: Value,
25
    info: SpanInfo,
26
}
27
28
impl Datum {
29
0
    pub(crate) fn into_inner(self) -> (Value, SpanInfo) {
30
0
        (self.value, self.info)
31
0
    }
32
33
    /// Returns a reference to the contained value.
34
0
    pub fn value(&self) -> &Value {
35
0
        &self.value
36
0
    }
37
38
    /// Returns the span for the compelete value.
39
0
    pub fn span(&self) -> Span {
40
0
        self.info.span()
41
0
    }
42
43
    /// Returns a reference to the datum.
44
0
    pub fn as_ref(&self) -> Ref<'_> {
45
0
        Ref {
46
0
            value: &self.value,
47
0
            info: &self.info,
48
0
        }
49
0
    }
50
51
    /// Returns an iterator over the elements of a list.
52
    ///
53
    /// If the value contained in the datum is not either a cons cell or `Null`, `None` is
54
    /// returned.
55
    ///
56
    /// Note that the returned iterator has special behavior for improper lists, yielding the
57
    /// element after the dot after returning `None` the first time.
58
    ///
59
    /// ```
60
    /// use lexpr::sexp;
61
    ///
62
    /// let datum = lexpr::datum::from_str("(1 2 . 3)").unwrap();
63
    /// let mut iter = datum.list_iter().unwrap();
64
    /// let one = iter.next().unwrap();
65
    /// assert_eq!(one.value(), &sexp!(1));
66
    /// let two = iter.next().unwrap();
67
    /// assert_eq!(two.value(), &sexp!(2));
68
    /// assert_eq!(iter.next(), None);
69
    /// let three = iter.next().unwrap();
70
    /// assert_eq!(three.value(), &sexp!(3));
71
    /// assert_eq!(iter.next(), None);
72
    /// ```
73
0
    pub fn list_iter(&self) -> Option<ListIter<'_>> {
74
0
        self.as_ref().list_iter()
75
0
    }
76
77
    /// Returns an iterator over the elements of a vector.
78
    ///
79
    /// If the value contained in the datum is not a vector, `None` is returned.
80
0
    pub fn vector_iter(&self) -> Option<VectorIter<'_>> {
81
0
        self.as_ref().vector_iter()
82
0
    }
83
84
0
    pub(crate) fn primitive(value: Value, start: Position, end: Position) -> Self {
85
0
        Datum {
86
0
            value,
87
0
            info: SpanInfo::Prim(Span { start, end }),
88
0
        }
89
0
    }
90
91
0
    pub(crate) fn vec(
92
0
        elements: Vec<Value>,
93
0
        element_info: Vec<SpanInfo>,
94
0
        start: Position,
95
0
        end: Position,
96
0
    ) -> Self {
97
0
        Datum {
98
0
            value: Value::Vector(elements.into()),
99
0
            info: SpanInfo::Vec(Span { start, end }, element_info),
100
0
        }
101
0
    }
102
103
0
    pub(crate) fn cons(cell: Cons, meta: [SpanInfo; 2], start: Position, end: Position) -> Self {
104
0
        Datum {
105
0
            value: Value::Cons(cell),
106
0
            info: SpanInfo::Cons(Span::new(start, end), Box::new(meta)),
107
0
        }
108
0
    }
109
110
0
    pub(crate) fn quotation(name: &str, quoted: Datum, quote_span: Span) -> Self {
111
0
        let (quoted_value, quoted_info) = quoted.into_inner();
112
0
        let quoted_end = quoted_info.span().end();
113
0
        let null_span = Span::new(quoted_end, quoted_end);
114
0
        Datum {
115
0
            value: Value::list(vec![Value::symbol(name), quoted_value]),
116
0
            info: SpanInfo::Cons(
117
0
                Span::new(quote_span.start(), quoted_end),
118
0
                Box::new([
119
0
                    SpanInfo::Prim(quote_span),
120
0
                    SpanInfo::Cons(
121
0
                        quoted_info.span(),
122
0
                        Box::new([quoted_info, SpanInfo::Prim(null_span)]),
123
0
                    ),
124
0
                ]),
125
0
            ),
126
0
        }
127
0
    }
128
}
129
130
impl From<Datum> for Value {
131
0
    fn from(datum: Datum) -> Self {
132
0
        datum.value
133
0
    }
134
}
135
136
/// A reference to a value and corresponding location information.
137
///
138
/// A `Ref` is the generalized version of `&Datum`; it can not only refer a top-level, owned `Datum`
139
/// value, but also to values recursively contained therein.
140
#[derive(Debug, Clone, Copy, PartialEq)]
141
pub struct Ref<'a> {
142
    value: &'a Value,
143
    info: &'a SpanInfo,
144
}
145
146
impl<'a> AsRef<Value> for Ref<'a> {
147
0
    fn as_ref(&self) -> &Value {
148
0
        self.value
149
0
    }
150
}
151
152
impl<'a> From<Ref<'a>> for Datum {
153
    /// Turns a reference into an owned `Datum`, by cloning the referenced value and location
154
    /// information.
155
0
    fn from(r: Ref<'a>) -> Self {
156
0
        Datum {
157
0
            value: r.value.clone(),
158
0
            info: r.info.clone(),
159
0
        }
160
0
    }
161
}
162
163
impl<'a> Ref<'a> {
164
0
    fn new(value: &'a Value, info: &'a SpanInfo) -> Self {
165
0
        Ref { value, info }
166
0
    }
167
168
    /// Returns the span of the referenced value.
169
0
    pub fn span(&self) -> Span {
170
0
        self.info.span()
171
0
    }
172
173
    /// Returns a reference to the contained value.
174
0
    pub fn value(&self) -> &'a Value {
175
0
        self.value
176
0
    }
177
178
    /// If the value referenced is not either a cons cell or `Null`, `None` is returned.
179
    ///
180
    /// Note that the returned iterator has special behavior for improper lists, yielding the
181
    /// element after the dot after returning `None` the first time; see [`Datum::list_iter`] for an
182
    /// example.
183
0
    pub fn list_iter(&self) -> Option<ListIter<'a>> {
184
0
        match (self.value, self.info) {
185
0
            (Value::Cons(cell), SpanInfo::Cons(_, meta)) => Some(ListIter::cons(cell, meta)),
186
0
            (Value::Null, _) => Some(ListIter::empty()),
187
0
            _ => None,
188
        }
189
0
    }
190
191
    /// Returns an iterator over the elements of a vector.
192
    ///
193
    /// If the value referenced is not a vector, `None` is returned.
194
0
    pub fn vector_iter(&self) -> Option<VectorIter<'a>> {
195
0
        match (self.value, self.info) {
196
0
            (Value::Vector(elements), SpanInfo::Vec(_, element_meta)) => {
197
0
                Some(VectorIter(elements.iter().zip(element_meta)))
198
            }
199
0
            _ => None,
200
        }
201
0
    }
202
203
    /// Returns a pair of references to the fields of a cons cell.
204
    ///
205
    /// If the value referenced is not a cons cell, `None` is returned.
206
0
    pub fn as_pair(&self) -> Option<(Ref<'a>, Ref<'a>)> {
207
0
        let (car, cdr) = self.value.as_pair()?;
208
0
        match &self.info {
209
0
            SpanInfo::Cons(_, inner) if inner.len() == 2 => {
210
0
                Some((Ref::new(car, &inner[0]), Ref::new(cdr, &inner[1])))
211
            }
212
0
            _ => unreachable!("badly shaped pair span information"),
213
        }
214
0
    }
215
}
216
217
impl<'a> std::ops::Deref for Ref<'a> {
218
    type Target = Value;
219
220
0
    fn deref(&self) -> &Self::Target {
221
0
        self.value
222
0
    }
223
}
224
225
/// The start and end for a span of text.
226
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
227
pub struct Span {
228
    start: Position,
229
    end: Position,
230
}
231
232
impl Span {
233
0
    pub(crate) fn new(start: Position, end: Position) -> Self {
234
0
        Span { start, end }
235
0
    }
236
237
0
    pub(crate) fn empty() -> Self {
238
0
        Span {
239
0
            start: Position::new(0, 0),
240
0
            end: Position::new(0, 0),
241
0
        }
242
0
    }
243
244
    /// Get the starting line/column in the source file for this span.
245
0
    pub fn start(&self) -> Position {
246
0
        self.start
247
0
    }
248
249
    /// Get the ending line/column in the source file for this span.
250
0
    pub fn end(&self) -> Position {
251
0
        self.end
252
0
    }
253
}
254
255
#[derive(Debug, Clone, PartialEq)]
256
pub(crate) enum SpanInfo {
257
    Prim(Span),
258
    Cons(Span, Box<[SpanInfo; 2]>),
259
    Vec(Span, Vec<SpanInfo>),
260
}
261
262
impl SpanInfo {
263
0
    fn span(&self) -> Span {
264
0
        match self {
265
0
            SpanInfo::Prim(span) => *span,
266
0
            SpanInfo::Cons(span, _) => *span,
267
0
            SpanInfo::Vec(span, _) => *span,
268
        }
269
0
    }
270
0
    pub(crate) fn cons_mut(&mut self) -> Option<&mut [SpanInfo; 2]> {
271
0
        match self {
272
0
            SpanInfo::Cons(_, info) => Some(info),
273
0
            _ => None,
274
        }
275
0
    }
276
}
277
278
/// An iterator over the elements
279
#[derive(Debug, Clone)]
280
pub struct VectorIter<'a>(iter::Zip<slice::Iter<'a, Value>, slice::Iter<'a, SpanInfo>>);
281
282
impl<'a> Iterator for VectorIter<'a> {
283
    type Item = Ref<'a>;
284
285
0
    fn next(&mut self) -> Option<Self::Item> {
286
0
        self.0.next().map(|(value, info)| Ref { value, info })
287
0
    }
288
}
289
290
/// An iterator yielding the `car` field of a chain of cons cells.
291
///
292
/// # Improper lists
293
///
294
/// Since in Lisp, lists can be "improper", i.e., terminated by a value other than `Null`, this
295
/// iterator type takes advantage of the fact that Rust's iterators can produce multiple sequences
296
/// of values, each terminated by `None`. For an improper list, the terminating value is produced
297
/// after the sequence of elements, as a singleton element, again followed by `None`.
298
///
299
/// For example, while the list `(1 2 3)` will produce the three expected `Some` values, followed by
300
/// `None`, the list `(1 2 . 3)` will produce `Some` values for `1` and `2`, then a `None`, followed
301
/// by a some value for `3`, and then the final `None`.
302
#[derive(Debug, Clone)]
303
pub struct ListIter<'a>(ListCursor<'a>);
304
305
impl<'a> ListIter<'a> {
306
    /// Returns true when the iterator is completely exhausted.
307
    ///
308
    /// For an improper list, true will only be returned after the terminating value has been
309
    /// consumed.
310
0
    pub fn is_empty(&self) -> bool {
311
0
        matches!(&self.0, ListCursor::Exhausted)
312
0
    }
313
314
    /// Returns a peek at the value that would be returned by a call to `next`.
315
    ///
316
    /// For improper lists, this implies that after the last regular element, `None` will be
317
    /// returned, while `is_empty` still returns false at that point.
318
0
    pub fn peek(&self) -> Option<Ref<'_>> {
319
0
        match &self.0 {
320
0
            ListCursor::Cons(cell, info) => Some(Ref {
321
0
                value: cell.car(),
322
0
                info: &info[0],
323
0
            }),
324
0
            ListCursor::Dot(_, _) => None,
325
0
            ListCursor::Rest(value, info) => Some(Ref { value, info }),
326
0
            ListCursor::Exhausted => None,
327
        }
328
0
    }
329
330
0
    fn empty() -> Self {
331
0
        ListIter(ListCursor::Exhausted)
332
0
    }
333
334
0
    fn cons(cell: &'a Cons, meta: &'a [SpanInfo; 2]) -> Self {
335
0
        ListIter(ListCursor::Cons(cell, meta))
336
0
    }
337
}
338
339
#[derive(Debug, Clone)]
340
enum ListCursor<'a> {
341
    Cons(&'a Cons, &'a [SpanInfo; 2]),
342
    Dot(&'a Value, &'a SpanInfo),
343
    Rest(&'a Value, &'a SpanInfo),
344
    Exhausted,
345
}
346
347
impl<'a> Iterator for ListIter<'a> {
348
    type Item = Ref<'a>;
349
350
0
    fn next(&mut self) -> Option<Self::Item> {
351
0
        match self.0 {
352
0
            ListCursor::Cons(cell, [car_meta, cdr_meta]) => {
353
0
                let car = cell.car();
354
0
                match cdr_meta {
355
0
                    SpanInfo::Cons(_, next) => {
356
0
                        let cell = cell
357
0
                            .cdr()
358
0
                            .as_cons()
359
0
                            .expect("badly shaped list span information");
360
0
                        self.0 = ListCursor::Cons(cell, next);
361
0
                    }
362
0
                    SpanInfo::Prim(_) if cell.cdr().is_null() => {
363
0
                        self.0 = ListCursor::Exhausted;
364
0
                    }
365
0
                    _ => {
366
0
                        self.0 = ListCursor::Dot(cell.cdr(), cdr_meta);
367
0
                    }
368
                }
369
0
                Some(Ref {
370
0
                    value: car,
371
0
                    info: car_meta,
372
0
                })
373
            }
374
0
            ListCursor::Dot(value, info) => {
375
0
                self.0 = ListCursor::Rest(value, info);
376
0
                None
377
            }
378
0
            ListCursor::Rest(value, info) => {
379
0
                self.0 = ListCursor::Exhausted;
380
0
                Some(Ref { value, info })
381
            }
382
0
            ListCursor::Exhausted => None,
383
        }
384
0
    }
385
}
386
387
0
fn from_trait<'de, R>(read: R, options: Options) -> Result<Datum>
388
0
where
389
0
    R: read::Read<'de>,
390
{
391
0
    let mut parser = Parser::with_options(read, options);
392
0
    let datum = parser.expect_datum()?;
393
0
    parser.expect_end()?;
394
395
0
    Ok(datum)
396
0
}
Unexecuted instantiation: lexpr::datum::from_trait::<lexpr::parse::read::StrRead>
Unexecuted instantiation: lexpr::datum::from_trait::<lexpr::parse::read::SliceRead>
397
398
/// Parse a datum from an IO stream containing a single S-expression.
399
///
400
/// The content of the IO stream is parsed directly from the stream
401
/// without being buffered in memory.
402
///
403
/// When reading from a source against which short reads are not efficient, such
404
/// as a [`File`], you will want to apply your own buffering, e.g. using
405
/// [`std::io::BufReader`].
406
///
407
/// ```no_run
408
/// use std::error::Error;
409
/// use std::fs::File;
410
/// use std::io::BufReader;
411
/// use std::path::Path;
412
///
413
/// fn read_datum_from_file<P: AsRef<Path>>(path: P) -> Result<lexpr::Datum, Box<dyn Error>> {
414
///     // Open the file in read-only mode with buffer.
415
///     let file = File::open(path)?;
416
///     let reader = BufReader::new(file);
417
///
418
///     // Read an arbitrary S-expression, using parser options suitable for Emacs Lisp.
419
///     let datum = lexpr::datum::from_reader_custom(reader, lexpr::parse::Options::elisp())?;
420
///
421
///     // Return the datum.
422
///     Ok(datum)
423
/// }
424
///
425
/// let datum = read_datum_from_file("test.el").unwrap();
426
/// println!("{:?}", datum);
427
/// ```
428
///
429
/// [`File`]: https://doc.rust-lang.org/std/fs/struct.File.html
430
/// [`BufReader`]: https://doc.rust-lang.org/std/io/struct.BufReader.html
431
0
pub fn from_reader_custom(rdr: impl io::Read, options: Options) -> Result<Datum> {
432
0
    from_trait(read::IoRead::new(rdr), options)
433
0
}
434
435
/// Parse a datum from an IO stream of S-expressions, using the default parser
436
/// options.
437
///
438
/// See [`from_reader_custom`] for more information.
439
///
440
/// [`from_reader_custom`]: fn.from_reader_custom.html
441
0
pub fn from_reader(rdr: impl io::Read) -> Result<Datum> {
442
0
    from_reader_custom(rdr, Options::default())
443
0
}
444
445
/// Parse a datum from an IO stream of S-expressions, using the parser
446
/// options suitable for parsing Emacs Lisp.
447
///
448
/// See [`from_reader_custom`] for more information.
449
///
450
/// [`from_reader_custom`]: fn.from_reader_custom.html
451
0
pub fn from_reader_elisp(rdr: impl io::Read) -> Result<Datum> {
452
0
    from_reader_custom(rdr, Options::elisp())
453
0
}
454
455
/// Parse a datum from bytes representing a single S-expression.
456
///
457
/// ```
458
/// let datum = lexpr::from_slice_custom(b"(a (nested) list)", lexpr::parse::Options::new());
459
/// println!("{:?}", datum);
460
/// ```
461
0
pub fn from_slice_custom(bytes: &[u8], options: Options) -> Result<Datum> {
462
    // TODO: the use of SliceRead is most probably not a good idea, since it calculates position
463
    // information on-demand, leading to O(n^2) complexity.
464
0
    from_trait(read::SliceRead::new(bytes), options)
465
0
}
466
467
/// Parse a datum from bytes representing a single S-expressions, using the
468
/// default parser options.
469
///
470
/// See [`from_slice_custom`] for more information.
471
///
472
/// [`from_slice_custom`]: fn.from_slice_custom.html
473
0
pub fn from_slice(bytes: &[u8]) -> Result<Datum> {
474
0
    from_slice_custom(bytes, Options::default())
475
0
}
476
477
/// Parse a datum from bytes representing a single S-expressions, using parser
478
/// options suitable for Emacs Lisp.
479
///
480
/// See [`from_slice_custom`] for more information.
481
///
482
/// [`from_slice_custom`]: fn.from_slice_custom.html
483
0
pub fn from_slice_elisp(bytes: &[u8]) -> Result<Datum> {
484
0
    from_slice_custom(bytes, Options::elisp())
485
0
}
486
487
/// Parse a datum from a string slice representing a single S-expression.
488
///
489
/// ```
490
/// let datum = lexpr::from_str_custom("(a (nested) list)", lexpr::parse::Options::new());
491
/// println!("{:?}", datum);
492
/// ```
493
0
pub fn from_str_custom(s: &str, options: Options) -> Result<Datum> {
494
    // TODO: the use of StrRead (which delegates to SliceRead) is most probably not a good idea,
495
    // since it calculates position information on-demand, leading to O(n^2) complexity.
496
0
    from_trait(read::StrRead::new(s), options)
497
0
}
498
499
/// Parse a datum from a string slice representing a single S-expressions, using
500
/// the default parser options.
501
///
502
/// See [`from_str_custom`] for more information.
503
///
504
/// [`from_str_custom`]: fn.from_str_custom.html
505
0
pub fn from_str(s: &str) -> Result<Datum> {
506
0
    from_str_custom(s, Options::default())
507
0
}
508
509
/// Parse a datum from a string slice representing a single S-expression, using
510
/// parser options suitable for Emacs Lisp.
511
///
512
/// See [`from_str_custom`] for more information.
513
///
514
/// [`from_str_custom`]: fn.from_str_custom.html
515
0
pub fn from_str_elisp(s: &str) -> Result<Datum> {
516
0
    from_str_custom(s, Options::elisp())
517
0
}