/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 | } |