use crate::ast::{Token, Value};
use crate::error::{Error, Result, Span};
use crate::lazy::{LazyParser, LazyValue};
use rustc_hash::FxHashMap;
use std::sync::Arc;
#[derive(Debug, Clone)]
pub struct LazyObject {
pub(super) fields: FxHashMap<String, LazyValue>,
#[allow(dead_code)]
pub(super) input: Arc<str>,
#[allow(dead_code)]
pub(super) options: crate::parser::ParserOptions,
}
impl LazyObject {
pub fn new(input: Arc<str>, options: crate::parser::ParserOptions) -> Self {
LazyObject {
fields: FxHashMap::default(),
input,
options,
}
}
pub fn insert(&mut self, key: String, value: LazyValue) {
self.fields.insert(key, value);
}
pub fn get(&self, key: &str) -> Option<Result<Value>> {
self.fields.get(key).map(|lazy_val| lazy_val.evaluate())
}
pub fn get_lazy(&self, key: &str) -> Option<&LazyValue> {
self.fields.get(key)
}
pub fn keys(&self) -> impl Iterator<Item = &String> {
self.fields.keys()
}
pub fn contains_key(&self, key: &str) -> bool {
self.fields.contains_key(key)
}
pub fn evaluate_all(&self) -> Result<Value> {
let mut resolved_obj = FxHashMap::default();
for (key, lazy_val) in &self.fields {
resolved_obj.insert(key.clone(), lazy_val.evaluate()?);
}
Ok(Value::Object(resolved_obj))
}
}
impl<'a> LazyParser<'a> {
pub(super) fn parse_object(&mut self, _start_span: Span) -> Result<Value> {
self.parse_object_immediate()
}
pub(super) fn parse_object_immediate(&mut self) -> Result<Value> {
let mut object = FxHashMap::default();
let mut first = true;
loop {
loop {
let (next_token, _) = self.peek_token()?;
if next_token == Token::Newline {
self.next_token()?;
} else {
break;
}
}
let (next_token, _) = self.peek_token()?;
if next_token == Token::RightBrace {
self.next_token()?;
break;
}
if !first {
let (token, span) = self.next_token()?;
match token {
Token::Comma => {}
Token::Newline if self.options.newline_as_comma => {}
Token::RightBrace if self.options.allow_trailing_commas => break,
_ => {
return Err(Error::Expected {
expected: "comma or }".to_string(),
found: format!("{token:?}"),
position: span.start,
});
}
}
}
first = false;
let (key_token, key_span) = self.next_token()?;
let key = match key_token {
Token::String => self.parse_string_content(key_span)?,
Token::UnquotedString if self.options.allow_unquoted_keys => {
self.input[key_span.start..key_span.end].to_string()
}
_ => {
return Err(Error::Expected {
expected: "string key".to_string(),
found: format!("{key_token:?}"),
position: key_span.start,
});
}
};
let (colon_token, colon_span) = self.next_token()?;
match colon_token {
Token::Colon => {}
_ => {
return Err(Error::Expected {
expected: "colon".to_string(),
found: format!("{colon_token:?}"),
position: colon_span.start,
});
}
}
let (value_token, value_span) = self.next_token()?;
let value = self.parse_value(value_token, value_span)?;
object.insert(key, value);
}
Ok(Value::Object(object))
}
}