lib.rs
1 // Copyright (C) 2019-2025 ADnet Contributors 2 // This file is part of the ADL library. 3 4 // The ADL library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 9 // The ADL library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 14 // You should have received a copy of the GNU General Public License 15 // along with the ADL library. If not, see <https://www.gnu.org/licenses/>. 16 17 //! The abstract syntax tree (ast) for a ADL program. 18 //! 19 //! This module contains the [`Ast`] type, a wrapper around the [`Program`] type. 20 //! The [`Ast`] type is intended to be parsed and modified by different passes 21 //! of the ADL compiler. The ADL compiler can generate a set of R1CS constraints from any [`Ast`]. 22 23 #![allow(ambiguous_glob_reexports)] 24 25 mod composite; 26 pub use self::composite::*; 27 28 pub mod common; 29 pub use self::common::*; 30 31 pub mod constructor; 32 pub use self::constructor::*; 33 34 mod expressions; 35 pub use self::expressions::*; 36 37 mod functions; 38 pub use self::functions::*; 39 40 mod indent_display; 41 use indent_display::*; 42 43 pub mod interpreter_value; 44 45 mod mapping; 46 pub use self::mapping::*; 47 48 mod module; 49 pub use self::module::*; 50 51 mod passes; 52 pub use self::passes::*; 53 54 mod program; 55 pub use self::program::*; 56 57 mod statement; 58 pub use self::statement::*; 59 60 mod storage; 61 pub use self::storage::*; 62 63 mod types; 64 pub use self::types::*; 65 66 mod stub; 67 pub use self::stub::*; 68 69 pub use common::node::*; 70 71 use adl_errors::{AstError, Result}; 72 73 /// The abstract syntax tree (AST) for a ADL program. 74 /// 75 /// The [`Ast`] type represents a ADL program as a series of recursive data types. 76 /// These data types form a tree that begins from a [`Program`] type root. 77 #[derive(Clone, Debug, Default, Eq, PartialEq)] 78 pub struct Ast { 79 pub ast: Program, 80 } 81 82 impl Ast { 83 /// Creates a new AST from a given program tree. 84 pub fn new(program: Program) -> Self { 85 Self { ast: program } 86 } 87 88 /// Returns a reference to the inner program AST representation. 89 pub fn as_repr(&self) -> &Program { 90 &self.ast 91 } 92 93 pub fn into_repr(self) -> Program { 94 self.ast 95 } 96 97 /// Serializes the ast into a JSON string. 98 pub fn to_json_string(&self) -> Result<String> { 99 Ok(serde_json::to_string_pretty(&self.ast).map_err(|e| AstError::failed_to_convert_ast_to_json_string(&e))?) 100 } 101 102 // Converts the ast into a JSON value. 103 // Note that there is no corresponding `from_json_value` function 104 // since we modify JSON values leaving them unable to be converted 105 // back into Programs. 106 pub fn to_json_value(&self) -> Result<serde_json::Value> { 107 Ok(serde_json::to_value(&self.ast).map_err(|e| AstError::failed_to_convert_ast_to_json_value(&e))?) 108 } 109 110 /// Serializes the ast into a JSON file. 111 pub fn to_json_file(&self, mut path: std::path::PathBuf, file_name: &str) -> Result<()> { 112 path.push(file_name); 113 let file = std::fs::File::create(&path).map_err(|e| AstError::failed_to_create_ast_json_file(&path, &e))?; 114 let writer = std::io::BufWriter::new(file); 115 Ok(serde_json::to_writer_pretty(writer, &self.ast) 116 .map_err(|e| AstError::failed_to_write_ast_to_json_file(&path, &e))?) 117 } 118 119 /// Serializes the ast into a JSON value and removes keys from object mappings before writing to a file. 120 pub fn to_json_file_without_keys( 121 &self, 122 mut path: std::path::PathBuf, 123 file_name: &str, 124 excluded_keys: &[&str], 125 ) -> Result<()> { 126 path.push(file_name); 127 let file = std::fs::File::create(&path).map_err(|e| AstError::failed_to_create_ast_json_file(&path, &e))?; 128 let writer = std::io::BufWriter::new(file); 129 130 let mut value = self.to_json_value().unwrap(); 131 for key in excluded_keys { 132 value = remove_key_from_json(value, key); 133 } 134 value = normalize_json_value(value); 135 136 Ok(serde_json::to_writer_pretty(writer, &value) 137 .map_err(|e| AstError::failed_to_write_ast_to_json_file(&path, &e))?) 138 } 139 140 /// Deserializes the JSON string into a ast. 141 pub fn from_json_string(json: &str) -> Result<Self> { 142 let ast: Program = serde_json::from_str(json).map_err(|e| AstError::failed_to_read_json_string_to_ast(&e))?; 143 Ok(Self { ast }) 144 } 145 146 /// Deserializes the JSON string into a ast from a file. 147 pub fn from_json_file(path: std::path::PathBuf) -> Result<Self> { 148 let data = std::fs::read_to_string(&path).map_err(|e| AstError::failed_to_read_json_file(&path, &e))?; 149 Self::from_json_string(&data) 150 } 151 } 152 153 impl AsRef<Program> for Ast { 154 fn as_ref(&self) -> &Program { 155 &self.ast 156 } 157 } 158 159 /// Helper function to recursively filter keys from AST JSON 160 pub fn remove_key_from_json(value: serde_json::Value, key: &str) -> serde_json::Value { 161 match value { 162 serde_json::Value::Object(map) => serde_json::Value::Object( 163 map.into_iter().filter(|(k, _)| k != key).map(|(k, v)| (k, remove_key_from_json(v, key))).collect(), 164 ), 165 serde_json::Value::Array(values) => { 166 serde_json::Value::Array(values.into_iter().map(|v| remove_key_from_json(v, key)).collect()) 167 } 168 _ => value, 169 } 170 } 171 172 /// Helper function to normalize AST JSON into a form compatible with tgc. 173 /// This function will traverse the original JSON value and produce a new 174 /// one under the following rules: 175 /// 1. Remove empty object mappings from JSON arrays 176 /// 2. If there are two elements in a JSON array and one is an empty object 177 /// mapping and the other is not, then lift up the one that isn't 178 pub fn normalize_json_value(value: serde_json::Value) -> serde_json::Value { 179 match value { 180 serde_json::Value::Array(vec) => { 181 let orig_length = vec.len(); 182 let mut new_vec: Vec<serde_json::Value> = vec 183 .into_iter() 184 .filter(|v| !matches!(v, serde_json::Value::Object(map) if map.is_empty())) 185 .map(normalize_json_value) 186 .collect(); 187 188 if orig_length == 2 && new_vec.len() == 1 { 189 new_vec.pop().unwrap() 190 } else { 191 serde_json::Value::Array(new_vec) 192 } 193 } 194 serde_json::Value::Object(map) => { 195 serde_json::Value::Object(map.into_iter().map(|(k, v)| (k, normalize_json_value(v))).collect()) 196 } 197 _ => value, 198 } 199 }