jsonpiler 0.9.3

a Json syntax programming language for Windows
Documentation
use crate::prelude::*;
pub(crate) type KeyVal = (WithPos<String>, WithPos<Json>);
#[derive(Debug, Clone)]
pub(crate) enum Json {
  Array(Bind<Vec<WithPos<Json>>>),
  Bool(Bind<bool>),
  Float(Bind<f64>),
  Int(Bind<i64>),
  Null(Bind<()>),
  Object(Bind<Vec<KeyVal>>),
  Str(Bind<String>),
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub(crate) enum JsonType {
  ArrayT,
  BoolT,
  CustomT(String),
  FloatT,
  IntT,
  NullT,
  ObjectT,
  StrT,
}
impl Json {
  pub(crate) fn as_str(&self) -> Option<&str> {
    if let Str(Lit(string)) = self { Some(string) } else { None }
  }
  pub(crate) fn as_type(&self) -> JsonType {
    match self {
      Array(_) => ArrayT,
      Bool(_) => BoolT,
      Float(_) => FloatT,
      Int(_) => IntT,
      Null(_) => NullT,
      Object(_) => ObjectT,
      Str(_) => StrT,
    }
  }
  pub(crate) fn describe(&self) -> String {
    format!(
      "{}{}",
      self.as_type().name(),
      match self {
        Bool(bind) => format!("{bind}"),
        Null(_) => String::new(),
        Float(bind) => format!("{bind}"),
        Object(bind) => format!("{bind}"),
        Int(bind) => format!("{bind}"),
        Str(bind) => format!("{bind}"),
        Array(bind) => format!("{bind}"),
      }
    )
  }
  #[expect(clippy::print_stderr)]
  pub(crate) fn get(&self, key: &str) -> Option<&Json> {
    if let Object(Lit(obj)) = self {
      let opt = obj.iter().find(|(ke, _)| ke.val == key).map(|(_, va)| &va.val);
      if let Some(json) = opt {
        return Some(json);
      }
    }
    eprintln!("{key} failed");
    None
  }
  pub(crate) fn get_int(&self, key: &str) -> Option<i64> {
    if let Int(Lit(int)) = self.get(key)? { Some(*int) } else { None }
  }
  pub(crate) fn into_str(self) -> Option<String> {
    if let Str(Lit(string)) = self { Some(string) } else { None }
  }
  pub(crate) fn memory(&self) -> Option<Memory> {
    match self {
      Int(Var(memory)) | Float(Var(memory)) | Str(Var(memory)) | Bool(Var(memory))
      | Array(Var(memory)) | Null(Var(memory)) | Object(Var(memory)) => Some(*memory),
      Array(_) | Bool(_) | Float(_) | Int(_) | Null(_) | Object(_) | Str(_) => None,
    }
  }
  #[expect(clippy::print_stderr)]
  pub(crate) fn take(&mut self, key: &str) -> Option<Json> {
    if let Object(Lit(obj)) = self {
      let opt = obj.iter_mut().find(|(ke, _)| ke.val == key).map(|(_, va)| &mut va.val);
      if let Some(json) = opt {
        return Some(take(json));
      }
    }
    eprintln!("{key} failed");
    None
  }
}
impl JsonType {
  pub(crate) fn from_string(name: &str) -> Self {
    match name {
      "Str" => StrT,
      "Int" => IntT,
      "Float" => FloatT,
      "Null" => NullT,
      "Bool" => BoolT,
      "Object" => ObjectT,
      "Array" => ArrayT,
      unknown => CustomT(unknown.to_owned()),
    }
  }
  pub(crate) fn mem_type(&self, pos: Position) -> ErrOR<MemoryType> {
    match self {
      BoolT => Ok(Size(1)),
      FloatT | IntT | NullT => Ok(Size(8)),
      StrT => Ok(Heap(None)),
      ArrayT | ObjectT => err!(pos, UnsupportedType(self.name())),
      CustomT(_) => err!(pos, UnknownType(self.name())),
    }
  }
  pub(crate) fn name(&self) -> String {
    match self {
      BoolT => "Bool",
      NullT => "Null",
      FloatT => "Float",
      ObjectT => "Object",
      IntT => "Int",
      StrT => "Str",
      ArrayT => "Array",
      CustomT(name) => name,
    }
    .into()
  }
  pub(crate) fn to_json(&self, pos: Position, addr: Address) -> ErrOR<Json> {
    let memory = Memory(addr, self.mem_type(pos)?);
    match self {
      StrT => Ok(Str(Var(memory))),
      IntT => Ok(Int(Var(memory))),
      FloatT => Ok(Float(Var(memory))),
      NullT => Ok(Null(Var(memory))),
      BoolT => Ok(Bool(Var(memory))),
      ArrayT | ObjectT => err!(pos, UnsupportedType(self.name())),
      CustomT(name) => err!(pos, UnknownType(name.clone())),
    }
  }
}
impl WithPos<Json> {
  pub(crate) fn into_ident(mut self, name: &str) -> ErrOR<WithPos<String>> {
    if let Object(Lit(obj)) = &self.val
      && obj.len() == 1
      && let Some(Str(Lit(string))) = self.val.take("$")
    {
      Ok(self.pos.with(string.clone()))
    } else {
      Err(type_err(name.into(), vec![CustomT("Ident".into())], self.map_ref(Json::as_type)))
    }
  }
}
impl fmt::Display for JsonType {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    f.write_str(&self.name())
  }
}
impl fmt::Display for Json {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match self {
      Array(Lit(array)) => {
        let content = array.iter().map(|item| format!("{}", &item.val));
        write!(f, "[{}]", &content.collect::<Vec<_>>().join(","))
      }
      Bool(Lit(lit)) => lit.fmt(f),
      Int(Lit(lit)) => lit.fmt(f),
      Float(Lit(lit)) => lit.fmt(f),
      Str(Lit(lit)) => lit.fmt(f),
      Object(Lit(obj)) => {
        let content = obj.iter().map(|(key, val)| format!("{}:{}", &key.val, val.val));
        write!(f, "{{{}}}", &content.collect::<Vec<_>>().join(","))
      }
      Null(Lit(())) => write!(f, "null"),
      Null(Var(memory)) | Array(Var(memory)) | Bool(Var(memory)) | Int(Var(memory))
      | Float(Var(memory)) | Str(Var(memory)) | Object(Var(memory)) => memory.fmt(f),
    }
  }
}
impl<T> fmt::Display for Bind<T> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match self {
      Var(memory) => write!(f, "{memory}"),
      Lit(_) => f.write_str(" (Literal)"),
    }
  }
}
impl fmt::Display for Memory {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match self.0 {
      Local(Tmp, _) => Ok(()),
      Local(Long, _) => write!(f, " (Local variable)"),
      Global(_) => write!(f, " (Global variable)"),
    }
  }
}
impl Default for Json {
  fn default() -> Self {
    Null(Lit(()))
  }
}