diff --git a/Cargo.lock b/Cargo.lock index 13cd67d69f..9c88ebb2f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1229,6 +1229,9 @@ dependencies = [ "leo-parser", "leo-passes", "leo-span", + "leo-test-framework", + "serde", + "serde_yaml", "sha2", ] diff --git a/compiler/ast/src/input/input_ast.rs b/compiler/ast/src/input/input_ast.rs index f5c6d9658f..be83f33f52 100644 --- a/compiler/ast/src/input/input_ast.rs +++ b/compiler/ast/src/input/input_ast.rs @@ -14,8 +14,10 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . +use crate::{normalize_json_value, remove_key_from_json}; + use super::*; -use leo_errors::AstError; +use leo_errors::{AstError, Result}; /// Input data which includes [`ProgramInput`] and [`ProgramState`]. #[derive(Debug, Clone, Default, Serialize, Deserialize)] @@ -31,6 +33,34 @@ pub struct ParsedInputFile { pub sections: Vec
, } +impl ParsedInputFile { + /// Serializes the `ParsedInputFile` into a JSON Value. + pub fn to_json_value(&self) -> Result { + Ok(serde_json::to_value(&self).map_err(|e| AstError::failed_to_convert_ast_to_json_value(&e))?) + } + + /// Serializes the `ParsedInputFile` into a JSON value and removes keys from object mappings before writing to a file. + 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))?) + } +} + impl Input { /// Serializes the ast into a JSON string. pub fn to_json_string(&self) -> Result { diff --git a/compiler/ast/src/lib.rs b/compiler/ast/src/lib.rs index 2b2b82cd16..64adaed260 100644 --- a/compiler/ast/src/lib.rs +++ b/compiler/ast/src/lib.rs @@ -144,7 +144,7 @@ impl AsRef for Ast { } /// Helper function to recursively filter keys from AST JSON -fn remove_key_from_json(value: serde_json::Value, key: &str) -> serde_json::Value { +pub(crate) 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() @@ -165,7 +165,7 @@ fn remove_key_from_json(value: serde_json::Value, key: &str) -> serde_json::Valu /// 1. Remove empty object mappings from JSON arrays /// 2. If there are two elements in a JSON array and one is an empty object /// mapping and the other is not, then lift up the one that isn't -fn normalize_json_value(value: serde_json::Value) -> serde_json::Value { +pub(crate) fn normalize_json_value(value: serde_json::Value) -> serde_json::Value { match value { serde_json::Value::Array(vec) => { let orig_length = vec.len(); diff --git a/compiler/compiler/src/lib.rs b/compiler/compiler/src/lib.rs index 0de90b387d..4974481db1 100644 --- a/compiler/compiler/src/lib.rs +++ b/compiler/compiler/src/lib.rs @@ -76,7 +76,7 @@ impl<'a> Compiler<'a> { /// /// Runs the compiler stages. /// - fn compiler_stages(&self) -> Result { + fn compiler_stages(&self, program_string: &str) -> Result { //load the input file if it exists. if let Some(input_file_path) = self.input_file_path.as_ref() { let _input_ast = if input_file_path.exists() { @@ -93,10 +93,6 @@ impl<'a> Compiler<'a> { }; } - // Load the program file. - let program_string = fs::read_to_string(&self.main_file_path) - .map_err(|e| CompilerError::file_read_error(self.main_file_path.clone(), e))?; - // Use the parser to construct the abstract syntax tree (ast). let ast: leo_ast::Ast = leo_parser::parse_ast( self.handler, @@ -116,10 +112,21 @@ impl<'a> Compiler<'a> { Ok(ast) } + /// Parses and stores the main program file, constructs a syntax tree, and generates a program. + /// + /// Parses and stores all programs imported by the main program file. + pub fn parse_program(&self) -> Result { + // Load the program file. + let program_string = fs::read_to_string(&self.main_file_path) + .map_err(|e| CompilerError::file_read_error(self.main_file_path.clone(), e))?; + + self.compiler_stages(&program_string) + } + /// /// Returns a compiled Leo program. /// pub fn compile(&self) -> Result { - create_session_if_not_set_then(|_| self.compiler_stages()) + create_session_if_not_set_then(|_| self.parse_program()) } } diff --git a/compiler/compiler/src/test.rs b/compiler/compiler/src/test.rs index a0515dc80c..ef871fd127 100644 --- a/compiler/compiler/src/test.rs +++ b/compiler/compiler/src/test.rs @@ -77,8 +77,7 @@ impl Namespace for CompileNamespace { let handler = Handler::new(Box::new(err_buf.clone())); create_session_if_not_set_then(|_| { - // run_test(test, &handler, &err_buf).map_err(|()| err_buf.0.take().to_string()) - Err("todo".to_string()) + run_test(test, &handler, &err_buf).map_err(|()| err_buf.0.take().to_string()) }) } } @@ -220,7 +219,7 @@ fn run_test(test: Test, handler: &Handler, err_buf: &BufferEmitter) -> Result { functions: IndexMap, variables: VariableSymbol<'a>, diff --git a/compiler/passes/src/symbol_table/variable_symbol.rs b/compiler/passes/src/symbol_table/variable_symbol.rs index 9f453b84d1..8f172656b6 100644 --- a/compiler/passes/src/symbol_table/variable_symbol.rs +++ b/compiler/passes/src/symbol_table/variable_symbol.rs @@ -19,7 +19,7 @@ use leo_ast::{DefinitionStatement, FunctionInput, FunctionInputVariable}; use leo_errors::{AstError, Result}; use leo_span::Symbol; -#[derive(Debug, Default)] +#[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct VariableSymbol<'a> { parent: Option>>, inputs: IndexMap, diff --git a/leo/commands/build.rs b/leo/commands/build.rs index 3996c17dcf..176243e074 100644 --- a/leo/commands/build.rs +++ b/leo/commands/build.rs @@ -180,7 +180,7 @@ impl Command for Build { // Initialize error handler let handler = leo_errors::emitter::Handler::default(); - let program = Compiler::new(&handler, main_file_path, output_directory, input_path.to_path_buf()); + let program = Compiler::new(&handler, main_file_path, output_directory); // Compute the current program checksum let program_checksum = program.checksum()?;