diff --git a/Cargo.lock b/Cargo.lock index 8f98aac73d..ca5af4b5a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1291,8 +1291,6 @@ dependencies = [ "leo-input", "leo-package", "leo-state", - "leo-symbol-table", - "leo-type-inference", "num-bigint", "pest", "rand", @@ -1362,6 +1360,7 @@ name = "leo-imports" version = "1.0.7" dependencies = [ "indexmap", + "leo-asg", "leo-ast", "leo-grammar", "thiserror", diff --git a/asg/src/error/mod.rs b/asg/src/error/mod.rs index 14ed22e8f7..7870f0a1d5 100644 --- a/asg/src/error/mod.rs +++ b/asg/src/error/mod.rs @@ -1,11 +1,16 @@ use crate::Span; use leo_ast::Error as FormattedError; +use leo_grammar::ParserError; #[derive(Debug, Error)] pub enum AsgConvertError { #[error("{}", _0)] Error(#[from] FormattedError), #[error("{}", _0)] + ImportError(FormattedError), + #[error("{}", _0)] + ParserError(#[from] ParserError), + #[error("{}", _0)] InternalError(String), } diff --git a/asg/src/expression/binary.rs b/asg/src/expression/binary.rs index c443e5ab33..1832580845 100644 --- a/asg/src/expression/binary.rs +++ b/asg/src/expression/binary.rs @@ -161,7 +161,6 @@ impl FromAst for BinaryExpression { Some(Type::Integer(_)) | None => (), Some(x) => return Err(AsgConvertError::unexpected_type(&x.to_string(), Some("integer"), &value.span)), } - } } diff --git a/asg/src/expression/circuit_access.rs b/asg/src/expression/circuit_access.rs index 720257bd5c..d35068984a 100644 --- a/asg/src/expression/circuit_access.rs +++ b/asg/src/expression/circuit_access.rs @@ -1,5 +1,5 @@ use crate::Span; -use crate::{ Expression, Identifier, Type, Node, ExpressionNode, FromAst, Scope, AsgConvertError, Circuit, CircuitMember, ConstValue, PartialType }; +use crate::{ Expression, Identifier, Type, Node, ExpressionNode, FromAst, Scope, AsgConvertError, Circuit, CircuitMember, ConstValue, PartialType, CircuitMemberBody }; use std::sync::{ Weak, Arc }; use std::cell::RefCell; @@ -91,7 +91,15 @@ impl FromAst for CircuitAccessExpression circuit.members.borrow_mut().insert( value.name.name.clone(), CircuitMember::Variable( - expected_type.into() + expected_type.clone().into() + ) + ); + let body = circuit.body.borrow().upgrade().expect("stale input circuit body"); + + body.members.borrow_mut().insert( + value.name.name.clone(), + CircuitMemberBody::Variable( + expected_type ) ); } else { diff --git a/asg/src/import.rs b/asg/src/import.rs index d38eb49950..b9682467f4 100644 --- a/asg/src/import.rs +++ b/asg/src/import.rs @@ -1,27 +1,26 @@ use indexmap::IndexMap; -use crate::{ Program, AsgConvertError }; -use std::sync::Arc; +use crate::{ Program, AsgConvertError, Span }; pub trait ImportResolver { - fn resolve_package(&self, package_segments: &[&str]) -> Result, AsgConvertError>; + fn resolve_package(&mut self, package_segments: &[&str], span: &Span) -> Result, AsgConvertError>; } pub struct NullImportResolver; impl ImportResolver for NullImportResolver { - fn resolve_package(&self, _package_segments: &[&str]) -> Result, AsgConvertError> { + fn resolve_package(&mut self, _package_segments: &[&str], _span: &Span) -> Result, AsgConvertError> { Ok(None) } } -pub struct CoreImportResolver<'a, T: ImportResolver + 'static>(pub &'a T); +pub struct CoreImportResolver<'a, T: ImportResolver + 'static>(pub &'a mut T); impl<'a, T: ImportResolver + 'static> ImportResolver for CoreImportResolver<'a, T> { - fn resolve_package(&self, package_segments: &[&str]) -> Result, AsgConvertError> { + fn resolve_package(&mut self, package_segments: &[&str], span: &Span) -> Result, AsgConvertError> { if package_segments.len() > 0 && package_segments.get(0).unwrap() == &"core" { Ok(crate::resolve_core_module(&*package_segments[1..].join("."))?) } else { - self.0.resolve_package(package_segments) + self.0.resolve_package(package_segments, span) } } } @@ -30,7 +29,7 @@ pub struct StandardImportResolver; //todo: move compiler ImportParser here impl ImportResolver for StandardImportResolver { - fn resolve_package(&self, _package_segments: &[&str]) -> Result, AsgConvertError> { + fn resolve_package(&mut self, _package_segments: &[&str], _span: &Span) -> Result, AsgConvertError> { Ok(None) } } @@ -40,7 +39,7 @@ pub struct MockedImportResolver { } impl ImportResolver for MockedImportResolver { - fn resolve_package(&self, package_segments: &[&str]) -> Result, AsgConvertError> { + fn resolve_package(&mut self, package_segments: &[&str], _span: &Span) -> Result, AsgConvertError> { Ok(self.packages.get(&package_segments.join(".")).cloned()) } } \ No newline at end of file diff --git a/asg/src/input.rs b/asg/src/input.rs index 6840fb29e6..5c4e526024 100644 --- a/asg/src/input.rs +++ b/asg/src/input.rs @@ -1,15 +1,15 @@ use std::sync::{ Arc, Weak }; -use crate::{ Circuit, Variable, Identifier, Type, CircuitMember, WeakType }; +use crate::{ Circuit, CircuitBody, Variable, Identifier, Type, CircuitMember, CircuitMemberBody, WeakType, Scope }; use std::cell::RefCell; use indexmap::IndexMap; #[derive(Clone)] pub struct Input { - pub registers: Arc, - pub state: Arc, - pub state_leaf: Arc, - pub record: Arc, - pub container_circuit: Arc, + pub registers: Arc, + pub state: Arc, + pub state_leaf: Arc, + pub record: Arc, + pub container_circuit: Arc, pub container: Variable, } @@ -20,32 +20,32 @@ pub const STATE_PSUEDO_CIRCUIT: &str = "$InputState"; pub const STATE_LEAF_PSUEDO_CIRCUIT: &str = "$InputStateLeaf"; impl Input { - pub fn new() -> Self { - let registers = Arc::new(Circuit { + fn make_header(name: &str) -> Arc { + Arc::new(Circuit { id: uuid::Uuid::new_v4(), - name: RefCell::new(Identifier::new(REGISTERS_PSUEDO_CIRCUIT.to_string())), + name: RefCell::new(Identifier::new(name.to_string())), body: RefCell::new(Weak::new()), members: RefCell::new(IndexMap::new()), - }); - let record = Arc::new(Circuit { - id: uuid::Uuid::new_v4(), - name: RefCell::new(Identifier::new(RECORD_PSUEDO_CIRCUIT.to_string())), - body: RefCell::new(Weak::new()), - members: RefCell::new(IndexMap::new()), - }); - let state = Arc::new(Circuit { - id: uuid::Uuid::new_v4(), - name: RefCell::new(Identifier::new(STATE_PSUEDO_CIRCUIT.to_string())), - body: RefCell::new(Weak::new()), - members: RefCell::new(IndexMap::new()), - }); - let state_leaf = Arc::new(Circuit { - id: uuid::Uuid::new_v4(), - name: RefCell::new(Identifier::new(STATE_LEAF_PSUEDO_CIRCUIT.to_string())), - body: RefCell::new(Weak::new()), - members: RefCell::new(IndexMap::new()), - }); + }) + } + fn make_body(scope: &Scope, circuit: &Arc) -> Arc { + let body = Arc::new(CircuitBody { + scope: scope.clone(), + span: None, + circuit: circuit.clone(), + members: RefCell::new(IndexMap::new()), + }); + circuit.body.replace(Arc::downgrade(&body)); + body + } + + pub fn new(scope: &Scope) -> Self { + let registers = Self::make_header(REGISTERS_PSUEDO_CIRCUIT); + let record = Self::make_header(RECORD_PSUEDO_CIRCUIT); + let state = Self::make_header(STATE_PSUEDO_CIRCUIT); + let state_leaf = Self::make_header(STATE_LEAF_PSUEDO_CIRCUIT); + let mut container_members = IndexMap::new(); container_members.insert("registers".to_string(), CircuitMember::Variable(WeakType::Circuit(Arc::downgrade(®isters)))); container_members.insert("record".to_string(), CircuitMember::Variable(WeakType::Circuit(Arc::downgrade(&record)))); @@ -59,12 +59,31 @@ impl Input { members: RefCell::new(container_members), }); + let registers_body = Self::make_body(scope, ®isters); + let record_body = Self::make_body(scope, &record); + let state_body = Self::make_body(scope, &state); + let state_leaf_body = Self::make_body(scope, &state_leaf); + + let mut container_body_members = IndexMap::new(); + container_body_members.insert("registers".to_string(), CircuitMemberBody::Variable(Type::Circuit(registers.clone()))); + container_body_members.insert("record".to_string(), CircuitMemberBody::Variable(Type::Circuit(record.clone()))); + container_body_members.insert("state".to_string(), CircuitMemberBody::Variable(Type::Circuit(state.clone()))); + container_body_members.insert("state_leaf".to_string(), CircuitMemberBody::Variable(Type::Circuit(state_leaf.clone()))); + + let container_circuit_body = Arc::new(CircuitBody { + scope: scope.clone(), + span: None, + circuit: container_circuit.clone(), + members: RefCell::new(container_body_members), + }); + container_circuit.body.replace(Arc::downgrade(&container_circuit_body)); + Input { - registers, - record, - state, - state_leaf, - container_circuit: container_circuit.clone(), + registers: registers_body, + record: record_body, + state: state_body, + state_leaf: state_leaf_body, + container_circuit: container_circuit_body, container: Arc::new(RefCell::new(crate::InnerVariable { id: uuid::Uuid::new_v4(), name: Identifier::new("input".to_string()), diff --git a/asg/src/lib.rs b/asg/src/lib.rs index cbb364a0c6..f12222b7e0 100644 --- a/asg/src/lib.rs +++ b/asg/src/lib.rs @@ -56,10 +56,10 @@ pub fn load_ast, Y: AsRef>(path: T, content: Y) -> Result(content: leo_ast::Program, resolver: &T) -> Result { +pub fn load_asg_from_ast(content: leo_ast::Program, resolver: &mut T) -> Result { InnerProgram::new(&content, resolver) } -pub fn load_asg(content: &str, resolver: &T) -> Result { +pub fn load_asg(content: &str, resolver: &mut T) -> Result { InnerProgram::new(&load_ast("input.leo", content)?, resolver) } \ No newline at end of file diff --git a/asg/src/prelude.rs b/asg/src/prelude.rs index b13dac84a3..5bfe6b1aed 100644 --- a/asg/src/prelude.rs +++ b/asg/src/prelude.rs @@ -15,7 +15,7 @@ pub fn resolve_core_module(module: &str) -> Result, AsgConvertEr return [0; 32] } } - "#, &crate::NullImportResolver)?)) + "#, &mut crate::NullImportResolver)?)) }, _ => Ok(None), } diff --git a/asg/src/program/mod.rs b/asg/src/program/mod.rs index c25905323c..45079a7d44 100644 --- a/asg/src/program/mod.rs +++ b/asg/src/program/mod.rs @@ -73,7 +73,7 @@ impl InnerProgram { 3. finalize declared functions 4. resolve all asg nodes */ - pub fn new<'a, T: ImportResolver + 'static>(value: &leo_ast::Program, import_resolver: &'a T) -> Result { + pub fn new<'a, T: ImportResolver + 'static>(value: &leo_ast::Program, import_resolver: &'a mut T) -> Result { // TODO: right now if some program A is imported from programs B and C, it will be copied to both, which is not optimal -- needs fixed // recursively extract our imported symbols @@ -83,18 +83,18 @@ impl InnerProgram { } // package list - let mut deduplicated_imports: IndexSet> = IndexSet::new(); - for (package, _symbol, _span) in imported_symbols.iter() { - deduplicated_imports.insert(package.clone()); + let mut deduplicated_imports: IndexMap, Span> = IndexMap::new(); + for (package, _symbol, span) in imported_symbols.iter() { + deduplicated_imports.insert(package.clone(), span.clone()); } - let wrapped_resolver = crate::CoreImportResolver(import_resolver); + let mut wrapped_resolver = crate::CoreImportResolver(import_resolver); // load imported programs let mut resolved_packages: IndexMap, Program> = IndexMap::new(); - for package in deduplicated_imports.iter() { + for (package, span) in deduplicated_imports.iter() { let pretty_package = package.join("."); - let resolved_package = match wrapped_resolver.resolve_package(&package.iter().map(|x| &**x).collect::>()[..])? { + let resolved_package = match wrapped_resolver.resolve_package(&package.iter().map(|x| &**x).collect::>()[..], span)? { Some(x) => x, None => return Err(AsgConvertError::unresolved_import(&*pretty_package, &Span::default())), // todo: better span }; @@ -158,6 +158,7 @@ impl InnerProgram { } let scope = Arc::new(RefCell::new(InnerScope { + input: Some(Input::new(&import_scope)), // we use import_scope to avoid recursive scope ref here id: uuid::Uuid::new_v4(), parent_scope: Some(import_scope), circuit_self: None, @@ -165,7 +166,6 @@ impl InnerProgram { functions: IndexMap::new(), circuits: proto_circuits.iter().map(|(name, circuit)| (name.clone(), circuit.clone())).collect(), function: None, - input: Some(Input::new()), })); for (name, circuit) in value.circuits.iter() { diff --git a/asg/src/scope.rs b/asg/src/scope.rs index dc264fe496..13dcabd775 100644 --- a/asg/src/scope.rs +++ b/asg/src/scope.rs @@ -117,7 +117,7 @@ impl InnerScope { })) } - pub(crate) fn resolve_ast_type(&self, type_: &leo_ast::Type) -> Result { + pub fn resolve_ast_type(&self, type_: &leo_ast::Type) -> Result { use leo_ast::Type::*; Ok(match type_ { Address => Type::Address, diff --git a/asg/tests/mod.rs b/asg/tests/mod.rs index 8d6d0b92bd..4cc6f289a7 100644 --- a/asg/tests/mod.rs +++ b/asg/tests/mod.rs @@ -4,10 +4,10 @@ mod pass; mod fail; fn load_asg(content: &str) -> Result { - leo_asg::load_asg(content, &NullImportResolver) + leo_asg::load_asg(content, &mut NullImportResolver) } -fn load_asg_imports(content: &str, imports: &T) -> Result { +fn load_asg_imports(content: &str, imports: &mut T) -> Result { leo_asg::load_asg(content, imports) } diff --git a/asg/tests/pass/form_ast.rs b/asg/tests/pass/form_ast.rs index 2047d8bb7c..3d5f054656 100644 --- a/asg/tests/pass/form_ast.rs +++ b/asg/tests/pass/form_ast.rs @@ -58,7 +58,7 @@ fn test_imports() { "#; println!("{}", serde_json::to_string(&crate::load_ast("test-import.leo", test_import).unwrap()).unwrap()); println!("{}", serde_json::to_string(&crate::load_ast("test.leo", program_string).unwrap()).unwrap()); - let asg = crate::load_asg_imports(program_string, &imports).unwrap(); + let asg = crate::load_asg_imports(program_string, &mut imports).unwrap(); let reformed_ast = leo_asg::reform_ast(&asg); println!("{}", serde_json::to_string(&reformed_ast).unwrap()); panic!(); diff --git a/asg/tests/pass/import/mod.rs b/asg/tests/pass/import/mod.rs index 3a6f3b70f9..05fba7868c 100644 --- a/asg/tests/pass/import/mod.rs +++ b/asg/tests/pass/import/mod.rs @@ -21,7 +21,7 @@ fn test_basic() { let mut imports = mocked_resolver(); imports.packages.insert("test-import".to_string(), load_asg(include_str!("src/test-import.leo")).unwrap()); let program_string = include_str!("basic.leo"); - load_asg_imports(program_string, &imports).unwrap(); + load_asg_imports(program_string, &mut imports).unwrap(); } #[test] @@ -29,7 +29,7 @@ fn test_multiple() { let mut imports = mocked_resolver(); imports.packages.insert("test-import".to_string(), load_asg(include_str!("src/test-import.leo")).unwrap()); let program_string = include_str!("multiple.leo"); - load_asg_imports(program_string, &imports).unwrap(); + load_asg_imports(program_string, &mut imports).unwrap(); } #[test] @@ -38,7 +38,7 @@ fn test_star() { imports.packages.insert("test-import".to_string(), load_asg(include_str!("src/test-import.leo")).unwrap()); let program_string = include_str!("star.leo"); - load_asg_imports(program_string, &imports).unwrap(); + load_asg_imports(program_string, &mut imports).unwrap(); } #[test] @@ -47,7 +47,7 @@ fn test_alias() { imports.packages.insert("test-import".to_string(), load_asg(include_str!("src/test-import.leo")).unwrap()); let program_string = include_str!("alias.leo"); - load_asg_imports(program_string, &imports).unwrap(); + load_asg_imports(program_string, &mut imports).unwrap(); } // naming tests @@ -59,7 +59,7 @@ fn test_name() { imports.packages.insert("a-9".to_string(), load_asg(include_str!("src/a-9.leo")).unwrap()); let program_string = include_str!("names.leo"); - load_asg_imports(program_string, &imports).unwrap(); + load_asg_imports(program_string, &mut imports).unwrap(); } // more complex tests @@ -74,7 +74,7 @@ fn test_many_import() { imports.packages.insert("car".to_string(), load_asg(include_str!("imports/car/src/lib.leo")).unwrap()); let program_string = include_str!("many_import.leo"); - load_asg_imports(program_string, &imports).unwrap(); + load_asg_imports(program_string, &mut imports).unwrap(); } #[test] @@ -88,5 +88,5 @@ fn test_many_import_star() { imports.packages.insert("car".to_string(), load_asg(include_str!("imports/car/src/lib.leo")).unwrap()); let program_string = include_str!("many_import_star.leo"); - load_asg_imports(program_string, &imports).unwrap(); + load_asg_imports(program_string, &mut imports).unwrap(); } diff --git a/compiler/Cargo.toml b/compiler/Cargo.toml index a8a03a19ef..b80917267e 100644 --- a/compiler/Cargo.toml +++ b/compiler/Cargo.toml @@ -49,14 +49,6 @@ version = "1.0.7" path = "../state" version = "1.0.7" -[dependencies.leo-symbol-table] -path = "../symbol-table" -version = "1.0.7" - -[dependencies.leo-type-inference] -path = "../type-inference" -version = "1.0.7" - [dependencies.leo-asg] path = "../asg" version = "1.0.7" diff --git a/compiler/src/compiler.rs b/compiler/src/compiler.rs index 9eb7ee4665..8decf7bf29 100644 --- a/compiler/src/compiler.rs +++ b/compiler/src/compiler.rs @@ -25,12 +25,9 @@ use crate::{ }; use leo_ast::{Ast, Input, MainInput, Program}; use leo_grammar::Grammar; -use leo_imports::ImportParser; use leo_input::LeoInputParser; use leo_package::inputs::InputPairs; use leo_state::verify_local_data_commitment; -use leo_symbol_table::SymbolTable; -use leo_type_inference::TypeInference; use snarkvm_dpc::{base_dpc::instantiated::Components, SystemParameters}; use snarkvm_errors::gadgets::SynthesisError; @@ -56,7 +53,6 @@ pub struct Compiler> { program: Program, program_input: Input, asg: Option, - imported_programs: ImportParser, _engine: PhantomData, _group: PhantomData, } @@ -73,7 +69,6 @@ impl> Compiler { program: Program::new(package_name), program_input: Input::new(), asg: None, - imported_programs: ImportParser::default(), _engine: PhantomData, _group: PhantomData, } @@ -165,11 +160,7 @@ impl> Compiler { /// Runs program parser and type inference checker consecutively. /// pub(crate) fn parse_and_check_program(&mut self) -> Result<(), CompilerError> { - self.parse_program()?; - - self.check_program()?; - - self.program_asg_generate() + self.parse_program() } /// @@ -194,45 +185,16 @@ impl> Compiler { // Store the main program file. self.program = core_ast.into_repr(); - // Parse and store all programs imported by the main program file. - self.imported_programs = ImportParser::parse(&self.program)?; - tracing::debug!("Program parsing complete\n{:#?}", self.program); - Ok(()) - } - - /// - /// Runs a type check on the program, imports, and input. - /// - /// First, a symbol table of all user defined types is created. - /// Second, a type inference check is run on the program - inferring a data type for all implicit types and - /// catching type mismatch errors. - /// - pub(crate) fn check_program(&self) -> Result<(), CompilerError> { - // Create a new symbol table from the program, imported_programs, and program_input. - let symbol_table = - SymbolTable::new(&self.program, &self.imported_programs, &self.program_input).map_err(|mut e| { - e.set_path(&self.main_file_path); - - e - })?; - - // Run type inference check on program. - TypeInference::new(&self.program, symbol_table).map_err(|mut e| { - e.set_path(&self.main_file_path); - - e - })?; - - tracing::debug!("Program checks complete"); + self.program_asg_generate()?; Ok(()) } pub(crate) fn program_asg_generate(&mut self) -> Result<(), CompilerError> { // Create a new symbol table from the program, imported_programs, and program_input. - let asg = leo_asg::InnerProgram::new(&self.program, &leo_asg::NullImportResolver)?; + let asg = leo_asg::InnerProgram::new(&self.program, &mut leo_imports::ImportParser::default())?; tracing::debug!("ASG generation complete"); @@ -262,17 +224,10 @@ impl> Compiler { // Store the main program file. self.program = core_ast.into_repr(); - // Parse and store all programs imported by the main program file. - self.imported_programs = ImportParser::parse(&self.program)?; - - // Create a new symbol table from the program, imported programs, and program input. - let symbol_table = SymbolTable::new(&self.program, &self.imported_programs, &self.program_input)?; - - // Run type inference check on program. - TypeInference::new(&self.program, symbol_table)?; - tracing::debug!("Program parsing complete\n{:#?}", self.program); + self.program_asg_generate()?; + Ok(()) } diff --git a/compiler/src/console/format.rs b/compiler/src/console/format.rs index 3bde7cb706..3adae966c5 100644 --- a/compiler/src/console/format.rs +++ b/compiler/src/console/format.rs @@ -37,7 +37,7 @@ impl> ConstrainedProgram { return Err(ConsoleError::length( formatted.containers.len(), formatted.parameters.len(), - formatted.span, + formatted.span.clone(), )); } diff --git a/compiler/src/constraints/constraints.rs b/compiler/src/constraints/constraints.rs index ad6437c773..9f2e4060ac 100644 --- a/compiler/src/constraints/constraints.rs +++ b/compiler/src/constraints/constraints.rs @@ -39,7 +39,7 @@ pub fn generate_constraints, CS: Constrai program: &Program, input: &Input, ) -> Result { - let mut resolved_program = ConstrainedProgram::::new(); + let mut resolved_program = ConstrainedProgram::::new(program.clone()); let program_name = program.borrow().name.clone(); let main = { @@ -62,7 +62,7 @@ pub fn generate_test_constraints>( main_file_path: &Path, output_directory: &Path, ) -> Result<(u32, u32), CompilerError> { - let mut resolved_program = ConstrainedProgram::::new(); + let mut resolved_program = ConstrainedProgram::::new(program.clone()); let program_name = program.borrow().name.clone(); // Get default input @@ -84,7 +84,7 @@ pub fn generate_test_constraints>( // get input file name from annotation or use test_name let input_pair = match input_file { Some(file_id) => { - let file_name = file_id.name; + let file_name = file_id.name.clone(); output_file_name = file_name.clone(); diff --git a/compiler/src/errors/compiler.rs b/compiler/src/errors/compiler.rs index f2fe31e105..1484acd8d8 100644 --- a/compiler/src/errors/compiler.rs +++ b/compiler/src/errors/compiler.rs @@ -20,8 +20,6 @@ use leo_grammar::ParserError; use leo_imports::ImportParserError; use leo_input::InputParserError; use leo_state::LocalDataVerificationError; -use leo_symbol_table::SymbolTableError; -use leo_type_inference::TypeInferenceError; use bincode::Error as SerdeError; use std::path::{Path, PathBuf}; @@ -70,12 +68,6 @@ pub enum CompilerError { #[error("{}", _0)] SerdeError(#[from] SerdeError), - #[error("{}", _0)] - SymbolTableError(#[from] SymbolTableError), - - #[error("{}", _0)] - TypeInferenceError(#[from] TypeInferenceError), - #[error("{}", _0)] AsgConvertError(#[from] AsgConvertError), } @@ -86,8 +78,6 @@ impl CompilerError { CompilerError::InputParserError(error) => error.set_path(path), CompilerError::FunctionError(error) => error.set_path(path), CompilerError::OutputStringError(error) => error.set_path(path), - CompilerError::SymbolTableError(error) => error.set_path(path), - CompilerError::TypeInferenceError(error) => error.set_path(path), _ => {} } } diff --git a/compiler/src/errors/function.rs b/compiler/src/errors/function.rs index 49dfae9467..f8ae312709 100644 --- a/compiler/src/errors/function.rs +++ b/compiler/src/errors/function.rs @@ -25,6 +25,7 @@ use crate::errors::{ StatementError, ValueError, }; +use leo_asg::AsgConvertError; use leo_ast::{Error as FormattedError, Span}; use std::path::Path; @@ -60,6 +61,9 @@ pub enum FunctionError { #[error("{}", _0)] ValueError(#[from] ValueError), + + #[error("{}", _0)] + ImportASGError(#[from] AsgConvertError), } impl FunctionError { @@ -75,6 +79,7 @@ impl FunctionError { FunctionError::OutputStringError(error) => error.set_path(path), FunctionError::StatementError(error) => error.set_path(path), FunctionError::ValueError(error) => error.set_path(path), + FunctionError::ImportASGError(error) => (), } } diff --git a/compiler/src/expression/circuit/access.rs b/compiler/src/expression/circuit/access.rs index 12d1e3ea8a..59a2b720f3 100644 --- a/compiler/src/expression/circuit/access.rs +++ b/compiler/src/expression/circuit/access.rs @@ -29,8 +29,6 @@ use snarkvm_models::{ gadgets::r1cs::ConstraintSystem, }; -static SELF_KEYWORD: &str = "self"; - impl> ConstrainedProgram { #[allow(clippy::too_many_arguments)] pub fn enforce_circuit_access>( @@ -45,7 +43,7 @@ impl> ConstrainedProgram { //todo: we can prob pass values by ref here to avoid copying the entire circuit on access let target_value = self.enforce_operand(cs, file_scope, function_scope, target)?; match target_value { - ConstrainedValue::CircuitExpression(def, _, members) => { + ConstrainedValue::CircuitExpression(def, members) => { assert!(def.circuit == expr.circuit); if let Some(member) = members.into_iter().find(|x| x.0.name == expr.member.name) { Ok(member.1) diff --git a/compiler/src/expression/circuit/circuit.rs b/compiler/src/expression/circuit/circuit.rs index dffb47b3e8..1195f15aae 100644 --- a/compiler/src/expression/circuit/circuit.rs +++ b/compiler/src/expression/circuit/circuit.rs @@ -64,13 +64,10 @@ impl> ConstrainedProgram { } } - let id = uuid::Uuid::new_v4(); let value = ConstrainedValue::CircuitExpression( - circuit, - id.clone(), + circuit.clone(), resolved_members, ); - self.store(id, value.clone()); Ok(value) } } diff --git a/compiler/src/expression/expression.rs b/compiler/src/expression/expression.rs index 9b4ff9a1bf..614a205012 100644 --- a/compiler/src/expression/expression.rs +++ b/compiler/src/expression/expression.rs @@ -179,7 +179,7 @@ impl> ConstrainedProgram { target, arguments, .. - }) => match *function { + }) => match function { function if function.name.borrow().is_core() => self.enforce_core_circuit_call_expression( cs, file_scope, diff --git a/compiler/src/expression/function/function.rs b/compiler/src/expression/function/function.rs index bbdc5ce9a5..fff8c1036c 100644 --- a/compiler/src/expression/function/function.rs +++ b/compiler/src/expression/function/function.rs @@ -55,19 +55,25 @@ impl> ConstrainedProgram { }; let old_self_alias = self.self_alias.take(); - self.self_alias = if let Some(target) = &target { + // self.self_alias = + if let Some(target) = &target { let self_var = function.scope.borrow().resolve_variable("self").expect("attempted to call static function from non-static context"); - match target { - ConstrainedValue::CircuitExpression(circuit, id, values) => { - assert!(Some(&circuit.circuit) == function.function.circuit.borrow().map(|x| x.upgrade()).flatten().as_ref()); - Some((self_var.borrow().id.clone(), id.clone())) - }, - _ => panic!("attempted to pass non-circuit as target"), - } - } else { - None - }; + self.store(self_var.borrow().id.clone(), target.clone()); + // match target { + // ConstrainedValue::CircuitExpression(circuit, values) => { + // assert!(Some(&circuit.circuit) == function.function.circuit.borrow().map(|x| x.upgrade()).flatten().as_ref()); + // Some((self_var.borrow().id.clone(), id.clone())) + // }, + // _ => panic!("attempted to pass non-circuit as target"), + // } + } + // } else { + // None + // }; + //todo: mut self + + let return_value = self.enforce_function( &mut cs.ns(name_unique), file_scope, @@ -78,6 +84,7 @@ impl> ConstrainedProgram { ) .map_err(|error| ExpressionError::from(Box::new(error)))?; + self.self_alias = old_self_alias; Ok(return_value) } } diff --git a/compiler/src/function/function.rs b/compiler/src/function/function.rs index 7cc1061c9f..12ccfe28a0 100644 --- a/compiler/src/function/function.rs +++ b/compiler/src/function/function.rs @@ -73,21 +73,20 @@ impl> ConstrainedProgram { // FunctionQualifier::Static => (), // } if function.arguments.len() != arguments.len() { - return Err(FunctionError::input_not_found("arguments length invalid".to_string(), function.span.unwrap_or_default())); + return Err(FunctionError::input_not_found("arguments length invalid".to_string(), function.span.clone().unwrap_or_default())); } // Store input values as new variables in resolved program for (variable, input_expression) in function.arguments.iter().zip(arguments.into_iter()) { - let variable = variable.borrow(); let mut input_value = self.enforce_function_input( cs, scope, caller_scope, &function_name, - Some(variable.type_.clone()), input_expression, )?; + let variable = variable.borrow(); if variable.mutable { input_value = ConstrainedValue::Mutable(Box::new(input_value)) @@ -114,7 +113,7 @@ impl> ConstrainedProgram { results.append(&mut result); // Conditionally select a result based on returned indicators - Self::conditionally_select_result(cs, &output, results, &function.span.unwrap_or_default()) + Self::conditionally_select_result(cs, &output, results, &function.span.clone().unwrap_or_default()) .map_err(FunctionError::StatementError) } } diff --git a/compiler/src/function/input/array.rs b/compiler/src/function/input/array.rs index 78df4e1802..7f5aec6fee 100644 --- a/compiler/src/function/input/array.rs +++ b/compiler/src/function/input/array.rs @@ -18,16 +18,14 @@ use crate::{ errors::FunctionError, - inner_array_type, - parse_index, program::{new_scope, ConstrainedProgram}, value::ConstrainedValue, GroupType, }; -use leo_ast::{ArrayDimensions, InputValue, Span, Type}; +use leo_ast::{InputValue, Span}; +use leo_asg::Type; -use crate::errors::ExpressionError; use snarkvm_models::{ curves::{Field, PrimeField}, gadgets::r1cs::ConstraintSystem, @@ -38,26 +36,11 @@ impl> ConstrainedProgram { &mut self, cs: &mut CS, name: &str, - array_type: Type, - mut array_dimensions: ArrayDimensions, + array_type: &Type, + array_len: usize, input_value: Option, span: &Span, ) -> Result, FunctionError> { - let expected_length = match array_dimensions.remove_first() { - Some(number) => { - // Parse the array dimension into a `usize`. - parse_index(&number, &span)? - } - None => { - return Err(FunctionError::ExpressionError(ExpressionError::unexpected_array( - array_type.to_string(), - span.to_owned(), - ))); - } - }; - - // Get the expected type for each array element. - let inner_array_type = inner_array_type(array_type, array_dimensions); // Build the array value using the expected types. let mut array_value = vec![]; @@ -70,7 +53,7 @@ impl> ConstrainedProgram { array_value.push(self.allocate_main_function_input( cs, - inner_array_type.clone(), + array_type, &value_name, Some(value), span, @@ -79,12 +62,12 @@ impl> ConstrainedProgram { } None => { // Allocate all row values as none - for i in 0..expected_length { + for i in 0..array_len { let value_name = new_scope(&name, &i.to_string()); array_value.push(self.allocate_main_function_input( cs, - inner_array_type.clone(), + array_type, &value_name, None, span, diff --git a/compiler/src/function/input/function_input.rs b/compiler/src/function/input/function_input.rs index 8b23cc8347..96cedf05a2 100644 --- a/compiler/src/function/input/function_input.rs +++ b/compiler/src/function/input/function_input.rs @@ -18,7 +18,8 @@ use crate::{errors::FunctionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType}; -use leo_asg::{Expression, Type}; +use leo_asg::{Expression}; +use std::sync::Arc; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -32,16 +33,12 @@ impl> ConstrainedProgram { scope: &str, caller_scope: &str, function_name: &str, - expected_type: Option, - input: &Expression, + input: &Arc, ) -> Result, FunctionError> { // Evaluate the function input value as pass by value from the caller or // evaluate as an expression in the current function scope match input { - Expression::Identifier(identifier) => { - Ok(self.evaluate_identifier(caller_scope, function_name, expected_type, identifier)?) - } - expression => Ok(self.enforce_expression(cs, scope, function_name, expected_type, expression)?), + expression => Ok(self.enforce_expression(cs, scope, function_name, expression)?), } } } diff --git a/compiler/src/function/input/input_keyword.rs b/compiler/src/function/input/input_keyword.rs index c424941b2d..1b72f07726 100644 --- a/compiler/src/function/input/input_keyword.rs +++ b/compiler/src/function/input/input_keyword.rs @@ -16,6 +16,8 @@ use crate::{errors::FunctionError, ConstrainedCircuitMember, ConstrainedProgram, ConstrainedValue, GroupType}; use leo_ast::{Identifier, Input, Span}; +use leo_asg::{CircuitBody, CircuitMemberBody, Type}; +use std::sync::Arc; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -32,25 +34,26 @@ impl> ConstrainedProgram { &mut self, cs: &mut CS, span: Span, + expected_type: &Arc, input: &Input, ) -> Result, FunctionError> { // Create an identifier for each input variable let registers_name = Identifier { name: REGISTERS_VARIABLE_NAME.to_string(), - span, + span: span.clone(), }; let record_name = Identifier { name: RECORD_VARIABLE_NAME.to_string(), - span, + span: span.clone(), }; let state_name = Identifier { name: STATE_VARIABLE_NAME.to_string(), - span, + span: span.clone(), }; let state_leaf_name = Identifier { name: STATE_LEAF_VARIABLE_NAME.to_string(), - span, + span: span.clone(), }; // Fetch each input variable's definitions @@ -72,8 +75,15 @@ impl> ConstrainedProgram { let mut members = Vec::with_capacity(sections.len()); for (name, values) in sections { + let sub_circuit = match expected_type.members.borrow().get(&name.name) { + Some(CircuitMemberBody::Variable(Type::Circuit(circuit))) => { + circuit.body.borrow().upgrade().expect("stale circuit body for input subtype") + }, + _ => panic!("illegal input type definition from asg"), + }; + let member_name = name.clone(); - let member_value = self.allocate_input_section(cs, name, values)?; + let member_value = self.allocate_input_section(cs, name, sub_circuit, values)?; let member = ConstrainedCircuitMember(member_name, member_value); @@ -82,6 +92,6 @@ impl> ConstrainedProgram { // Return input variable keyword as circuit expression - Ok(ConstrainedValue::CircuitExpression(Identifier::from(keyword), members)) + Ok(ConstrainedValue::CircuitExpression(expected_type.clone(), members)) } } diff --git a/compiler/src/function/input/input_section.rs b/compiler/src/function/input/input_section.rs index 69947906d7..79f423f305 100644 --- a/compiler/src/function/input/input_section.rs +++ b/compiler/src/function/input/input_section.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::{errors::FunctionError, ConstrainedCircuitMember, ConstrainedProgram, ConstrainedValue, GroupType}; +use crate::{ConstrainedCircuitMember, ConstrainedProgram, ConstrainedValue, GroupType, errors::{FunctionError}}; +use leo_asg::{CircuitBody, CircuitMemberBody, AsgConvertError}; use leo_ast::{Identifier, InputValue, Parameter}; +use std::sync::Arc; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -29,6 +31,7 @@ impl> ConstrainedProgram { &mut self, cs: &mut CS, identifier: Identifier, + expected_type: Arc, section: IndexMap>, ) -> Result, FunctionError> { let mut members = Vec::with_capacity(section.len()); @@ -36,10 +39,19 @@ impl> ConstrainedProgram { // Allocate each section definition as a circuit member value for (parameter, option) in section.into_iter() { + let section_members = expected_type.members.borrow(); + let expected_type = match section_members.get(¶meter.variable.name) { + Some(CircuitMemberBody::Variable(inner)) => inner, + _ => continue, // present, but unused + }; + let declared_type = self.asg.borrow().scope.borrow().resolve_ast_type(¶meter.type_)?; + if !expected_type.is_assignable_from(&declared_type) { + Err(AsgConvertError::unexpected_type(&expected_type.to_string(), Some(&declared_type.to_string()), &identifier.span))?; + } let member_name = parameter.variable.clone(); let member_value = self.allocate_main_function_input( cs, - parameter.type_, + &declared_type, ¶meter.variable.name, option, ¶meter.span, @@ -51,6 +63,6 @@ impl> ConstrainedProgram { // Return section as circuit expression - Ok(ConstrainedValue::CircuitExpression(identifier, members)) + Ok(ConstrainedValue::CircuitExpression(expected_type, members)) } } diff --git a/compiler/src/function/input/main_function_input.rs b/compiler/src/function/input/main_function_input.rs index 0a14a9ac61..1bd95bd8ec 100644 --- a/compiler/src/function/input/main_function_input.rs +++ b/compiler/src/function/input/main_function_input.rs @@ -30,8 +30,8 @@ use crate::{ Integer, }; -use leo_ast::{InputValue, Span, Type}; - +use leo_ast::{InputValue, Span}; +use leo_asg::Type; use snarkvm_models::{ curves::{Field, PrimeField}, gadgets::r1cs::ConstraintSystem, @@ -41,7 +41,7 @@ impl> ConstrainedProgram { pub fn allocate_main_function_input>( &mut self, cs: &mut CS, - type_: Type, + type_: &Type, name: &str, input_option: Option, span: &Span, @@ -51,14 +51,14 @@ impl> ConstrainedProgram { Type::Boolean => Ok(bool_from_input(cs, name, input_option, span)?), Type::Field => Ok(field_from_input(cs, name, input_option, span)?), Type::Group => Ok(group_from_input(cs, name, input_option, span)?), - Type::IntegerType(integer_type) => Ok(ConstrainedValue::Integer(Integer::from_input( + Type::Integer(integer_type) => Ok(ConstrainedValue::Integer(Integer::from_input( cs, integer_type, name, input_option, span, )?)), - Type::Array(type_, dimensions) => self.allocate_array(cs, name, *type_, dimensions, input_option, span), + Type::Array(type_, len) => self.allocate_array(cs, name, &*type_, *len, input_option, span), Type::Tuple(types) => self.allocate_tuple(cs, &name, types, input_option, span), _ => unimplemented!("main function input not implemented for type"), } diff --git a/compiler/src/function/input/tuple.rs b/compiler/src/function/input/tuple.rs index db75c63ed0..575c69dea8 100644 --- a/compiler/src/function/input/tuple.rs +++ b/compiler/src/function/input/tuple.rs @@ -23,7 +23,8 @@ use crate::{ GroupType, }; -use leo_ast::{InputValue, Span, Type}; +use leo_ast::{InputValue, Span}; +use leo_asg::Type; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -35,7 +36,7 @@ impl> ConstrainedProgram { &mut self, cs: &mut CS, name: &str, - types: Vec, + types: &Vec, input_value: Option, span: &Span, ) -> Result, FunctionError> { @@ -44,7 +45,7 @@ impl> ConstrainedProgram { match input_value { Some(InputValue::Tuple(values)) => { // Allocate each value in the tuple - for (i, (value, type_)) in values.into_iter().zip(types.into_iter()).enumerate() { + for (i, (value, type_)) in values.into_iter().zip(types.iter()).enumerate() { let value_name = new_scope(name, &i.to_string()); tuple_values.push(self.allocate_main_function_input(cs, type_, &value_name, Some(value), span)?) @@ -52,7 +53,7 @@ impl> ConstrainedProgram { } None => { // Allocate all tuple values as none - for (i, type_) in types.into_iter().enumerate() { + for (i, type_) in types.iter().enumerate() { let value_name = new_scope(name, &i.to_string()); tuple_values.push(self.allocate_main_function_input(cs, type_, &value_name, None, span)?); diff --git a/compiler/src/function/main_function.rs b/compiler/src/function/main_function.rs index ad3bf4cf32..17bb019c35 100644 --- a/compiler/src/function/main_function.rs +++ b/compiler/src/function/main_function.rs @@ -46,11 +46,11 @@ impl> ConstrainedProgram { // Iterate over main function input variables and allocate new values if function.function.has_input { // let input_var = function.scope. - let variable = function.scope.borrow().resolve_variable("input").expect("no input variable in scope when function is qualified"); + let asg_input = function.scope.borrow().resolve_input().expect("no input variable in scope when function is qualified"); - let value = self.allocate_input_keyword(cs, function.function.name.borrow().span.clone(), input)?; + let value = self.allocate_input_keyword(cs, function.function.name.borrow().span.clone(), &asg_input.container_circuit, input)?; - self.store(variable.borrow().id.clone(), value); + self.store(asg_input.container.borrow().id.clone(), value); } diff --git a/compiler/src/function/result/result.rs b/compiler/src/function/result/result.rs index e4ca80cdc6..7e5c21e05f 100644 --- a/compiler/src/function/result/result.rs +++ b/compiler/src/function/result/result.rs @@ -49,12 +49,14 @@ impl> ConstrainedProgram { let mut return_value = ConstrainedValue::Tuple(vec![]); // Error if the function or one of its branches does not return. - if results - .iter() - .find(|(indicator, _res)| get_indicator_value(indicator)) - .is_none() - { - return Err(StatementError::no_returns(&expected_return, span.to_owned())); + if !matches!(expected_return, Type::Tuple(x) if x.len() == 0) { + if results + .iter() + .find(|(indicator, _res)| get_indicator_value(indicator)) + .is_none() + { + return Err(StatementError::no_returns(&expected_return, span.to_owned())); + } } // Find the return value diff --git a/compiler/src/import/mod.rs b/compiler/src/import/mod.rs deleted file mode 100644 index e4767afd6b..0000000000 --- a/compiler/src/import/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) 2019-2020 Aleo Systems Inc. -// This file is part of the Leo library. - -// The Leo library is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// The Leo library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with the Leo library. If not, see . -/// The import store brings an imported symbol into the main program from an import program struct -pub mod store; -pub use self::store::*; diff --git a/compiler/src/import/store/core_package.rs b/compiler/src/import/store/core_package.rs deleted file mode 100644 index efefe7147a..0000000000 --- a/compiler/src/import/store/core_package.rs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (C) 2019-2020 Aleo Systems Inc. -// This file is part of the Leo library. - -// The Leo library is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// The Leo library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with the Leo library. If not, see . - -use crate::{new_scope, ConstrainedProgram, ConstrainedValue, GroupType}; -use leo_ast::Package; - -use leo_core::{CorePackageList, LeoCorePackageError}; -use snarkvm_models::curves::{Field, PrimeField}; - -impl> ConstrainedProgram { - pub(crate) fn store_core_package(&mut self, scope: &str, package: Package) -> Result<(), LeoCorePackageError> { - // Create list of imported core packages. - let list = CorePackageList::from_package_access(package.access)?; - - // Fetch core packages from `leo-core`. - let symbol_list = list.to_symbols()?; - - for (symbol, circuit) in symbol_list.symbols() { - let symbol_name = new_scope(scope, symbol); - - // store packages - self.store(symbol_name, ConstrainedValue::CircuitDefinition(circuit.to_owned())) - } - - Ok(()) - } -} diff --git a/compiler/src/import/store/import.rs b/compiler/src/import/store/import.rs deleted file mode 100644 index 221d553c57..0000000000 --- a/compiler/src/import/store/import.rs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (C) 2019-2020 Aleo Systems Inc. -// This file is part of the Leo library. - -// The Leo library is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// The Leo library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with the Leo library. If not, see . - -use crate::{errors::ImportError, ConstrainedProgram, GroupType}; -use leo_ast::ImportStatement; -use leo_imports::ImportParser; -use leo_symbol_table::imported_symbols::ImportedSymbols; - -use snarkvm_models::curves::{Field, PrimeField}; - -impl> ConstrainedProgram { - pub(crate) fn store_import( - &mut self, - scope: &str, - import: &ImportStatement, - imported_programs: &ImportParser, - ) -> Result<(), ImportError> { - // Fetch core packages. - let core_package = imported_programs.get_core_package(&import.package); - - if let Some(package) = core_package { - self.store_core_package(scope, package.clone())?; - - return Ok(()); - } - - // Fetch dependencies for the current import - let imported_symbols = ImportedSymbols::new(import); - - for (name, symbol) in imported_symbols.symbols { - // Find imported program - let program = imported_programs - .get_import(&name) - .ok_or_else(|| ImportError::unknown_package(import.package.name.clone()))?; - - // Store the imported symbol - self.store_symbol(scope, &name, &symbol, program)?; - } - - Ok(()) - } -} diff --git a/compiler/src/import/store/mod.rs b/compiler/src/import/store/mod.rs deleted file mode 100644 index 6b881f6016..0000000000 --- a/compiler/src/import/store/mod.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (C) 2019-2020 Aleo Systems Inc. -// This file is part of the Leo library. - -// The Leo library is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// The Leo library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with the Leo library. If not, see . - -/// The import store brings an imported symbol into the main program from an import program struct -pub mod core_package; -pub use self::core_package::*; - -pub mod import; -pub use self::import::*; - -pub mod symbol; -pub use self::symbol::*; diff --git a/compiler/src/import/store/symbol.rs b/compiler/src/import/store/symbol.rs deleted file mode 100644 index 61b781b8e2..0000000000 --- a/compiler/src/import/store/symbol.rs +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (C) 2019-2020 Aleo Systems Inc. -// This file is part of the Leo library. - -// The Leo library is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// The Leo library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with the Leo library. If not, see . - -use crate::{errors::ImportError, new_scope, ConstrainedProgram, ConstrainedValue, GroupType}; -use leo_ast::{ImportSymbol, Program}; - -use snarkvm_models::curves::{Field, PrimeField}; - -impl> ConstrainedProgram { - pub(crate) fn store_symbol( - &mut self, - scope: &str, - program_name: &str, - symbol: &ImportSymbol, - program: &Program, - ) -> Result<(), ImportError> { - // Store the symbol that was imported by another file - if symbol.is_star() { - // evaluate and store all circuit definitions - program.circuits.iter().for_each(|(identifier, circuit)| { - let name = new_scope(scope, &identifier.name); - let value = ConstrainedValue::Import( - program_name.to_owned(), - Box::new(ConstrainedValue::CircuitDefinition(circuit.clone())), - ); - - self.store(name, value); - }); - - // evaluate and store all function definitions - program.functions.iter().for_each(|(identifier, function)| { - let name = new_scope(scope, &identifier.name); - let value = ConstrainedValue::Import( - program_name.to_owned(), - Box::new(ConstrainedValue::Function(None, Box::new(function.clone()))), - ); - - self.store(name, value); - }); - } else { - // see if the imported symbol is a circuit - let matched_circuit = program - .circuits - .iter() - .find(|(circuit_name, _circuit_def)| symbol.symbol == **circuit_name); - - let value = match matched_circuit { - Some((_circuit_name, circuit)) => ConstrainedValue::Import( - program_name.to_owned(), - Box::new(ConstrainedValue::CircuitDefinition(circuit.clone())), - ), - None => { - // see if the imported symbol is a function - let matched_function = program - .functions - .iter() - .find(|(function_name, _function)| symbol.symbol == **function_name); - - match matched_function { - Some((_function_name, function)) => ConstrainedValue::Import( - program_name.to_owned(), - Box::new(ConstrainedValue::Function(None, Box::new(function.clone()))), - ), - None => return Err(ImportError::unknown_symbol(symbol.to_owned(), program_name.to_owned())), - } - } - }; - - // take the alias if it is present - let id = symbol.alias.clone().unwrap_or_else(|| symbol.symbol.clone()); - let name = new_scope(scope, &id.name); - - // store imported circuit under imported name - self.store(name, value); - } - - Ok(()) - } -} diff --git a/compiler/src/lib.rs b/compiler/src/lib.rs index b38de5b75b..fc455d85b9 100644 --- a/compiler/src/lib.rs +++ b/compiler/src/lib.rs @@ -41,9 +41,6 @@ pub use self::expression::*; pub mod function; pub use self::function::*; -pub mod import; -pub use self::import::*; - pub mod output; pub use self::output::*; diff --git a/compiler/src/program/program.rs b/compiler/src/program/program.rs index 55c15841b8..37733070d3 100644 --- a/compiler/src/program/program.rs +++ b/compiler/src/program/program.rs @@ -19,24 +19,17 @@ use crate::{value::ConstrainedValue, GroupType}; use snarkvm_models::curves::{Field, PrimeField}; +use leo_asg::Program; use indexmap::IndexMap; use uuid::Uuid; pub struct ConstrainedProgram> { + pub asg: Program, identifiers: IndexMap>, pub self_alias: Option<(Uuid, Uuid)>, // current self id -> id that self resolves to } -impl> Default for ConstrainedProgram { - fn default() -> Self { - Self { - identifiers: IndexMap::new(), - self_alias: None, - } - } -} - pub fn new_scope(outer: &str, inner: &str) -> String { format!("{}_{}", outer, inner) } @@ -46,8 +39,12 @@ pub fn is_in_scope(current_scope: &str, desired_scope: &str) -> bool { } impl> ConstrainedProgram { - pub fn new() -> Self { - Self::default() + pub fn new(asg: Program) -> Self { + Self { + asg, + identifiers: IndexMap::new(), + self_alias: None, + } } pub(crate) fn store(&mut self, name: Uuid, value: ConstrainedValue) { diff --git a/compiler/src/statement/assign/assignee.rs b/compiler/src/statement/assign/assignee.rs index 7985556dad..00c2f5868c 100644 --- a/compiler/src/statement/assign/assignee.rs +++ b/compiler/src/statement/assign/assignee.rs @@ -187,7 +187,7 @@ impl> ConstrainedProgram { return Err(StatementError::array_assign_interior_index(span.clone())); } match Self::unwrap_mutable(value.remove(0)) { - ConstrainedValue::CircuitExpression(_variable, _, members) => { + ConstrainedValue::CircuitExpression(_variable, members) => { // Modify the circuit variable in place let matched_variable = members.iter_mut().find(|member| member.0 == name); diff --git a/compiler/src/statement/statement.rs b/compiler/src/statement/statement.rs index ee97f4e7ee..5c88de7a8f 100644 --- a/compiler/src/statement/statement.rs +++ b/compiler/src/statement/statement.rs @@ -106,7 +106,7 @@ impl> ConstrainedProgram { results.push((*indicator, value)); } } - _ => return Err(StatementError::unassigned(statement.span.map(|x| x.text.clone()).unwrap_or_default(), statement.span.clone().unwrap_or_default())), + _ => return Err(StatementError::unassigned(statement.span.as_ref().map(|x| x.text.clone()).unwrap_or_default(), statement.span.clone().unwrap_or_default())), } } Statement::Block(statement) => { diff --git a/compiler/src/value/group/targets/edwards_bls12.rs b/compiler/src/value/group/targets/edwards_bls12.rs index 7479bb3140..154d06249a 100644 --- a/compiler/src/value/group/targets/edwards_bls12.rs +++ b/compiler/src/value/group/targets/edwards_bls12.rs @@ -156,7 +156,6 @@ impl EdwardsGroupType { pub fn edwards_affine_from_tuple(x: &GroupCoordinate, y: &GroupCoordinate, span: &Span) -> Result { let x = x.clone(); let y = y.clone(); - let span = span.clone(); match (x, y) { // (x, y) @@ -188,21 +187,21 @@ impl EdwardsGroupType { Self::edwards_affine_from_y_str(y_string, span, None, span) } // Invalid - (x, y) => Err(GroupError::invalid_group(format!("({}, {})", x, y), span)), + (x, y) => Err(GroupError::invalid_group(format!("({}, {})", x, y), span.clone())), } } pub fn edwards_affine_from_x_str( x_string: String, - x_span: Span, + x_span: &Span, greatest: Option, - element_span: Span, + element_span: &Span, ) -> Result { - let x = Fq::from_str(&x_string).map_err(|_| GroupError::x_invalid(x_string, x_span))?; + let x = Fq::from_str(&x_string).map_err(|_| GroupError::x_invalid(x_string, x_span.clone()))?; match greatest { // Sign provided Some(greatest) => { - EdwardsAffine::from_x_coordinate(x, greatest).ok_or_else(|| GroupError::x_recover(element_span)) + EdwardsAffine::from_x_coordinate(x, greatest).ok_or_else(|| GroupError::x_recover(element_span.clone())) } // Sign inferred None => { @@ -217,23 +216,23 @@ impl EdwardsGroupType { } // Otherwise return error. - Err(GroupError::x_recover(element_span)) + Err(GroupError::x_recover(element_span.clone())) } } } pub fn edwards_affine_from_y_str( y_string: String, - y_span: Span, + y_span: &Span, greatest: Option, - element_span: Span, + element_span: &Span, ) -> Result { - let y = Fq::from_str(&y_string).map_err(|_| GroupError::y_invalid(y_string, y_span))?; + let y = Fq::from_str(&y_string).map_err(|_| GroupError::y_invalid(y_string, y_span.clone()))?; match greatest { // Sign provided Some(greatest) => { - EdwardsAffine::from_y_coordinate(y, greatest).ok_or_else(|| GroupError::y_recover(element_span)) + EdwardsAffine::from_y_coordinate(y, greatest).ok_or_else(|| GroupError::y_recover(element_span.clone())) } // Sign inferred None => { @@ -248,7 +247,7 @@ impl EdwardsGroupType { } // Otherwise return error. - Err(GroupError::y_recover(element_span)) + Err(GroupError::y_recover(element_span.clone())) } } } @@ -256,19 +255,19 @@ impl EdwardsGroupType { pub fn edwards_affine_from_pair( x_string: String, y_string: String, - x_span: Span, - y_span: Span, - element_span: Span, + x_span: &Span, + y_span: &Span, + element_span: &Span, ) -> Result { - let x = Fq::from_str(&x_string).map_err(|_| GroupError::x_invalid(x_string, x_span))?; - let y = Fq::from_str(&y_string).map_err(|_| GroupError::y_invalid(y_string, y_span))?; + let x = Fq::from_str(&x_string).map_err(|_| GroupError::x_invalid(x_string, x_span.clone()))?; + let y = Fq::from_str(&y_string).map_err(|_| GroupError::y_invalid(y_string, y_span.clone()))?; let element = EdwardsAffine::new(x, y); if element.is_on_curve() { Ok(element) } else { - Err(GroupError::not_on_curve(element.to_string(), element_span)) + Err(GroupError::not_on_curve(element.to_string(), element_span.clone())) } } diff --git a/compiler/src/value/integer/integer.rs b/compiler/src/value/integer/integer.rs index f5962e371c..7b57ce42fc 100644 --- a/compiler/src/value/integer/integer.rs +++ b/compiler/src/value/integer/integer.rs @@ -130,7 +130,7 @@ impl Integer { pub fn allocate_type>( cs: &mut CS, - integer_type: IntegerType, + integer_type: &IntegerType, name: &str, option: Option, span: &Span, @@ -281,7 +281,7 @@ impl Integer { pub fn from_input>( cs: &mut CS, - integer_type: IntegerType, + integer_type: &IntegerType, name: &str, integer_value: Option, span: &Span, diff --git a/compiler/src/value/value.rs b/compiler/src/value/value.rs index 6b0b0c2e50..8b6da3a0b6 100644 --- a/compiler/src/value/value.rs +++ b/compiler/src/value/value.rs @@ -37,7 +37,6 @@ use snarkvm_models::{ }; use std::fmt; use std::sync::Arc; -use uuid::Uuid; #[derive(Clone, PartialEq, Eq)] pub struct ConstrainedCircuitMember>(pub Identifier, pub ConstrainedValue); @@ -58,7 +57,7 @@ pub enum ConstrainedValue> { Tuple(Vec>), // Circuits - CircuitExpression(Arc, Uuid, Vec>), + CircuitExpression(Arc, Vec>), // Modifiers Mutable(Box>), @@ -91,7 +90,7 @@ impl> ConstrainedValue { Type::Tuple(types) } - ConstrainedValue::CircuitExpression(id, _, _members) => Type::Circuit(id.circuit.clone()), + ConstrainedValue::CircuitExpression(id, _members) => Type::Circuit(id.circuit.clone()), ConstrainedValue::Mutable(value) => return value.to_type(span), value => return Err(ValueError::implicit(value.to_string(), span.to_owned())), }) @@ -174,7 +173,7 @@ impl> ConstrainedValue { let option = integer.get_value(); let name = option.clone().unwrap_or_else(|| "[allocated]".to_string()); - *integer = Integer::allocate_type(&mut cs, integer_type, &name, option, span)?; + *integer = Integer::allocate_type(&mut cs, &integer_type, &name, option, span)?; } // Data type wrappers @@ -192,7 +191,7 @@ impl> ConstrainedValue { value.allocate_value(cs.ns(|| unique_name), span) })?; } - ConstrainedValue::CircuitExpression(_id, _, members) => { + ConstrainedValue::CircuitExpression(_id, members) => { members.iter_mut().enumerate().try_for_each(|(i, member)| { let unique_name = format!("allocate circuit member {} {}:{}", i, span.line, span.start); @@ -241,7 +240,7 @@ impl> fmt::Display for ConstrainedValue { + ConstrainedValue::CircuitExpression(ref circuit, ref members) => { write!(f, "{} {{", circuit.circuit.name.borrow())?; for (i, member) in members.iter().enumerate() { write!(f, "{}: {}", member.0, member.1)?; @@ -358,8 +357,8 @@ impl> CondSelectGadget for Constrained ConstrainedValue::Tuple(array) } ( - ConstrainedValue::CircuitExpression(identifier, _, members_1), - ConstrainedValue::CircuitExpression(_identifier, _, members_2), + ConstrainedValue::CircuitExpression(identifier, members_1), + ConstrainedValue::CircuitExpression(_identifier, members_2), ) => { let mut members = Vec::with_capacity(members_1.len()); @@ -372,7 +371,7 @@ impl> CondSelectGadget for Constrained )?); } - ConstrainedValue::CircuitExpression(identifier.clone(), Uuid::new_v4(), members) + ConstrainedValue::CircuitExpression(identifier.clone(), members) } (ConstrainedValue::Mutable(first), _) => Self::conditionally_select(cs, cond, first, second)?, (_, ConstrainedValue::Mutable(second)) => Self::conditionally_select(cs, cond, first, second)?, diff --git a/compiler/tests/boolean/mod.rs b/compiler/tests/boolean/mod.rs index 02d5dad962..75f94b3f86 100644 --- a/compiler/tests/boolean/mod.rs +++ b/compiler/tests/boolean/mod.rs @@ -17,7 +17,7 @@ use crate::{ assert_satisfied, expect_compiler_error, - expect_type_inference_error, + expect_asg_error, get_output, parse_program, parse_program_with_input, @@ -140,7 +140,7 @@ fn test_true_or_u32() { let program_string = include_str!("true_or_u32.leo"); let error = parse_program(program_string).err().unwrap(); - expect_type_inference_error(error); + expect_asg_error(error); } // Boolean and && @@ -174,7 +174,7 @@ fn test_true_and_u32() { let program_string = include_str!("true_and_u32.leo"); let error = parse_program(program_string).err().unwrap(); - expect_type_inference_error(error); + expect_asg_error(error); } // All diff --git a/compiler/tests/circuits/mod.rs b/compiler/tests/circuits/mod.rs index 37c88ac7f9..be753acf30 100644 --- a/compiler/tests/circuits/mod.rs +++ b/compiler/tests/circuits/mod.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{assert_satisfied, expect_compiler_error, expect_type_inference_error, parse_program}; +use crate::{assert_satisfied, expect_compiler_error, expect_asg_error, parse_program}; // Expressions @@ -39,7 +39,7 @@ fn test_inline_undefined() { let program_string = include_str!("inline_undefined.leo"); let error = parse_program(program_string).err().unwrap(); - expect_type_inference_error(error); + expect_asg_error(error); } // Members @@ -57,7 +57,7 @@ fn test_member_variable_fail() { let program_string = include_str!("member_variable_fail.leo"); let error = parse_program(program_string).err().unwrap(); - expect_type_inference_error(error); + expect_asg_error(error); } #[test] @@ -81,7 +81,7 @@ fn test_member_function_fail() { let program_string = include_str!("member_function_fail.leo"); let error = parse_program(program_string).err().unwrap(); - expect_type_inference_error(error); + expect_asg_error(error); } #[test] @@ -89,7 +89,7 @@ fn test_member_function_invalid() { let program_string = include_str!("member_function_invalid.leo"); let error = parse_program(program_string).err().unwrap(); - expect_type_inference_error(error); + expect_asg_error(error); } #[test] @@ -121,7 +121,7 @@ fn test_member_static_function_invalid() { let program_string = include_str!("member_static_function_invalid.leo"); let error = parse_program(program_string).err().unwrap(); - expect_type_inference_error(error) + expect_asg_error(error) } #[test] @@ -129,7 +129,7 @@ fn test_member_static_function_undefined() { let program_string = include_str!("member_static_function_undefined.leo"); let error = parse_program(program_string).err().unwrap(); - expect_type_inference_error(error) + expect_asg_error(error) } // Mutability @@ -139,7 +139,7 @@ fn test_mutate_function_fail() { let program_string = include_str!("mut_function_fail.leo"); let error = parse_program(program_string).err().unwrap(); - expect_type_inference_error(error); + expect_asg_error(error); } #[test] @@ -171,7 +171,7 @@ fn test_mutate_self_function_fail() { let program_string = include_str!("mut_self_function_fail.leo"); let error = parse_program(program_string).err().unwrap(); - expect_type_inference_error(error); + expect_asg_error(error); } #[test] @@ -179,7 +179,7 @@ fn test_mutate_self_static_function_fail() { let program_string = include_str!("mut_self_static_function_fail.leo"); let error = parse_program(program_string).err().unwrap(); - expect_type_inference_error(error); + expect_asg_error(error); } #[test] @@ -187,7 +187,7 @@ fn test_mutate_static_function_fail() { let program_string = include_str!("mut_static_function_fail.leo"); let error = parse_program(program_string).err().unwrap(); - expect_type_inference_error(error); + expect_asg_error(error); } #[test] @@ -213,7 +213,7 @@ fn test_self_fail() { let program_string = include_str!("self_fail.leo"); let error = parse_program(program_string).err().unwrap(); - expect_type_inference_error(error); + expect_asg_error(error); } #[test] @@ -229,7 +229,7 @@ fn test_self_member_invalid() { let program_string = include_str!("self_member_invalid.leo"); let error = parse_program(program_string).err().unwrap(); - expect_type_inference_error(error); + expect_asg_error(error); } #[test] @@ -237,7 +237,7 @@ fn test_self_member_undefined() { let program_string = include_str!("self_member_undefined.leo"); let error = parse_program(program_string).err().unwrap(); - expect_type_inference_error(error); + expect_asg_error(error); } // All diff --git a/compiler/tests/core/mod.rs b/compiler/tests/core/mod.rs index 11ad5f71df..ee7c86e99e 100644 --- a/compiler/tests/core/mod.rs +++ b/compiler/tests/core/mod.rs @@ -16,14 +16,14 @@ pub mod packages; -use crate::{assert_satisfied, expect_symbol_table_error, parse_program}; +use crate::{assert_satisfied, expect_asg_error, parse_program}; #[test] fn test_core_circuit_invalid() { let program_string = include_str!("core_package_invalid.leo"); let error = parse_program(program_string).err().unwrap(); - expect_symbol_table_error(error); + expect_asg_error(error); } #[test] @@ -31,7 +31,7 @@ fn test_core_circuit_star_fail() { let program_string = include_str!("core_circuit_star_fail.leo"); let error = parse_program(program_string).err().unwrap(); - expect_symbol_table_error(error); + expect_asg_error(error); } #[test] @@ -39,7 +39,7 @@ fn test_core_package_invalid() { let program_string = include_str!("core_package_invalid.leo"); let error = parse_program(program_string).err().unwrap(); - expect_symbol_table_error(error); + expect_asg_error(error); } #[test] @@ -47,7 +47,7 @@ fn test_core_unstable_package_invalid() { let program_string = include_str!("core_unstable_package_invalid.leo"); let error = parse_program(program_string).err().unwrap(); - expect_symbol_table_error(error); + expect_asg_error(error); } #[test] diff --git a/compiler/tests/core/packages/unstable/blake2s/mod.rs b/compiler/tests/core/packages/unstable/blake2s/mod.rs index db8877fd21..12795d018c 100644 --- a/compiler/tests/core/packages/unstable/blake2s/mod.rs +++ b/compiler/tests/core/packages/unstable/blake2s/mod.rs @@ -16,7 +16,7 @@ use crate::{ assert_satisfied, - expect_type_inference_error, + expect_asg_error, generate_main_input, get_output, parse_program, @@ -35,7 +35,7 @@ fn test_arguments_length_fail() { let program_string = include_str!("arguments_length_fail.leo"); let error = parse_program(program_string).err().unwrap(); - expect_type_inference_error(error); + expect_asg_error(error); } #[test] @@ -43,7 +43,7 @@ fn test_arguments_type_fail() { let program_string = include_str!("arguments_type_fail.leo"); let error = parse_program(program_string).err().unwrap(); - expect_type_inference_error(error); + expect_asg_error(error); } #[test] diff --git a/compiler/tests/function/mod.rs b/compiler/tests/function/mod.rs index 652964fafb..35fc09a11d 100644 --- a/compiler/tests/function/mod.rs +++ b/compiler/tests/function/mod.rs @@ -17,12 +17,11 @@ use crate::{ assert_satisfied, expect_compiler_error, - expect_type_inference_error, + expect_asg_error, get_output, parse_program, parse_program_with_input, }; -use leo_compiler::errors::{CompilerError, ExpressionError, FunctionError, StatementError}; #[test] fn test_empty() { @@ -118,17 +117,9 @@ fn test_return() { #[test] fn test_scope_fail() { let program_string = include_str!("scope_fail.leo"); - let program = parse_program(program_string).unwrap(); + let error = parse_program(program_string).err().unwrap(); - match expect_compiler_error(program) { - CompilerError::FunctionError(FunctionError::StatementError(StatementError::ExpressionError( - ExpressionError::FunctionError(value), - ))) => match *value { - FunctionError::StatementError(StatementError::ExpressionError(ExpressionError::Error(_))) => {} - error => panic!("Expected function undefined, got {}", error), - }, - error => panic!("Expected function undefined, got {}", error), - } + expect_asg_error(error); } #[test] @@ -136,7 +127,7 @@ fn test_undefined() { let program_string = include_str!("undefined.leo"); let error = parse_program(program_string).err().unwrap(); - expect_type_inference_error(error); + expect_asg_error(error); } #[test] @@ -152,7 +143,7 @@ fn test_array_input() { let program_string = include_str!("array_input.leo"); let error = parse_program(program_string).err().unwrap(); - expect_type_inference_error(error) + expect_asg_error(error) } // Test return multidimensional arrays diff --git a/compiler/tests/integers/i128/mod.rs b/compiler/tests/integers/i128/mod.rs index 8cb73fff1a..d671fc494e 100644 --- a/compiler/tests/integers/i128/mod.rs +++ b/compiler/tests/integers/i128/mod.rs @@ -18,7 +18,8 @@ use crate::{ assert_satisfied, expect_compiler_error, generate_main_input, - integers::{expect_computation_error, expect_parsing_error, IntegerTester}, + integers::{expect_computation_error, IntegerTester}, + expect_asg_error, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/i16/mod.rs b/compiler/tests/integers/i16/mod.rs index ad2988aad0..92620d7468 100644 --- a/compiler/tests/integers/i16/mod.rs +++ b/compiler/tests/integers/i16/mod.rs @@ -18,7 +18,8 @@ use crate::{ assert_satisfied, expect_compiler_error, generate_main_input, - integers::{expect_computation_error, expect_parsing_error, IntegerTester}, + integers::{expect_computation_error, IntegerTester}, + expect_asg_error, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/i32/mod.rs b/compiler/tests/integers/i32/mod.rs index f4df3cc7ff..37f3d161fe 100644 --- a/compiler/tests/integers/i32/mod.rs +++ b/compiler/tests/integers/i32/mod.rs @@ -18,7 +18,8 @@ use crate::{ assert_satisfied, expect_compiler_error, generate_main_input, - integers::{expect_computation_error, expect_parsing_error, IntegerTester}, + integers::{expect_computation_error, IntegerTester}, + expect_asg_error, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/i64/mod.rs b/compiler/tests/integers/i64/mod.rs index 713e02dd8e..bded8ffd07 100644 --- a/compiler/tests/integers/i64/mod.rs +++ b/compiler/tests/integers/i64/mod.rs @@ -18,7 +18,8 @@ use crate::{ assert_satisfied, expect_compiler_error, generate_main_input, - integers::{expect_computation_error, expect_parsing_error, IntegerTester}, + integers::{expect_computation_error, IntegerTester}, + expect_asg_error, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/i8/mod.rs b/compiler/tests/integers/i8/mod.rs index 813e2c13d2..a1c07df5bd 100644 --- a/compiler/tests/integers/i8/mod.rs +++ b/compiler/tests/integers/i8/mod.rs @@ -18,7 +18,8 @@ use crate::{ assert_satisfied, expect_compiler_error, generate_main_input, - integers::{expect_computation_error, expect_parsing_error, IntegerTester}, + integers::{expect_computation_error, IntegerTester}, + expect_asg_error, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/int_macro.rs b/compiler/tests/integers/int_macro.rs index 9346ced2d8..bed15e2493 100644 --- a/compiler/tests/integers/int_macro.rs +++ b/compiler/tests/integers/int_macro.rs @@ -66,9 +66,9 @@ macro_rules! test_int { fn test_min_fail() { let program_string = include_str!("min_fail.leo"); - let program = parse_program(program_string).unwrap(); + let error = parse_program(program_string).err().unwrap(); - expect_parsing_error(program); + expect_asg_error(error); } fn test_max() { @@ -80,9 +80,9 @@ macro_rules! test_int { fn test_max_fail() { let program_string = include_str!("max_fail.leo"); - let program = parse_program(program_string).unwrap(); + let error = parse_program(program_string).err().unwrap(); - expect_parsing_error(program); + expect_asg_error(error); } fn test_add() { diff --git a/compiler/tests/integers/integer_tester.rs b/compiler/tests/integers/integer_tester.rs index 41b0d05656..702bcef0ae 100644 --- a/compiler/tests/integers/integer_tester.rs +++ b/compiler/tests/integers/integer_tester.rs @@ -15,7 +15,7 @@ // along with the Leo library. If not, see . use crate::{expect_compiler_error, EdwardsTestCompiler}; -use leo_compiler::errors::{CompilerError, ExpressionError, FunctionError, IntegerError, StatementError, ValueError}; +use leo_compiler::errors::{CompilerError, ExpressionError, FunctionError, IntegerError, StatementError}; pub trait IntegerTester { /// Tests defining the smalled value that can be represented by the integer type @@ -70,15 +70,6 @@ pub trait IntegerTester { fn test_ternary(); } -pub(crate) fn expect_parsing_error(program: EdwardsTestCompiler) { - match expect_compiler_error(program) { - CompilerError::FunctionError(FunctionError::StatementError(StatementError::ExpressionError( - ExpressionError::ValueError(ValueError::IntegerError(IntegerError::Error(_))), - ))) => {} - error => panic!("Expected integer parsing error, found {:?}", error), - } -} - pub(crate) fn expect_computation_error(program: EdwardsTestCompiler) { match expect_compiler_error(program) { CompilerError::FunctionError(FunctionError::StatementError(StatementError::ExpressionError( diff --git a/compiler/tests/integers/u128/mod.rs b/compiler/tests/integers/u128/mod.rs index 5312c43e5a..60e3df5d47 100644 --- a/compiler/tests/integers/u128/mod.rs +++ b/compiler/tests/integers/u128/mod.rs @@ -18,7 +18,8 @@ use crate::{ assert_satisfied, expect_compiler_error, generate_main_input, - integers::{expect_parsing_error, IntegerTester}, + integers::{IntegerTester}, + expect_asg_error, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/u16/mod.rs b/compiler/tests/integers/u16/mod.rs index fac708a456..bb07fba4fe 100644 --- a/compiler/tests/integers/u16/mod.rs +++ b/compiler/tests/integers/u16/mod.rs @@ -18,7 +18,8 @@ use crate::{ assert_satisfied, expect_compiler_error, generate_main_input, - integers::{expect_parsing_error, IntegerTester}, + integers::{IntegerTester}, + expect_asg_error, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/u32/mod.rs b/compiler/tests/integers/u32/mod.rs index ac6b51f3fd..c475d967d9 100644 --- a/compiler/tests/integers/u32/mod.rs +++ b/compiler/tests/integers/u32/mod.rs @@ -18,7 +18,8 @@ use crate::{ assert_satisfied, expect_compiler_error, generate_main_input, - integers::{expect_parsing_error, IntegerTester}, + integers::{IntegerTester}, + expect_asg_error, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/u64/mod.rs b/compiler/tests/integers/u64/mod.rs index d66ec56e64..9bc2186fa6 100644 --- a/compiler/tests/integers/u64/mod.rs +++ b/compiler/tests/integers/u64/mod.rs @@ -18,7 +18,8 @@ use crate::{ assert_satisfied, expect_compiler_error, generate_main_input, - integers::{expect_parsing_error, IntegerTester}, + integers::{IntegerTester}, + expect_asg_error, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/u8/mod.rs b/compiler/tests/integers/u8/mod.rs index 3eb3666263..5a7632f365 100644 --- a/compiler/tests/integers/u8/mod.rs +++ b/compiler/tests/integers/u8/mod.rs @@ -18,7 +18,8 @@ use crate::{ assert_satisfied, expect_compiler_error, generate_main_input, - integers::{expect_parsing_error, IntegerTester}, + integers::{IntegerTester}, + expect_asg_error, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/uint_macro.rs b/compiler/tests/integers/uint_macro.rs index e220a82be7..fb045bbc7d 100644 --- a/compiler/tests/integers/uint_macro.rs +++ b/compiler/tests/integers/uint_macro.rs @@ -28,23 +28,23 @@ macro_rules! test_uint { fn test_min_fail() { let program_string = include_str!("min_fail.leo"); - let program = parse_program(program_string).unwrap(); + let program = parse_program(program_string).err().unwrap(); - expect_parsing_error(program); + expect_asg_error(program); } fn test_max() { let program_string = include_str!("max.leo"); - let program = parse_program(program_string).unwrap(); + let error = parse_program(program_string).unwrap(); - assert_satisfied(program); + assert_satisfied(error); } fn test_max_fail() { let program_string = include_str!("max_fail.leo"); - let program = parse_program(program_string).unwrap(); + let error = parse_program(program_string).err().unwrap(); - expect_parsing_error(program); + expect_asg_error(error); } fn test_add() { diff --git a/compiler/tests/mod.rs b/compiler/tests/mod.rs index 7f20a94217..21c3f9aa6a 100644 --- a/compiler/tests/mod.rs +++ b/compiler/tests/mod.rs @@ -167,12 +167,8 @@ pub(crate) fn expect_compiler_error(program: EdwardsTestCompiler) -> CompilerErr program.generate_constraints_helper(&mut cs).unwrap_err() } -pub(crate) fn expect_type_inference_error(error: CompilerError) { - assert!(matches!(error, CompilerError::TypeInferenceError(_))) -} - -pub(crate) fn expect_symbol_table_error(error: CompilerError) { - assert!(matches!(error, CompilerError::SymbolTableError(_))) +pub(crate) fn expect_asg_error(error: CompilerError) { + assert!(matches!(error, CompilerError::AsgConvertError(_))) } pub(crate) fn generate_main_input(input: Vec<(&str, Option)>) -> MainInput { diff --git a/compiler/tests/mutability/mod.rs b/compiler/tests/mutability/mod.rs index bbb9f3a639..7b6a14ca6c 100644 --- a/compiler/tests/mutability/mod.rs +++ b/compiler/tests/mutability/mod.rs @@ -14,15 +14,15 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{assert_satisfied, expect_compiler_error, expect_type_inference_error, generate_main_input, parse_program}; +use crate::{assert_satisfied, expect_asg_error, generate_main_input, parse_program}; use leo_ast::InputValue; #[test] fn test_let() { let program_string = include_str!("let.leo"); - let program = parse_program(program_string).unwrap(); + let error = parse_program(program_string).err().unwrap(); - expect_compiler_error(program); + expect_asg_error(error); } #[test] @@ -44,25 +44,25 @@ fn test_let_mut_nested() { #[test] fn test_const_fail() { let program_string = include_str!("const.leo"); - let program = parse_program(program_string).unwrap(); + let error = parse_program(program_string).err().unwrap(); - expect_compiler_error(program); + expect_asg_error(error); } #[test] fn test_const_mut_fail() { let program_string = include_str!("const_mut.leo"); - let program = parse_program(program_string).unwrap(); + let error = parse_program(program_string).err().unwrap(); - expect_compiler_error(program); + expect_asg_error(error); } #[test] fn test_array() { let program_string = include_str!("array.leo"); - let program = parse_program(program_string).unwrap(); + let error = parse_program(program_string).err().unwrap(); - expect_compiler_error(program); + expect_asg_error(error); } #[test] @@ -92,9 +92,9 @@ fn test_array_splice_mut() { #[test] fn test_circuit() { let program_string = include_str!("circuit.leo"); - let program = parse_program(program_string).unwrap(); + let error = parse_program(program_string).err().unwrap(); - expect_compiler_error(program); + expect_asg_error(error); } #[test] @@ -118,7 +118,7 @@ fn test_circuit_function_mut() { let program_string = include_str!("circuit_function_mut.leo"); let error = parse_program(program_string).err().unwrap(); - expect_type_inference_error(error); + expect_asg_error(error); } #[test] @@ -126,19 +126,14 @@ fn test_circuit_static_function_mut() { let program_string = include_str!("circuit_static_function_mut.leo"); let error = parse_program(program_string).err().unwrap(); - expect_type_inference_error(error); + expect_asg_error(error); } #[test] fn test_function_input() { let program_string = include_str!("function_input.leo"); - let mut program = parse_program(program_string).unwrap(); - - let main_input = generate_main_input(vec![("a", Some(InputValue::Boolean(true)))]); - - program.set_main_input(main_input); - - expect_compiler_error(program); + let error = parse_program(program_string).err().unwrap(); + expect_asg_error(error); } #[test] diff --git a/compiler/tests/statements/conditional/multiple_returns.leo b/compiler/tests/statements/conditional/multiple_returns.leo index 234375349b..b8dd869b47 100644 --- a/compiler/tests/statements/conditional/multiple_returns.leo +++ b/compiler/tests/statements/conditional/multiple_returns.leo @@ -1,5 +1,5 @@ function main(input) -> u32 { - if input.registers.a == 0 { + if input.registers.a == 0u32 { return 0u32 } else { return 1u32 diff --git a/compiler/tests/statements/mod.rs b/compiler/tests/statements/mod.rs index a2e1581fda..d346f2fc3e 100644 --- a/compiler/tests/statements/mod.rs +++ b/compiler/tests/statements/mod.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{assert_satisfied, expect_type_inference_error, generate_main_input, parse_program}; +use crate::{assert_satisfied, expect_asg_error, generate_main_input, parse_program}; use leo_ast::InputValue; pub mod conditional; @@ -62,7 +62,7 @@ fn test_num_returns_fail() { let program_string = include_str!("num_returns_fail.leo"); let error = parse_program(program_string).err().unwrap(); - expect_type_inference_error(error); + expect_asg_error(error); } #[test] diff --git a/compiler/tests/syntax/mod.rs b/compiler/tests/syntax/mod.rs index 1bb6493d4b..1f9c271c47 100644 --- a/compiler/tests/syntax/mod.rs +++ b/compiler/tests/syntax/mod.rs @@ -18,7 +18,6 @@ use crate::{expect_compiler_error, parse_input, parse_program}; use leo_compiler::errors::{CompilerError, ExpressionError, FunctionError, StatementError}; use leo_grammar::ParserError; use leo_input::InputParserError; -use leo_type_inference::errors::{FrameError, TypeAssertionError, TypeInferenceError}; pub mod identifiers; @@ -80,10 +79,5 @@ fn test_compare_mismatched_types() { let error = parse_program(program_string).err().unwrap(); // Expect a type inference error. - match error { - CompilerError::TypeInferenceError(TypeInferenceError::FrameError(FrameError::TypeAssertionError( - TypeAssertionError::Error(_), - ))) => {} - error => panic!("Expected type inference error, found {}", error), - } + crate::expect_asg_error(error); } diff --git a/imports/Cargo.toml b/imports/Cargo.toml index 4542ad01a0..83ab2f142c 100644 --- a/imports/Cargo.toml +++ b/imports/Cargo.toml @@ -25,6 +25,10 @@ version = "1.0.7" path = "../grammar" version = "1.0.7" +[dependencies.leo-asg] +path = "../asg" +version = "1.0.7" + [dependencies.indexmap] version = "1.6.1" features = [ "serde-1" ] diff --git a/imports/src/errors/import_parser.rs b/imports/src/errors/import_parser.rs index 647a37a259..a45de1a5d9 100644 --- a/imports/src/errors/import_parser.rs +++ b/imports/src/errors/import_parser.rs @@ -15,6 +15,7 @@ // along with the Leo library. If not, see . use leo_ast::{Error as FormattedError, Identifier, Span}; use leo_grammar::ParserError; +use leo_asg::AsgConvertError; use std::{io, path::Path}; @@ -25,6 +26,18 @@ pub enum ImportParserError { #[error("{}", _0)] ParserError(#[from] ParserError), + #[error("{}", _0)] + AsgConvertError(#[from] AsgConvertError), +} + +impl Into for ImportParserError { + fn into(self) -> AsgConvertError { + match self { + ImportParserError::Error(x) => AsgConvertError::ImportError(x), + ImportParserError::ParserError(x) => x.into(), + ImportParserError::AsgConvertError(x) => x, + } + } } impl ImportParserError { @@ -45,6 +58,12 @@ impl ImportParserError { Self::new_from_span(message, identifier.span) } + pub fn recursive_imports(package: &str, span: &Span) -> Self { + let message = format!("recursive imports for `{}`.", package); + + Self::new_from_span(message, span.clone()) + } + /// /// A core package name has been imported twice. /// diff --git a/imports/src/parser/core_package.rs b/imports/src/parser/core_package.rs deleted file mode 100644 index 67c3df8d47..0000000000 --- a/imports/src/parser/core_package.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (C) 2019-2020 Aleo Systems Inc. -// This file is part of the Leo library. - -// The Leo library is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// The Leo library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with the Leo library. If not, see . - -use crate::{errors::ImportParserError, ImportParser}; -use leo_ast::Package; - -pub static CORE_PACKAGE_NAME: &str = "core"; - -impl ImportParser { - /// - /// Import a core package and insert into the `ImportParser`. - /// - pub fn parse_core_package(&mut self, package: &Package) -> Result<(), ImportParserError> { - // Insert a core package into the `ImportParser`. - self.insert_core_package(package)?; - - Ok(()) - } -} diff --git a/imports/src/parser/import_parser.rs b/imports/src/parser/import_parser.rs index fde6aa4d95..e342b15b69 100644 --- a/imports/src/parser/import_parser.rs +++ b/imports/src/parser/import_parser.rs @@ -15,7 +15,7 @@ // along with the Leo library. If not, see . use crate::errors::ImportParserError; -use leo_ast::{Package, Program}; +use leo_asg::{Program, ImportResolver, AsgConvertError, Span}; use indexmap::{IndexMap, IndexSet}; use std::env::current_dir; @@ -26,74 +26,27 @@ use std::env::current_dir; /// directory, foreign in the imports directory, or part of the core package list. #[derive(Clone, Default)] pub struct ImportParser { + partial_imports: IndexSet, imports: IndexMap, - core_packages: IndexSet, } -impl ImportParser { - /// - /// Inserts a (file name -> program) pair into the `ImportParser`. - /// - /// It is okay if the imported program is already present since importing multiple symbols from - /// the same file is allowed. - /// - pub fn insert_import(&mut self, file_name: String, program: Program) { - // Insert the imported program. - let _program = self.imports.insert(file_name, program); - } - - /// - /// Inserts a core package into the `ImportParser`. - /// - /// If the vector did not have this file_name present, `Ok()` is returned. - /// - /// If the vector did have this file_name present, a duplicate import error is thrown. - /// - pub fn insert_core_package(&mut self, package: &Package) -> Result<(), ImportParserError> { - // Check for duplicate core package name. - if self.core_packages.contains(package) { - return Err(ImportParserError::duplicate_core_package(package.name.clone())); +//todo: handle relative imports relative to file... +impl ImportResolver for ImportParser { + fn resolve_package(&mut self, package_segments: &[&str], span: &Span) -> Result, AsgConvertError> { + let full_path = package_segments.join("."); + if self.partial_imports.contains(&full_path) { + return Err(ImportParserError::recursive_imports(&full_path, span).into()) } - - // Append the core package. - self.core_packages.insert(package.clone()); - - Ok(()) - } - - /// - /// Returns a reference to the program corresponding to the file name. - /// - pub fn get_import(&self, file_name: &str) -> Option<&Program> { - self.imports.get(file_name) - } - - /// - /// Returns a reference to the core package corresponding to the given package. - /// - pub fn get_core_package(&self, package: &Package) -> Option<&Package> { - self.core_packages.iter().find(|core_package| core_package.eq(&package)) - } - - /// - /// Returns a new `ImportParser` from a given `Program`. - /// - /// For every import statement in the program: - /// 1. Check if the imported package exists. - /// 2. Create the Leo syntax tree for the imported package. - /// 3. Insert the Leo syntax tree into the `ImportParser` - /// - pub fn parse(program: &Program) -> Result { - let mut imports = Self::default(); - - // Find all imports relative to current directory. - let path = current_dir().map_err(ImportParserError::current_directory_error)?; - - // Parse each import statement. - for import in &program.imports { - imports.parse_package(path.clone(), &import.package)?; + if let Some(program) = self.imports.get(&full_path) { + return Ok(Some(program.clone())); } + let mut imports = Self::default(); + let path = current_dir().map_err(|x| -> AsgConvertError { ImportParserError::current_directory_error(x).into() })?; - Ok(imports) + self.partial_imports.insert(full_path.clone()); + let program = imports.parse_package(path.clone(), package_segments, span).map_err(|x| -> AsgConvertError { x.into() })?; + self.partial_imports.remove(&full_path); + self.imports.insert(full_path, program.clone()); + Ok(Some(program)) } -} +} \ No newline at end of file diff --git a/imports/src/parser/mod.rs b/imports/src/parser/mod.rs index 4cc48bcdc2..917eb7dfd1 100644 --- a/imports/src/parser/mod.rs +++ b/imports/src/parser/mod.rs @@ -15,8 +15,6 @@ // along with the Leo library. If not, see . /// The import parser creates a hashmap of import program names -> import program structs -pub mod core_package; -pub use self::core_package::*; pub mod parse_symbol; pub use self::parse_symbol::*; diff --git a/imports/src/parser/parse_package.rs b/imports/src/parser/parse_package.rs index 78118acd53..6cb16b8328 100644 --- a/imports/src/parser/parse_package.rs +++ b/imports/src/parser/parse_package.rs @@ -14,40 +14,25 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{errors::ImportParserError, ImportParser, CORE_PACKAGE_NAME}; -use leo_ast::{Package, PackageAccess}; +use crate::{errors::ImportParserError, ImportParser}; +use leo_asg::{Identifier, Program, Span}; -use std::{fs, fs::DirEntry, path::PathBuf}; +use std::{fs::DirEntry, fs, path::PathBuf}; static SOURCE_FILE_EXTENSION: &str = ".leo"; static SOURCE_DIRECTORY_NAME: &str = "src/"; static IMPORTS_DIRECTORY_NAME: &str = "imports/"; impl ImportParser { - /// - /// Import one or more symbols from a package. - /// - /// Will recursively traverse sub packages until the desired symbol is found. - /// - pub fn parse_package_access( - &mut self, - package: &DirEntry, - access: &PackageAccess, - ) -> Result<(), ImportParserError> { - tracing::debug!("import {:?}", package.path()); - - match access { - PackageAccess::Star(span) => self.parse_import_star(package, span), - PackageAccess::Symbol(symbol) => self.parse_import_symbol(package, symbol), - PackageAccess::SubPackage(sub_package) => self.parse_package(package.path(), sub_package), - PackageAccess::Multiple(accesses) => { - for access in accesses { - self.parse_package_access(package, access)?; - } - - Ok(()) - } + + fn parse_package_access(&mut self, package: &DirEntry, remaining_segments: &[&str], span: &Span) -> Result { + if remaining_segments.len() > 0 { + return self.parse_package(package.path(), remaining_segments, span); } + let program = Self::parse_import_file(package, span)?; + let asg = leo_asg::InnerProgram::new(&program, self)?; + + Ok(asg) } /// @@ -55,12 +40,15 @@ impl ImportParser { /// /// Inserts the Leo syntax tree into the `ImportParser`. /// - pub fn parse_package(&mut self, mut path: PathBuf, package: &Package) -> Result<(), ImportParserError> { + pub(crate) fn parse_package(&mut self, mut path: PathBuf, segments: &[&str], span: &Span) -> Result { let error_path = path.clone(); - let package_name = package.name.clone(); + let package_name = segments[0]; // Fetch a core package - let core_package = package_name.name.eq(CORE_PACKAGE_NAME); + let core_package = package_name.eq("core"); + if core_package { + panic!("attempted to import core package from filesystem"); + } // Trim path if importing from another file if path.is_file() { @@ -82,9 +70,9 @@ impl ImportParser { // Get a vector of all packages in the source directory. let entries = fs::read_dir(path) - .map_err(|error| ImportParserError::directory_error(error, package_name.span.clone(), &error_path))? + .map_err(|error| ImportParserError::directory_error(error, span.clone(), &error_path))? .collect::, std::io::Error>>() - .map_err(|error| ImportParserError::directory_error(error, package_name.span.clone(), &error_path))?; + .map_err(|error| ImportParserError::directory_error(error, span.clone(), &error_path))?; // Check if the imported package name is in the source directory. let matched_source_entry = entries.into_iter().find(|entry| { @@ -93,36 +81,33 @@ impl ImportParser { .into_string() .unwrap() .trim_end_matches(SOURCE_FILE_EXTENSION) - .eq(&package_name.name) + .eq(package_name) }); - if core_package { - // Enforce core package access. - self.parse_core_package(&package) - } else if imports_directory.exists() { + if imports_directory.exists() { // Get a vector of all packages in the imports directory. let entries = fs::read_dir(imports_directory) - .map_err(|error| ImportParserError::directory_error(error, package_name.span.clone(), &error_path))? + .map_err(|error| ImportParserError::directory_error(error, span.clone(), &error_path))? .collect::, std::io::Error>>() - .map_err(|error| ImportParserError::directory_error(error, package_name.span.clone(), &error_path))?; + .map_err(|error| ImportParserError::directory_error(error, span.clone(), &error_path))?; // Check if the imported package name is in the imports directory. let matched_import_entry = entries .into_iter() - .find(|entry| entry.file_name().into_string().unwrap().eq(&package_name.name)); + .find(|entry| entry.file_name().into_string().unwrap().eq(package_name)); // Check if the package name was found in both the source and imports directory. match (matched_source_entry, matched_import_entry) { - (Some(_), Some(_)) => Err(ImportParserError::conflicting_imports(package_name)), - (Some(source_entry), None) => self.parse_package_access(&source_entry, &package.access), - (None, Some(import_entry)) => self.parse_package_access(&import_entry, &package.access), - (None, None) => Err(ImportParserError::unknown_package(package_name)), + (Some(_), Some(_)) => Err(ImportParserError::conflicting_imports(Identifier::new_with_span(package_name, span))), + (Some(source_entry), None) => self.parse_package_access(&source_entry, &segments[1..], span), + (None, Some(import_entry)) => self.parse_package_access(&import_entry, &segments[1..], span), + (None, None) => Err(ImportParserError::unknown_package(Identifier::new_with_span(package_name, span))), } } else { // Enforce local package access with no found imports directory match matched_source_entry { - Some(source_entry) => self.parse_package_access(&source_entry, &package.access), - None => Err(ImportParserError::unknown_package(package_name)), + Some(source_entry) => self.parse_package_access(&source_entry, &segments[1..], span), + None => Err(ImportParserError::unknown_package(Identifier::new_with_span(package_name, span))), } } } diff --git a/imports/src/parser/parse_symbol.rs b/imports/src/parser/parse_symbol.rs index 3061a7ff8a..2a2ee14d9d 100644 --- a/imports/src/parser/parse_symbol.rs +++ b/imports/src/parser/parse_symbol.rs @@ -15,112 +15,46 @@ // along with the Leo library. If not, see . use crate::{errors::ImportParserError, ImportParser}; -use leo_ast::{ImportSymbol, Program, Span}; +use leo_ast::{Program, Span}; use leo_grammar::Grammar; -use std::{ffi::OsString, fs::DirEntry, path::PathBuf}; +use std::{fs::DirEntry}; static LIBRARY_FILE: &str = "src/lib.leo"; -static FILE_EXTENSION: &str = "leo"; - -/// -/// Returns a Leo syntax tree from a given package. -/// -/// Builds an abstract syntax tree from the given file and then builds the Leo syntax tree. -/// -fn parse_import_file(package: &DirEntry, span: &Span) -> Result { - // Get the package file type. - let file_type = package - .file_type() - .map_err(|error| ImportParserError::directory_error(error, span.clone(), &package.path()))?; - let file_name = package - .file_name() - .into_string() - .map_err(|_| ImportParserError::convert_os_string(span.clone()))?; - - let mut file_path = package.path(); - if file_type.is_dir() { - file_path.push(LIBRARY_FILE); - - if !file_path.exists() { - return Err(ImportParserError::expected_lib_file( - format!("{:?}", file_path.as_path()), - span.clone(), - )); - } - } - - // Build the package abstract syntax tree. - let program_string = &Grammar::load_file(&file_path)?; - let ast = &Grammar::new(&file_path, &program_string)?; - - // Build the package Leo syntax tree from the package abstract syntax tree. - Ok(Program::from(&file_name, ast.as_repr())) -} impl ImportParser { /// - /// Import all symbols from a given package. + /// Returns a Leo syntax tree from a given package. /// - /// If the package is a Leo file, import all symbols from the file. - /// If the package is a directory, import all symbol from the library file. + /// Builds an abstract syntax tree from the given file and then builds the Leo syntax tree. /// - pub fn parse_import_star(&mut self, package: &DirEntry, span: &Span) -> Result<(), ImportParserError> { - let path = package.path(); - let is_dir = path.is_dir(); - - // Check if the package is a Leo file. - let is_leo_file = path - .extension() - .map_or(false, |ext| ext.eq(&OsString::from(FILE_EXTENSION))); - - let mut package_path = path; - package_path.push(LIBRARY_FILE); - - // Check if the package is a directory. - let is_package = is_dir && package_path.exists(); - - // import * can only be invoked on a package with a library file or a leo file - if is_package || is_leo_file { - self.parse_import_package(package, span) - } else { - // importing * from a directory or non-leo file in `package/src/` is illegal - Err(ImportParserError::star(&package.path(), span.clone())) - } - } - - /// - /// Import a symbol from a given package. - /// - pub fn parse_import_symbol(&mut self, package: &DirEntry, symbol: &ImportSymbol) -> Result<(), ImportParserError> { - // Get the package Leo syntax tree. - self.parse_import_package(package, &symbol.span) - } - - /// - /// Import a symbol from a given package. - /// - pub fn parse_import_package(&mut self, package: &DirEntry, span: &Span) -> Result<(), ImportParserError> { - // Get the package Leo syntax tree. - let program = parse_import_file(package, span)?; - - // Insert the package's imports into the import parser. - for import in &program.imports { - self.parse_package(package.path(), &import.package)?; - } - - // Get the package file name from the path. - let file_name_path = PathBuf::from(package.file_name()); - let file_name = file_name_path - .file_stem() - .unwrap() - .to_os_string() + pub(crate) fn parse_import_file(package: &DirEntry, span: &Span) -> Result { + // Get the package file type. + let file_type = package + .file_type() + .map_err(|error| ImportParserError::directory_error(error, span.clone(), &package.path()))?; + let file_name = package + .file_name() .into_string() - .unwrap(); // the file exists so these will not fail - - // Attempt to insert the Leo syntax tree for the imported package. - self.insert_import(file_name, program); - - Ok(()) + .map_err(|_| ImportParserError::convert_os_string(span.clone()))?; + + let mut file_path = package.path(); + if file_type.is_dir() { + file_path.push(LIBRARY_FILE); + + if !file_path.exists() { + return Err(ImportParserError::expected_lib_file( + format!("{:?}", file_path.as_path()), + span.clone(), + )); + } + } + + // Build the package abstract syntax tree. + let program_string = &Grammar::load_file(&file_path)?; + let ast = &Grammar::new(&file_path, &program_string)?; + + // Build the package Leo syntax tree from the package abstract syntax tree. + Ok(Program::from(&file_name, ast.as_repr())) } }