#![cfg(not(feature = "no_object"))]
use crate::parser::{ParseSettingFlags, ParseState};
use crate::tokenizer::Token;
use crate::types::dynamic::Union;
use crate::{Dynamic, Engine, LexError, Map, RhaiResultOf};
use std::fmt::Write;
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
impl Engine {
#[inline]
pub fn parse_json(&self, json: impl AsRef<str>, has_null: bool) -> RhaiResultOf<Map> {
let scripts = [json.as_ref()];
let (stream, tokenizer_control) = self.lex_raw(
&scripts,
Some(if has_null {
&|token, _, _| {
match token {
Token::Reserved(s) if &*s == "null" => Token::Unit,
Token::LeftBrace => Token::MapStart,
t @ (Token::Unit | Token::MapStart) => Token::LexError(
LexError::ImproperSymbol(t.literal_syntax().to_string(), String::new())
.into(),
),
Token::InterpolatedString(..) => Token::LexError(
LexError::ImproperSymbol(
"interpolated string".to_string(),
String::new(),
)
.into(),
),
_ => token,
}
}
} else {
&|token, _, _| {
match token {
Token::Reserved(s) if &*s == "null" => Token::LexError(
LexError::ImproperSymbol("null".to_string(), String::new()).into(),
),
Token::LeftBrace => Token::MapStart,
t @ (Token::Unit | Token::MapStart) => Token::LexError(
LexError::ImproperSymbol(t.literal_syntax().to_string(), String::new())
.into(),
),
Token::InterpolatedString(..) => Token::LexError(
LexError::ImproperSymbol(
"interpolated string".to_string(),
String::new(),
)
.into(),
),
_ => token,
}
}
}),
);
let ast = {
let input = &mut stream.peekable();
let lib = &mut <_>::default();
let state = ParseState::new(None, input, tokenizer_control, lib);
self.parse_global_expr(
state,
|s| s.flags |= ParseSettingFlags::DISALLOW_UNQUOTED_MAP_PROPERTIES,
#[cfg(not(feature = "no_optimize"))]
crate::OptimizationLevel::None,
)?
};
self.eval_ast(&ast)
}
}
#[inline]
#[must_use]
pub fn format_map_as_json(map: &Map) -> String {
let mut result = String::from('{');
for (key, value) in map {
if result.len() > 1 {
result += ",";
}
write!(result, "{key:?}").unwrap();
result += ":";
format_dynamic_as_json(&mut result, value);
}
result += "}";
result
}
fn format_dynamic_as_json(result: &mut String, value: &Dynamic) {
match value.0 {
Union::Unit(..) => *result += "null",
Union::FnPtr(ref f, _, _) if f.is_curried() => {
*result += "[";
write!(result, "{:?}", f.fn_name()).unwrap();
f.iter_curry().for_each(|value| {
*result += ",";
format_dynamic_as_json(result, value);
});
*result += "]";
}
Union::FnPtr(ref f, _, _) => write!(result, "{:?}", f.fn_name()).unwrap(),
Union::Map(ref m, ..) => *result += &format_map_as_json(m),
#[cfg(not(feature = "no_index"))]
Union::Array(ref a, _, _) => {
*result += "[";
for (i, x) in a.iter().enumerate() {
if i > 0 {
*result += ",";
}
format_dynamic_as_json(result, x);
}
*result += "]";
}
#[cfg(not(feature = "no_index"))]
Union::Blob(ref b, _, _) => {
*result += "[";
for (i, x) in b.iter().enumerate() {
if i > 0 {
*result += ",";
}
write!(result, "{x}").unwrap();
}
*result += "]";
}
#[cfg(not(feature = "no_closure"))]
Union::Shared(ref v, _, _) => {
let value = &*crate::func::locked_read(v).unwrap();
format_dynamic_as_json(result, value)
}
_ => write!(result, "{value:?}").unwrap(),
}
}