mod program_scope;
pub use program_scope::*;
use leo_errors::{AstError, Result};
use leo_span::Symbol;
use crate::{Module, ProgramId, Stub};
use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct Program {
pub modules: IndexMap<Vec<Symbol>, Module>,
pub imports: IndexMap<Symbol, ProgramId>,
pub stubs: IndexMap<Symbol, Stub>,
pub program_scopes: IndexMap<Symbol, ProgramScope>,
}
impl fmt::Display for Program {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (_, stub) in self.stubs.iter() {
writeln!(f, "{stub}")?;
}
for (_, module) in self.modules.iter() {
writeln!(f, "{module}")?;
}
for (_, import_id) in self.imports.iter() {
writeln!(f, "import {import_id};")?;
}
for (_, program_scope) in self.program_scopes.iter() {
writeln!(f, "{program_scope}")?;
}
Ok(())
}
}
impl Default for Program {
fn default() -> Self {
Self {
modules: IndexMap::new(),
imports: IndexMap::new(),
stubs: IndexMap::new(),
program_scopes: IndexMap::new(),
}
}
}
impl Program {
pub fn to_json_string(&self) -> Result<String> {
Ok(serde_json::to_string_pretty(&self).map_err(|e| AstError::failed_to_convert_ast_to_json_string(&e))?)
}
pub fn to_json_value(&self) -> Result<serde_json::Value> {
Ok(serde_json::to_value(self).map_err(|e| AstError::failed_to_convert_ast_to_json_value(&e))?)
}
pub fn to_json_file(&self, mut path: std::path::PathBuf, file_name: &str) -> Result<()> {
path.push(file_name);
let file = std::fs::File::create(&path).map_err(|e| AstError::failed_to_create_ast_json_file(&path, &e))?;
let writer = std::io::BufWriter::new(file);
Ok(serde_json::to_writer_pretty(writer, &self)
.map_err(|e| AstError::failed_to_write_ast_to_json_file(&path, &e))?)
}
pub fn to_json_file_without_keys(
&self,
mut path: std::path::PathBuf,
file_name: &str,
excluded_keys: &[&str],
) -> Result<()> {
path.push(file_name);
let file = std::fs::File::create(&path).map_err(|e| AstError::failed_to_create_ast_json_file(&path, &e))?;
let writer = std::io::BufWriter::new(file);
let mut value = self.to_json_value().unwrap();
for key in excluded_keys {
value = remove_key_from_json(value, key);
}
value = normalize_json_value(value);
Ok(serde_json::to_writer_pretty(writer, &value)
.map_err(|e| AstError::failed_to_write_ast_to_json_file(&path, &e))?)
}
pub fn from_json_string(json: &str) -> Result<Self> {
let ast: Program = serde_json::from_str(json).map_err(|e| AstError::failed_to_read_json_string_to_ast(&e))?;
Ok(ast)
}
pub fn from_json_file(path: std::path::PathBuf) -> Result<Self> {
let data = std::fs::read_to_string(&path).map_err(|e| AstError::failed_to_read_json_file(&path, &e))?;
Self::from_json_string(&data)
}
}
pub fn remove_key_from_json(value: serde_json::Value, key: &str) -> serde_json::Value {
match value {
serde_json::Value::Object(map) => serde_json::Value::Object(
map.into_iter().filter(|(k, _)| k != key).map(|(k, v)| (k, remove_key_from_json(v, key))).collect(),
),
serde_json::Value::Array(values) => {
serde_json::Value::Array(values.into_iter().map(|v| remove_key_from_json(v, key)).collect())
}
_ => value,
}
}
pub fn normalize_json_value(value: serde_json::Value) -> serde_json::Value {
match value {
serde_json::Value::Array(vec) => {
let orig_length = vec.len();
let mut new_vec: Vec<serde_json::Value> = vec
.into_iter()
.filter(|v| !matches!(v, serde_json::Value::Object(map) if map.is_empty()))
.map(normalize_json_value)
.collect();
if orig_length == 2 && new_vec.len() == 1 {
new_vec.pop().unwrap()
} else {
serde_json::Value::Array(new_vec)
}
}
serde_json::Value::Object(map) => {
serde_json::Value::Object(map.into_iter().map(|(k, v)| (k, normalize_json_value(v))).collect())
}
_ => value,
}
}