jsonpiler 0.11.0

a Json syntax programming language for Windows
Documentation
use crate::prelude::*;
pub(crate) struct Formatter {
  pub comment_off: u32,
  pub indentation: u32,
  pub out: String,
}
impl Formatter {
  pub(crate) fn indent(&mut self) {
    self.out.push('\n');
    self.out.push_str(&"  ".repeat(self.indentation as usize));
  }
  pub(crate) fn new() -> Self {
    Formatter { out: String::new(), comment_off: 0, indentation: 0 }
  }
  pub(crate) fn update_indent(&mut self, plus: bool) {
    if plus {
      self.indentation += 1;
    } else {
      self.indentation = self.indentation.saturating_sub(1);
    }
  }
}
impl Pos<Parser> {
  pub(crate) fn comment(&self, fmter: &mut Formatter, offset: u32, default_indent: bool) {
    if self.val.comments.range(fmter.comment_off..=offset).next().is_none() {
      if default_indent {
        fmter.indent();
      }
      return;
    }
    let mut comments = self.val.comments.range(fmter.comment_off..=offset).clone().peekable();
    if let Some((_, comment)) = comments.peek() {
      if comment.leading {
        fmter.indent();
      } else {
        fmter.out.push(' ');
      }
    }
    for (_, comment) in comments {
      fmter.out.push_str(&comment.text);
      fmter.indent();
    }
    fmter.comment_off = offset;
  }
  pub(crate) fn comment_sep(&self, fmter: &mut Formatter, size: u32, offset: u32) {
    if size < LINE_MAX {
      fmter.out.push(' ');
    }
    self.comment(fmter, offset, size >= LINE_MAX);
  }
  pub(crate) fn format(&mut self, path: &str) -> Option<String> {
    let mut fmter = Formatter::new();
    let parsed = self.parse_jspl(path).ok()?;
    let size = self.sizeof_json(&parsed)?;
    for (_, comment) in self.val.comments.range(fmter.comment_off..=parsed.pos.offset) {
      fmter.out.push_str(&comment.text);
      fmter.out.push('\n');
    }
    fmter.comment_off = parsed.pos.offset;
    if matches!(parsed.val, Null(Lit(()))) {
      self.comment(&mut fmter, self.pos.end(), false);
      return Some(String::new());
    } else if let Object(Lit(object)) = parsed.val {
      self.format_block(&mut fmter, &object, size)?;
    } else {
      self.format_json(&mut fmter, &parsed)?;
    }
    self.comment(&mut fmter, self.pos.offset, true);
    Some(fmter.out)
  }
  pub(crate) fn format_array(
    &self,
    fmter: &mut Formatter,
    size: u32,
    pos: Position,
    array: &[Pos<Json>],
  ) -> Option<()> {
    fmter.out.push('[');
    for (idx, item) in array.iter().enumerate() {
      if idx != 0 {
        fmter.out.push(',');
      }
      self.format_json_sep(fmter, size, item)?;
    }
    if !array.is_empty() {
      self.comment_sep(fmter, size, pos.end() - 1);
    }
    fmter.out.push(']');
    Some(())
  }
  pub(crate) fn format_json(&self, fmter: &mut Formatter, json: &Pos<Json>) -> Option<()> {
    let size = self.sizeof_json(json)? + fmter.indentation * 2;
    match &json.val {
      Null(Lit(())) | Int(Lit(_)) | Bool(Lit(_)) | Str(Lit(_)) | Float(Lit(_)) => {
        fmter.out.push_str(self.get_slice(json.pos).ok()?);
      }
      Array(_, Lit(array)) => self.format_array(fmter, size, json.pos, array)?,
      Object(Lit(object)) => self.format_object(fmter, size, json.pos, object)?,
      Null(Var(_))
      | Int(Var(_))
      | Str(Var(_))
      | Object(Var(_))
      | Array(_, Var(_))
      | Bool(Var(_))
      | Float(Var(_)) => return None,
    }
    Some(())
  }
  pub(crate) fn format_json_sep(
    &self,
    fmter: &mut Formatter,
    size: u32,
    json: &Pos<Json>,
  ) -> Option<()> {
    let val_size = (fmter.indentation + 1) * 2 + self.sizeof_json(json)?;
    let do_indent = val_size < LINE_MAX || !json.val.is_block();
    if do_indent {
      self.with_indent(fmter, true, |_fmter| {
        self.comment_sep(_fmter, size, json.pos.offset + 1);
        Some(())
      });
    } else {
      self.comment_sep(fmter, size, json.pos.offset + 1);
    }
    self.with_indent(fmter, true, |_fmter| self.format_json(_fmter, json));
    Some(())
  }
  pub(crate) fn sizeof_json(&self, json: &Pos<Json>) -> Option<u32> {
    match &json.val {
      Null(Lit(())) | Int(Lit(_)) | Bool(Lit(_)) | Float(Lit(_)) | Str(Lit(_)) => {
        Some(json.pos.size)
      }
      Array(_, Lit(array)) => sizeof_container(array, |item| self.sizeof_json(item)),
      Object(Lit(object)) => {
        if object.len() == 1 {
          self.sizeof_key_val(&object[0])
        } else {
          sizeof_container(object, |key_val| self.sizeof_key_val(key_val))
        }
      }
      Null(_) | Array(..) | Bool(_) | Float(_) | Int(_) | Object(_) | Str(_) => None,
    }
  }
  pub(crate) fn with_indent<F: FnOnce(&mut Formatter) -> Option<()>>(
    &self,
    fmter: &mut Formatter,
    plus: bool,
    fmt_f: F,
  ) -> Option<()> {
    fmter.update_indent(plus);
    let result = fmt_f(fmter);
    fmter.update_indent(!plus);
    result
  }
}
pub(crate) fn sizeof_container<T, F: Fn(&T) -> Option<u32>>(
  container: &[T],
  sizeof_f: F,
) -> Option<u32> {
  container.iter().try_fold(2, |acc, item| Some(acc + sizeof_f(item)? + 2))
}