diff --git a/ast/Cargo.toml b/ast/Cargo.toml index 8a1eea319d..7050904de1 100644 --- a/ast/Cargo.toml +++ b/ast/Cargo.toml @@ -4,6 +4,10 @@ version = "0.1.0" authors = ["The Aleo Team "] edition = "2018" +[[bin]] +name = "leo_ast" +path = "src/main.rs" + [dependencies] from-pest = { version = "0.3.1" } lazy_static = { version = "1.3.0" } diff --git a/ast/src/errors/parser.rs b/ast/src/errors/parser.rs index fa5c985a66..c0726896cc 100644 --- a/ast/src/errors/parser.rs +++ b/ast/src/errors/parser.rs @@ -11,6 +11,9 @@ pub enum ParserError { #[error("Cannot read from the provided file path - {:?}", _0)] FileReadError(PathBuf), + #[error("{}", _0)] + JsonError(#[from] serde_json::error::Error), + #[error("{}", _0)] SyntaxError(#[from] SyntaxError), diff --git a/ast/src/lib.rs b/ast/src/lib.rs index 784413208e..7907a140dd 100644 --- a/ast/src/lib.rs +++ b/ast/src/lib.rs @@ -32,16 +32,16 @@ use std::{fs, path::PathBuf}; pub struct LeoParser; impl LeoParser { - /// Reads in the given file path into a string. + /// Loads the Leo code as a string from the given file path. pub fn load_file(file_path: &PathBuf) -> Result { Ok(fs::read_to_string(file_path).map_err(|_| ParserError::FileReadError(file_path.clone()))?) } - /// Parses the input file and constructs a syntax tree. - pub fn parse_file<'a>(file_path: &'a PathBuf, input_file: &'a str) -> Result, ParserError> { + /// Parses the Leo program string and constructs an abstract syntax tree. + pub fn parse_file<'a>(file_path: &'a PathBuf, program_string: &'a str) -> Result, ParserError> { // Parse the file using leo.pest - let mut file = - ast::parse(input_file).map_err(|error| ParserError::from(error.with_path(file_path.to_str().unwrap())))?; + let mut file = ast::parse(program_string) + .map_err(|error| ParserError::from(error.with_path(file_path.to_str().unwrap())))?; // Build the abstract syntax tree let syntax_tree = files::File::from_pest(&mut file).map_err(|_| ParserError::SyntaxTreeError)?; @@ -50,13 +50,8 @@ impl LeoParser { Ok(syntax_tree) } - /// Serializes and stores a given syntax tree in the output file. - pub fn store_syntax_tree<'a>(syntax_tree: files::File<'a>, output_file: &'a str) -> Result<(), ParserError> { - // Serialize and store the syntax tree to the given filepath. - let serialized_syntax_tree = serde_json::to_string(&syntax_tree).unwrap(); - println!("serialized = {}", serialized_syntax_tree); - fs::write(output_file, serialized_syntax_tree)?; - - Ok(()) + /// Serializes a given abstract syntax tree into a JSON string. + pub fn to_json_string(syntax_tree: &files::File) -> Result { + Ok(serde_json::to_string_pretty(syntax_tree)?) } } diff --git a/ast/src/main.rs b/ast/src/main.rs new file mode 100644 index 0000000000..9c288c18d2 --- /dev/null +++ b/ast/src/main.rs @@ -0,0 +1,50 @@ +use leo_ast::{LeoParser, ParserError}; +use std::{env, fs, path::Path}; + +fn to_leo_ast(filepath: &Path) -> Result { + // Loads the Leo code as a string from the given file path. + let program_filepath = filepath.to_path_buf(); + let program_string = LeoParser::load_file(&program_filepath)?; + + // Parses the Leo program string and constructs an abstract syntax tree. + let abstract_syntax_tree = LeoParser::parse_file(&program_filepath, &program_string)?; + + // Serializes the abstract syntax tree into JSON format. + let serialized_ast = LeoParser::to_json_string(&abstract_syntax_tree)?; + + Ok(serialized_ast) +} + +fn main() -> Result<(), ParserError> { + // Parse the command-line arguments as strings. + let cli_arguments = env::args().collect::>(); + + // Check that the correct number of command-line arguments were passed in. + if cli_arguments.len() < 2 || cli_arguments.len() > 3 { + eprintln!("Error - invalid number of command-line arguments"); + println!("\nCommand-line usage:\n\n\tleo_ast {{input_filename}}.leo {{optional_output_filepath}}\n"); + return Ok(()); // Exit innocently + } + + // Create the input filepath. + let input_filepath = Path::new(&cli_arguments[1]); + + // Create the serialized abstract syntax tree. + let serialized_ast = to_leo_ast(&input_filepath)?; + println!("{}", serialized_ast); + + // Create the output filepath. + let output_filepath = match cli_arguments.len() == 3 { + true => format!( + "{}/{}.json", + cli_arguments[2], + input_filepath.file_stem().unwrap().to_str().unwrap() + ), + false => format!("./{}.json", input_filepath.file_stem().unwrap().to_str().unwrap()), + }; + + // Write the serialized abstract syntax tree to the output filepath. + fs::write(Path::new(&output_filepath), serialized_ast)?; + + Ok(()) +} diff --git a/compiler/src/compiler.rs b/compiler/src/compiler.rs index 5f4718875c..1006480e0f 100644 --- a/compiler/src/compiler.rs +++ b/compiler/src/compiler.rs @@ -94,11 +94,12 @@ impl> Compiler { generate_test_constraints::(cs, self.program, &self.imported_programs) } + /// Loads the Leo code as a string from the given file path. fn load_program(&mut self) -> Result { - // Load the program syntax tree from the file path Ok(LeoParser::load_file(&self.main_file_path)?) } + /// Parses the Leo program string, constructs a syntax tree, and generates a program. pub fn parse_program(&mut self, program_string: &str) -> Result<(), CompilerError> { // Parse the program syntax tree let syntax_tree = LeoParser::parse_file(&self.main_file_path, program_string)?;