//! Compiles a Leo program from a file path. use crate::{ constraints::{generate_constraints, generate_test_constraints, ConstrainedValue}, errors::CompilerError, GroupType, }; use leo_ast::LeoParser; use leo_inputs::LeoInputsParser; use leo_types::{InputValue, Inputs, Program}; use snarkos_errors::gadgets::SynthesisError; use snarkos_models::{ curves::{Field, PrimeField}, gadgets::r1cs::{ConstraintSynthesizer, ConstraintSystem, TestConstraintSystem}, }; use sha2::{Digest, Sha256}; use std::{fs, marker::PhantomData, path::PathBuf}; #[derive(Clone)] pub struct Compiler> { package_name: String, main_file_path: PathBuf, program: Program, program_inputs: Inputs, output: Option>, _engine: PhantomData, } impl> Compiler { pub fn new(package_name: String) -> Self { Self { package_name: package_name.clone(), main_file_path: PathBuf::new(), program: Program::new(package_name), program_inputs: Inputs::new(), output: None, _engine: PhantomData, } } pub fn init(package_name: String, main_file_path: PathBuf) -> Result { let mut program = Self::new(package_name); program.set_path(main_file_path); // Generate the abstract syntax tree and assemble the program let program_string = program.load_program()?; program.parse_program(&program_string)?; Ok(program) } pub fn set_path(&mut self, main_file_path: PathBuf) { self.main_file_path = main_file_path } pub fn set_inputs(&mut self, program_inputs: Vec>) { self.program_inputs.set_inputs(program_inputs); } pub fn checksum(&self) -> Result { // Read in the main file as string let unparsed_file = fs::read_to_string(&self.main_file_path) .map_err(|_| CompilerError::FileReadError(self.main_file_path.clone()))?; // Hash the file contents let mut hasher = Sha256::new(); hasher.input(unparsed_file.as_bytes()); let hash = hasher.result(); Ok(hex::encode(hash)) } pub fn compile_constraints>( self, cs: &mut CS, ) -> Result, CompilerError> { generate_constraints(cs, self.program, self.program_inputs.get_inputs()) } pub fn compile_test_constraints(self, cs: &mut TestConstraintSystem) -> Result<(), CompilerError> { generate_test_constraints::(cs, self.program) } fn load_program(&mut self) -> Result { // Load the program syntax tree from the file path Ok(LeoParser::load_file(&self.main_file_path)?) } 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)?; // Build program from syntax tree let package_name = self.package_name.clone(); self.program = Program::from(syntax_tree, package_name); self.program_inputs.set_inputs_size(self.program.expected_inputs.len()); log::debug!("Program parsing complete\n{:#?}", self.program); Ok(()) } pub fn parse_inputs(&mut self, inputs_string: &str) -> Result<(), CompilerError> { let syntax_tree = LeoInputsParser::parse_file(&inputs_string)?; // Check number/order of parameters here self.program_inputs = Inputs::from_inputs_file(syntax_tree, self.program.expected_inputs.clone())?; Ok(()) } } impl> ConstraintSynthesizer for Compiler { fn generate_constraints>(self, cs: &mut CS) -> Result<(), SynthesisError> { let _result = generate_constraints::<_, G, _>(cs, self.program, self.program_inputs.get_inputs()).map_err(|e| { log::error!("{}", e); SynthesisError::Unsatisfiable })?; // Write results to file or something Ok(()) } }