///|
/// Parse a NestedText document string.
///
/// # Parameters
/// * `input` — The NestedText source text.
/// * `top` — Constrains the expected top-level shape. Pass `Top::Any` when the
/// structure is not known ahead of time.
///
/// # Returns
/// * `Ok(None)` — The document is empty and `top` is `Top::Any`.
/// * `Ok(Some(v))` — Successful parse. The returned `Value` matches
/// the constraint given by `top`.
/// * `Err(e)` — A `NestedTextError` describing the parse failure.
pub fn loads(input : String, top : Top) -> Result[Value?, NestedTextError] {
if input.contains("\u{FFFD}") {
let parts = input.split("\n")
for lineno, part in parts {
let line : String = part.to_owned()
let found = line.find("\u{FFFD}")
match found {
Some(p) => {
let prefix = line.unsafe_substring(start=0, end=p)
let colno = prefix.char_length() + 1
return Err(
NestedTextError::at(
UnrecognizedLine,
"input contains invalid UTF-8",
lineno + 1,
colno,
line,
),
)
}
None => continue
}
}
}
let lexer_result = Lexer::from_string(input)
match lexer_result {
Err(err) => Err(err)
Ok(lexer) => {
let parser = Parser::new(lexer)
let parsed = parser.read_value(0)
match parsed {
Err(err) => Err(err)
Ok(value) =>
match value {
Some(_) =>
match parser.lexer.peek() {
Some(line) =>
if line.depth > 0 &&
parser.all_indent_levels.length() > 1 &&
!parser.all_indent_levels.contains(line.depth) {
Err(
NestedTextError::at(
InvalidIndentLevel,
"invalid indentation, partial dedent.",
line.lineno,
1,
line.text,
),
)
} else {
Err(
NestedTextError::at(
UnexpectedLineType,
"extra content.",
line.lineno,
1,
line.text,
),
)
}
None => finish_top(value, top)
}
None => finish_top(value, top)
}
}
}
}
}
///|
fn finish_top(value : Value?, top : Top) -> Result[Value?, NestedTextError] {
match (value, top) {
(None, Top::Any) => Ok(None)
(None, Top::Dict) => Ok(Some(Value::Dict([])))
(None, Top::List) => Ok(Some(Value::List([])))
(None, Top::String) => Ok(Some(Value::String("")))
(Some(v), Top::Any) => Ok(Some(v))
(Some(Value::Dict(_) as v), Top::Dict) => Ok(Some(v))
(Some(Value::List(_) as v), Top::List) => Ok(Some(v))
(Some(Value::String(_) as v), Top::String) => Ok(Some(v))
(Some(_), Top::Dict) =>
Err(
NestedTextError::new(
UnexpectedLineType,
"expected dictionary top-level.",
),
)
(Some(_), Top::List) =>
Err(NestedTextError::new(UnexpectedLineType, "expected list top-level."))
(Some(_), Top::String) =>
Err(
NestedTextError::new(UnexpectedLineType, "expected string top-level."),
)
}
}