Skip to main content

substrate_data/forms/text/parser/
entry.rs

1//! The ways in: a document with its spans, a bare value, a borrowed value.
2
3use bumpalo::Bump;
4
5use super::borrowed::Borrowed;
6use super::build::{Build, Failure};
7use super::owned::Owned;
8use super::parser::Parser;
9use crate::forms::text::{Doc, Spans, SyntaxError};
10use crate::model::borrowed::ValueRef;
11use crate::model::value::Value;
12
13/// Deeper than this is an error, not a stack overflow.
14pub const MAX_DEPTH: usize = 256;
15
16/// Parses text.
17///
18/// # Errors
19///
20/// [`SyntaxError`] when the text doesn't parse.
21pub fn parse(text: &str) -> Result<Doc, SyntaxError> {
22    let (value, spans) = run::<Owned, true>(text, Owned::default())?;
23    Ok(Doc { value, spans })
24}
25
26/// Parses text, without the positions (faster).
27///
28/// # Errors
29///
30/// [`SyntaxError`] when the text doesn't parse.
31pub fn parse_value(text: &str) -> Result<Value, SyntaxError> {
32    run::<Owned, false>(text, Owned::default()).map(|(v, _)| v)
33}
34
35/// Parses text straight to a borrowed value, the way a schema reads it: no
36/// positions, and nothing is allocated on the heap per value — strings
37/// without escapes point into `text`, lists and maps are in `arena`.
38///
39/// # Errors
40///
41/// [`SyntaxError`] when the text doesn't parse.
42///
43/// ```
44/// let arena = substrate_data::Bump::new();
45/// let v = substrate_data::text::parse_ref(r#"{ name: "docs", pages: [1, 2] }"#, &arena).unwrap();
46/// assert_eq!(v.get("name").and_then(|n| n.as_str()), Some("docs"));
47/// ```
48pub fn parse_ref<'a>(text: &'a str, arena: &'a Bump) -> Result<ValueRef<'a>, SyntaxError> {
49    run::<Borrowed<'a>, false>(text, Borrowed::new(arena)).map(|(v, _)| v)
50}
51
52fn run<'t, B: Build<'t>, const SPANS: bool>(
53    text: &'t str,
54    builder: B,
55) -> Result<(B::Value, Spans), SyntaxError> {
56    parse_all::<B, SPANS>(text, builder).map_err(Failure::into_inner)
57}
58
59fn parse_all<'t, B: Build<'t>, const SPANS: bool>(
60    text: &'t str,
61    builder: B,
62) -> Result<(B::Value, Spans), Failure> {
63    let mut p = Parser::<B, SPANS>::new(text, builder);
64    if text.starts_with('\u{feff}') {
65        p.skip(3);
66    }
67    p.ws()?;
68    let mut root = Vec::new();
69    let value = p.value(None, &mut root)?;
70    p.ws()?;
71    if !p.at_end() {
72        return Err(p.error("unexpected text after the value"));
73    }
74    Ok((value, root.pop().unwrap_or_default()))
75}